DEV Community

Cover image for Advent of code - Day 22
Quentin Ménoret
Quentin Ménoret

Posted on

Advent of code - Day 22

Are you participating in the Advent of code this year?

If you don't know what the advent of code is, it's a website where you'll find a daily challenge (every day it gets harder). It's a really fun event, you should participate!

I try to solve the exercises using either JavaScript or TypeScript and will share my solutions daily (with one day delay so no one can cheat!). I only share the solution for the second part.


Interesting day! Nothing too complex, no hidden tricks, completely doable step by step. Fun fact, in order to complete the challenge I created a test file with the description of the game (the sample), and made my code return logs instead of the result. Once I had the exact same logs as the sample, I ran the code, and voilà, the solution appeared!

Here is my solution for day #22:

export class RecursiveGame {
  player1: number[]
  player2: number[]
  logs: string[] = []
  played = new Set<string>()

  constructor(deck1: number[], deck2: number[]) {
    this.player1 = deck1
    this.player2 = deck2
  }

  isFinished(): boolean {
    return this.player1.length === 0 || this.player2.length === 0
  }

  playAll() {
    while (!this.isFinished()) {
      this.playTurn()
    }
  }

  playTurn() {
    // if already happened, game end for player 1
    const key = `${this.player1}|${this.player2}`
    if (this.played.has(key)) {
      this.player2.length = 0
      return
    }
    this.played.add(key)

    const cardPlayer1 = this.player1.shift()
    const cardPlayer2 = this.player2.shift()
    if (!cardPlayer1 || !cardPlayer2) throw new Error('game already finished')

    let winner: 1 | 2 | null

    if (this.player1.length >= cardPlayer1 && this.player2.length >= cardPlayer2) {
      const subGame = new RecursiveGame(this.player1.slice(0, cardPlayer1), this.player2.slice(0, cardPlayer2))
      subGame.playAll()

      winner = subGame.getWinner()
    } else {
      if (cardPlayer1 > cardPlayer2) {
        winner = 1
      } else {
        winner = 2
      }
    }

    if (winner === null) throw new Error('winner cant be found')
    if (winner === 1) {
      this.player1.push(cardPlayer1, cardPlayer2)
    } else {
      this.player2.push(cardPlayer2, cardPlayer1)
    }
  }

  getWinner(): 1 | 2 {
    if (this.player1.length === 0) return 2
    if (this.player2.length === 0) return 1
    throw new Error('not over yet')
  }

  getWinnerDeck(): number[] {
    const winner = [this.player1, this.player2].find((deck) => deck.length !== 0)
    if (!winner) throw new Error('Game not finished yet')
    return winner
  }
}

function resolve(input: string) {
  const [deck1, deck2] = input.split('\n\n').map((deck) => {
    return deck
      .split('\n')
      .slice(1)
      .map((card) => parseInt(card, 10))
  })

  const game = new RecursiveGame(deck1, deck2)
  game.playAll()

  console.log(
    game.getWinnerDeck().reduce((acc, card, index, deck) => {
      return acc + (deck.length - index) * card
    }, 0),
  )
}

resolve(input)
Enter fullscreen mode Exit fullscreen mode

Feel free to share your solution in the comments!


Photo by Markus Spiske on Unsplash

Discussion (0)