3 minutes
Input template (Go) for algorithmic competitions
Since I have been playing with Go recently, I decided to use it for the qualification round of Google Code Jam - 2016.
Here is the struct I wrote to wrap around a reader so as to handle input from either a file or os.STDIN
(technicall any io.Reader
).
type MyInput struct {
rdr io.Reader
lineChan chan string
initialized bool
}
func (mi *MyInput) start(done chan struct{}) {
r := bufio.NewReader(mi.rdr)
defer func() { close(mi.lineChan) }()
for {
line, err := r.ReadString('\n')
if !mi.initialized {
mi.initialized = true
done <- struct{}{}
}
mi.lineChan <- strings.TrimSpace(line)
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
}
}
Its just a simple wrapper around a reader with some state variables.
Next, I added the function readLine()
which will be the base of all functions for reading from the input (file or stdin or whatever).
func (mi *MyInput) readLine() string {
// if this is the first call, initialize
if !mi.initialized {
mi.lineChan = make(chan string)
done := make(chan struct{})
go mi.start(done)
<-done
}
res, ok := <-mi.lineChan
if !ok {
panic("trying to read from a closed channel")
}
return res
}
The first call to readLine()
would initialize the MyInput instance, in addition to returning a line from the input.
Next I added some helper functions to cater to the most common use-cases for reading from an input, as far as algorithmic completions input is concerned.
// to read an int from a line that contains only one value and that is an int
func (mi *MyInput) readInt() int {
line := mi.readLine()
i, err := strconv.Atoi(line)
if err != nil {
panic(err)
}
return i
}
// similar to `readInt` but returns an int64
func (mi *MyInput) readInt64() int64 {
line := mi.readLine()
i, err := strconv.ParseInt(line, 10, 64)
if err != nil {
panic(err)
}
return i
}
// if a line has multiple ints seperated by a space,
//use this to get the ints in a slice []int
// e.g. if line is "1 2 6 77"
// this would return []int{1,2,6,77}
func (mi *MyInput) readInts() []int {
line := mi.readLine()
parts := strings.Split(line, " ")
res := []int{}
for _, s := range parts {
tmp, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
res = append(res, tmp)
}
return res
}
// similar to `readInts` but returns a slice of int64s
func (mi *MyInput) readInt64s() []int64 {
line := mi.readLine()
parts := strings.Split(line, " ")
res := []int64{}
for _, s := range parts {
tmp, err := strconv.ParseInt(s, 10, 64)
if err != nil {
panic(err)
}
res = append(res, tmp)
}
return res
}
// returns the words from the line that are seperated by a space
// e.g. if line is "who art thou",
// this would return []string{"who", "art", "thou"}
func (mi *MyInput) readWords() []string {
line := mi.readLine()
return strings.Split(line, " ")
}
Using MyInput
is as simple as shown below:
func main() {
f, _ := os.Open("input_file.in")
mi := MyInput{rdr: f}
// mi := MyInput{rdr: os.Stdin}
t := mi.readInt()
for caseNo := 1; caseNo <= t; caseNo++ {
// TODO - solve the case !
}
}
The complete code is available at as a Gitlab snippet here