301 lines
5.6 KiB
Go
301 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
)
|
|
|
|
var (
|
|
errItemAlreadySet = errors.New("cannot set item in direction as one is already set")
|
|
)
|
|
|
|
// ProcessLines maps a function on lines parsed from a file.
|
|
func ProcessLines(path string, f func(string) (stop bool, err error)) error {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
stop, err := f(scanner.Text())
|
|
if stop || err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ProcessGroups maps a function on groups of lines parsed from a file separated by some string.
|
|
func ProcessGroups(path, separator string, f func([]string) (stop bool, err error)) error {
|
|
group := []string{}
|
|
|
|
if err := ProcessLines(path, func(line string) (stop bool, err error) {
|
|
if line == separator {
|
|
stop, err = f(group)
|
|
if stop || err != nil {
|
|
return
|
|
}
|
|
group = []string{}
|
|
} else {
|
|
group = append(group, line)
|
|
}
|
|
|
|
return
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err := f(group)
|
|
|
|
return err
|
|
}
|
|
|
|
// StringSet is a set of strings..
|
|
type StringSet map[string]bool
|
|
|
|
// Add an item to a StringSet.
|
|
func (s *StringSet) Add(v string) {
|
|
(*s)[v] = true
|
|
}
|
|
|
|
// AddAll adds all items in a list to the set.
|
|
func (s *StringSet) AddAll(l []string) {
|
|
for _, v := range l {
|
|
s.Add(v)
|
|
}
|
|
}
|
|
|
|
// Items returns all values in the set as a list.
|
|
func (s StringSet) Items() []string {
|
|
values := []string{}
|
|
for k := range s {
|
|
values = append(values, k)
|
|
}
|
|
|
|
return values
|
|
}
|
|
|
|
// NewStringSet creates an empty string set.
|
|
func NewStringSet(values []string) StringSet {
|
|
v := StringSet{}
|
|
v.AddAll(values)
|
|
|
|
return v
|
|
}
|
|
|
|
// Union returns the union of two SringSets.
|
|
func Union(s1, s2 StringSet) StringSet {
|
|
union := NewStringSet(s1.Items())
|
|
union.AddAll(s2.Items())
|
|
|
|
return union
|
|
}
|
|
|
|
// Intersection returns the union of two SringSets.
|
|
func Intersection(s1, s2 StringSet) StringSet {
|
|
intersect := StringSet{}
|
|
|
|
for v := range s1 {
|
|
if _, ok := s2[v]; ok {
|
|
intersect.Add(v)
|
|
}
|
|
}
|
|
|
|
return intersect
|
|
}
|
|
|
|
// Difference returns the value of s1 with values of s2 removed.
|
|
func Difference(s1, s2 StringSet) StringSet {
|
|
difference := StringSet{}
|
|
|
|
for v := range s1 {
|
|
if _, ok := s2[v]; !ok {
|
|
difference.Add(v)
|
|
}
|
|
}
|
|
|
|
return difference
|
|
}
|
|
|
|
// Point represents a point on a coordinate system.
|
|
type Point struct {
|
|
x, y int
|
|
}
|
|
|
|
// AddPoints adds two points together.
|
|
func AddPoints(p1, p2 Point) Point {
|
|
return Point{
|
|
p1.x + p2.x,
|
|
p1.y + p2.y,
|
|
}
|
|
}
|
|
|
|
// PowInt is equivalent to math.Pow but for integers.
|
|
func PowInt(x, y int) int {
|
|
return int(math.Pow(float64(x), float64(y)))
|
|
}
|
|
|
|
// LinkedGridItem is a single item in a linked grid.
|
|
type LinkedGridItem struct {
|
|
location Point
|
|
left, right, up, down *LinkedGridItem
|
|
grid *LinkedGrid
|
|
}
|
|
|
|
func (item LinkedGridItem) String() string {
|
|
return fmt.Sprintf("%v", item.location)
|
|
}
|
|
|
|
// Location of the item.
|
|
func (item LinkedGridItem) Location() Point {
|
|
return item.location
|
|
}
|
|
|
|
// Left gives a pointer to the item on the left.
|
|
func (item LinkedGridItem) Left() *LinkedGridItem {
|
|
return item.left
|
|
}
|
|
|
|
// Up gives a pointer to the item above.
|
|
func (item LinkedGridItem) Up() *LinkedGridItem {
|
|
return item.up
|
|
}
|
|
|
|
// Right gives a pointer to the item on the right.
|
|
func (item LinkedGridItem) Right() *LinkedGridItem {
|
|
return item.right
|
|
}
|
|
|
|
// Down gives a pointer to the item below.
|
|
func (item LinkedGridItem) Down() *LinkedGridItem {
|
|
return item.down
|
|
}
|
|
|
|
// SetLeft gives a pointer to the item on the left.
|
|
func (item *LinkedGridItem) SetLeft(other *LinkedGridItem) error {
|
|
if item.left != nil || other.right != nil {
|
|
return errItemAlreadySet
|
|
}
|
|
|
|
item.left = other
|
|
other.right = item
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetUp gives a pointer to the item on the up.
|
|
func (item *LinkedGridItem) SetUp(other *LinkedGridItem) error {
|
|
if item.up != nil || other.down != nil {
|
|
return errItemAlreadySet
|
|
}
|
|
|
|
item.up = other
|
|
other.down = item
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetRight gives a pointer to the item on the right.
|
|
func (item *LinkedGridItem) SetRight(other *LinkedGridItem) error {
|
|
if item.right != nil || other.left != nil {
|
|
return errItemAlreadySet
|
|
}
|
|
|
|
item.right = other
|
|
other.left = item
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetDown gives a pointer to the item on the down.
|
|
func (item *LinkedGridItem) SetDown(other *LinkedGridItem) error {
|
|
if item.down != nil || other.up != nil {
|
|
return errItemAlreadySet
|
|
}
|
|
|
|
item.down = other
|
|
other.up = item
|
|
|
|
return nil
|
|
}
|
|
|
|
// LinkedGrid is a 2d array of grid square.
|
|
type LinkedGrid [][]*LinkedGridItem
|
|
|
|
// Print a linked grid.
|
|
func (grid LinkedGrid) Print() {
|
|
for _, row := range grid {
|
|
for _, item := range row {
|
|
fmt.Print(item.String())
|
|
}
|
|
|
|
fmt.Print("\n")
|
|
}
|
|
}
|
|
|
|
// NewLinkedGrid initializes a new linked grid of a given size.
|
|
func NewLinkedGrid(width, height int) *LinkedGrid {
|
|
|
|
var w = make(LinkedGrid, height)
|
|
|
|
for y := 0; y < height; y++ {
|
|
w[y] = make([]*LinkedGridItem, width)
|
|
|
|
for x := 0; x < height; x++ {
|
|
item := LinkedGridItem{location: Point{x, y}}
|
|
|
|
if x != 0 {
|
|
_ = item.SetLeft(w[y][x-1])
|
|
}
|
|
|
|
if y != 0 {
|
|
_ = item.SetUp(w[y-1][x])
|
|
}
|
|
|
|
w[y][x] = &item
|
|
}
|
|
}
|
|
|
|
return &w
|
|
}
|
|
|
|
// MapInt maps a function onto a list of ints.
|
|
func MapInt(a []int, f func(int) (int, error)) error {
|
|
var err error
|
|
|
|
for i, v := range a {
|
|
a[i], err = f(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReduceInt maps a function onto a list of ints.
|
|
func ReduceInt(a []int, start int, f func(int, int) (int, error)) (int, error) {
|
|
var err error
|
|
|
|
result := start
|
|
|
|
for _, v := range a {
|
|
result, err = f(result, v)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|