package main import ( "bufio" "flag" "fmt" "io" "os" "strconv" ) // CircElem ... type CircElem struct { Next *CircElem Val int } // CircList ... type CircList struct { Root *CircElem Last *CircElem Count int ValElems map[int]*CircElem } // Push ... func (c *CircList) Push(a int) *CircElem { cl := &CircElem{} if c.Root == nil { cl.Next = cl cl.Val = a c.Root = cl c.Last = cl c.ValElems = make(map[int]*CircElem) } else { cl.Next = c.Root cl.Val = a c.Last.Next = cl c.Last = cl } c.Count++ c.ValElems[a] = cl return cl } // Find ... func (c *CircList) Find(a int) *CircElem { var i int for e := c.Root; e != nil; e = e.Next { if e.Val == a { return e } i++ if i >= c.Count { break } } return nil } // Game ... type Game struct { Cups *CircList Current *CircElem Move int Lowest int Highest int } // Turn ... func (g *Game) Turn(debug bool) { target := g.Current.Val - 1 g.Move++ if debug { fmt.Printf("\n-- move %d --\n", g.Move) fmt.Printf("%s\n", g) } e := g.Current e1 := e.Next e2 := e1.Next e3 := e2.Next e.Next = e3.Next hand := []int{e1.Val, e2.Val, e3.Val} if debug { fmt.Printf("pick up: %+v\n", hand) } if target < g.Lowest { target = g.Highest } for { var found bool for _, d := range hand { if target == d { found = true target-- if target < g.Lowest { target = g.Highest } } } if !found { break } } if debug { fmt.Printf("destination: %d\n", target) } targetE := g.Cups.ValElems[target] e3.Next = targetE.Next targetE.Next = e1 g.Current = g.Current.Next } func (g Game) String() string { var result string result += fmt.Sprintf("cups: ") var i int for e := g.Cups.Root; e != nil; e = e.Next { if e.Val == g.Current.Val { result += fmt.Sprintf("(%d)", e.Val) } else { result += fmt.Sprintf(" %d ", e.Val) } i++ if i >= g.Cups.Count { break } } return result } // Task1 ... func Task1(input Game, iterations int, debug bool) string { for i := 0; i < iterations; i++ { input.Turn(debug) } if debug { fmt.Println("\n-- final--") fmt.Printf("%s\n", input) } var result string for e := input.Cups.ValElems[1].Next; e.Val != 1; e = e.Next { result += strconv.Itoa(e.Val) } return result } // Task2 ... func Task2(input Game, debug bool) int { for i := input.Highest + 1; i <= 1000000; i++ { input.Cups.Push(i) } input.Highest = 1000000 for i := 0; i < 10000000; i++ { input.Turn(debug) } e := input.Cups.ValElems[1] return e.Next.Val * e.Next.Next.Val } func readInput(reader io.Reader) Game { input := Game{ Cups: &CircList{}, Lowest: 1, } scanner := bufio.NewScanner(reader) for scanner.Scan() { for _, b := range scanner.Bytes() { d := int(b - '0') if d > input.Highest { input.Highest = d } input.Cups.Push(d) } } input.Current = input.Cups.Root return input } func main() { var debug bool flag.BoolVar(&debug, "debug", false, "debug") flag.Parse() var input1, input2 Game file, _ := os.Open("input.txt") input1 = readInput(file) file.Close() file, _ = os.Open("input.txt") input2 = readInput(file) file.Close() result1 := Task1(input1, 100, debug) fmt.Printf("Task 1: %s\n", result1) result2 := Task2(input2, debug) fmt.Printf("Task 2: %d\n", result2) }