You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've solved them in Coffeescript one year ago. But since I'm learning Go at the moment, and have just finished writing solutions for puzzles from this year (2018), I've decided to go with year 2017 puzzles as well, refactoring and cleaning up solutions as much as possible.
Goals:
implemented automatic puzzle input retrieval and result submission;
implement generic code, that can come in handy during programming contests;
same as for year 2018: learn & document quirks & tricks of Go, which are new to me.
"Go gotchas"
Go is low-level language with built-in concurrency and garbage collection, designed as a highly efficient C++ or Java competitor. To achieve high speed (both in compilation and execution), some surprising design decisions were made. It takes time to learn them.
To create custom iterators/generators, channels come in handy
myString:="a string with Unicode ⅀😃😉🎄❤"fmt.Println("\niterate over string, 1 Unicode rune at time. Note byteIndex is not continuous.")
forbyteIndex, aRune:=rangemyString {
fmt.Println(byteIndex, string(aRune))
}
mySlice:= []string{"hello", "world"}
fmt.Println("\niterate over slice")
forindex, value:=rangemySlice {
fmt.Println(index, value)
}
myMap:=map[string]int{"a": 15, "c": 19}
fmt.Println("\niterate over map")
forkey, value:=rangemyMap {
fmt.Println(key, value)
}
myChan:=make(chanstring)
gofunc() {
myChan<-"Hello"myChan<-"World!"// generate values on demand. Then close the channel to end iteration.close(myChan)
}()
fmt.Println("\niterate over channel")
foraString:=rangemyChan {
fmt.Println(aString)
}
Classical inheritance is hard
For example you want 2d grid base class with common methods, and implementation details in derived classes. In C++ you just create base class with virtual methods for implementation.
In Go you create base interface with method signatures, but can't add common methods. Instead you write functions, that recieve interface, and work as external functions.
package field
// Field is two-dimensional.typeFieldinterface {
Get(Pos) CellSet(Pos, Cell)
Bounds() RectDefault() CellSetDefault(Cell)
}
// Commond data and base methods, can't call methods of derived classes.typefieldBasestruct {
bRectdefCell
}
// Default cell value.func (f*fieldBase) Default() Cell {
returnf.def
}
// SetDefault cell value.func (f*fieldBase) SetDefault(cCell) {
f.def=c
}
// Bounds AABB.func (f*fieldBase) Bounds() Rect {
returnf.b
}
// Common "methods" that use interface methods are actually external functions.// Print fieldfuncPrint(fField) {
// ...
}
//////////////////////////////////////////////////////////////// Map based 2d field.typeMapstruct {
fieldBase// ... implementation details.
}
func (f*Map) Get(pPos) Cell {
//... implementation details.
}
Another option is to include interface into base class, but remember that interface is just a pointer, and it needs to be initialized, or else you'll get panics with nil-pointer dereference:
typefieldBasestruct {
Field
}
// Print the field.func (f*fieldBase) Print() {
// ... use f.Get here
}
// NewMap is required to initialize interface in base class.funcNewMap() Field {
f:=&Map{}
f.Field=f// store pointer to the Map object in base class. Failing to do so will lead to panics.returnf
}
Puzzle inputs
Inputs are automatically retrieved from Advent of Code, provided you put at least one <session-name>.cookie into inputs/ folder. To get the cookie, refer to website properties in your browser, after logging in into Advent of Code website.