diff --git a/2018/day09-1.go b/2018/day09-1.go new file mode 100644 index 0000000..9d7f2e9 --- /dev/null +++ b/2018/day09-1.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + + "internal/day09" +) + +func main() { + numPlayers, finNum := day09.ParseInput() + _, score := day09.PlayGame(numPlayers, finNum) + fmt.Println(score) +} diff --git a/2018/internal/day09/game.go b/2018/internal/day09/game.go new file mode 100644 index 0000000..9b5f643 --- /dev/null +++ b/2018/internal/day09/game.go @@ -0,0 +1,39 @@ +package day09 + +// Returns the winning player's index and score +func PlayGame(numPlayers, finNum int) (int, int) { + players := make([]int, numPlayers) + + // initialize the 'board' + currentMarble := &Marble{Number: 0} + currentMarble.CW = currentMarble + currentMarble.CCW = currentMarble + + currentPlayer := 0 + for i := 1; currentMarble.Number < finNum; i++ { + var score int + currentMarble, score = currentMarble.PlaceNewMarble(i) + players[currentPlayer] += score + + currentPlayer++ + if currentPlayer >= len(players) { + currentPlayer = 0 + } + } + + return findWinnerData(players) +} + +func findWinnerData(players []int) (int, int) { + topScore := -1 + winner := -1 + + for player, score := range players { + if score > topScore { + topScore = score + winner = player + } + } + + return winner, topScore +} diff --git a/2018/internal/day09/marbles.go b/2018/internal/day09/marbles.go new file mode 100644 index 0000000..f757514 --- /dev/null +++ b/2018/internal/day09/marbles.go @@ -0,0 +1,55 @@ +package day09 + +type Marble struct { + Number int + CW *Marble + CCW *Marble +} + +// Returns the new current marble and the score to add. +func (m *Marble) PlaceNewMarble(number int) (*Marble, int) { + // if the marble that is about to be placed has a number which is a multiple + // of 23, the current player keeps the marble they would have placed, adding + // it to their score. In addition, the marble 7 marbles counter-clockwise + // from the current marble is removed from the circle and also added to the + // current player's score. The marble located immediately clockwise of the + // marble that was removed becomes the new current marble. + if number%23 == 0 { + score := number + cursor := m + for i := 0; i < 7; i++ { + cursor = cursor.CCW + } + score += cursor.Number + cursor = cursor.Remove() + return cursor, score + } + + // [Insert the marble] between the marbles that are 1 and 2 + // marbles clockwise of the current marble. + // The marble that was just placed then becomes the current marble. + + // first create the marble and populate its fields correctly + newMarble := &Marble{Number: number} + cursor := m.CW + newMarble.CCW = cursor + newMarble.CW = cursor.CW + + // now sync up the pointers in the adjacent marbles + newMarble.CCW.CW = newMarble + newMarble.CW.CCW = newMarble + return newMarble, 0 +} + +func (m *Marble) Remove() *Marble { + // removes the marble from the list, repairing links. Returns the + // marble immediately CW of this one. + + // link the two newly-adjacent marbles. + ccw := m.CCW + cw := m.CW + ccw.CW = cw + cw.CCW = ccw + + return cw +} diff --git a/2018/internal/day09/util.go b/2018/internal/day09/util.go new file mode 100644 index 0000000..001fcda --- /dev/null +++ b/2018/internal/day09/util.go @@ -0,0 +1,25 @@ +package day09 + +import ( + "strconv" + "strings" + + "internal/util" +) + +func ParseInput() (int, int) { + rawData := strings.TrimSpace(util.ReadInput()[0]) + data := strings.Split(rawData, " ") + + players, err := strconv.Atoi(data[0]) + if err != nil { + panic(err) + } + + lastNum, err := strconv.Atoi(data[6]) + if err != nil { + panic(err) + } + + return players, lastNum +}