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)
}