Skip to content

2022 - Day 2 - Rock Paper Scissors

Posted on:December 2, 2022 at 03:00 PM

Day two of Advent of Code brought a playful challenge of Rock Paper Scissors. We’re not just playing the game; we’re cracking an encrypted strategy to maximize our score. Below is an explanation of the approach and the full JavaScript solution.

Table of Contents

Open Table of Contents

Challenge Overview

The task was to determine the optimal score following an encrypted strategy guide for a Rock Paper Scissors game. The guide dictated our moves and the required outcomes, adding a twist to this classic game.

Our Solution

We wrote a JavaScript function that deciphers the strategy and calculates the score based on the guide’s instructions. The steps were:

  1. Parse the input to determine our moves and the desired outcomes.
  2. Create a scoring system that assigns points based on the game’s rules.
  3. Implement a decision-making process that reacts to the opponent’s moves and the guide’s strategy.
const Using = {
  Rock: "A",
  Paper: "B",
  Scissors: "C",
};

const NeedsTo = {
  Lose: "X",
  Draw: "Y",
  Win: "Z",
};

const fs = require("fs");
const FILE_PATH = "./input.txt";
const start = Date.now();
const input = fs.readFileSync(FILE_PATH, "utf8").trim();
const rounds = input.split("\n");

partOne(rounds);
partTwo(rounds);

const end = Date.now();
console.log(`⏰ The script took ${end - start}ms to run.`);

The detailed implementation of partOne and partTwo functions calculates the score for each scenario by interpreting the encrypted strategy.

Part One: Following the Strategy

In partOne, we follow the strategy guide straightforwardly. Each line of input suggests the opponent’s move and our corresponding response. The function translates these instructions into gameplay, keeping track of the score throughout the tournament. It adjusts the score based on whether we win, lose, or draw each round.

function partOne(rounds) {
  let finalScore = 0;

  rounds.forEach(round => {
    let [opponent, player] = round.split(" ");

    // Make the player's move look the same as the opponent's move.
    player = String.fromCharCode(player.charCodeAt(0) - 23);

    if (player === opponent) {
      if (player === Using.Rock) {
        finalScore += 1; // Using Rock
      } else if (player === Using.Paper) {
        finalScore += 2; // Using Paper
      } else {
        finalScore += 3; // Using Scissors
      }
      finalScore += 3; // Draw Outcome
    } else {
      if (player === Using.Rock) {
        if (opponent === Using.Scissors) {
          finalScore += 6; // Win Outcome
        }
        finalScore += 1; // Using Rock
      } else if (player === Using.Paper) {
        if (opponent === Using.Rock) {
          finalScore += 6; // Win Outcome
        }
        finalScore += 2; // Using Paper
      } else {
        if (opponent === Using.Paper) {
          finalScore += 6; // Win Outcome
        }
        finalScore += 3; // Using Scissors
      }
    }
  });

  console.log(`🎄 Part one's final score is ${finalScore.toLocaleString()}.`);
}

Part Two: Deciphering the Outcome

partTwo delves deeper, requiring us to interpret the desired outcome rather than the direct move. Here, we read the opponent’s move and determine our response to achieve the required result, be it a win, loss, or draw. This function considers the encrypted guide’s second column to make the correct move, accumulating our score as per the updated rules.

function partTwo(rounds) {
  let finalScore = 0;

  rounds.forEach(round => {
    let [opponent, player] = round.split(" ");

    if (player === NeedsTo.Draw) {
      if (opponent === Using.Rock) {
        finalScore += 1; // Using Rock
      } else if (opponent === Using.Paper) {
        finalScore += 2; // Using Paper
      } else {
        finalScore += 3; // Using Scissors
      }
      finalScore += 3; // Draw Outcome
    } else if (player === NeedsTo.Lose) {
      if (opponent === Using.Paper) {
        finalScore += 1; // Using Rock
      } else if (opponent === Using.Scissors) {
        finalScore += 2; // Using Paper
      } else {
        finalScore += 3; // Using Scissors
      }
    } else {
      if (opponent === Using.Scissors) {
        finalScore += 1; // Using Rock
      } else if (opponent === Using.Rock) {
        finalScore += 2; // Using Paper
      } else {
        finalScore += 3; // Using Scissors
      }
      finalScore += 6; // Win Outcome
    }
  });

  console.log(`🎄 Part two's final score is ${finalScore.toLocaleString()}.`);
}

Complexity Analysis

The code runs with a time complexity of O(n) where n is the number of rounds in the tournament since it involves a single iteration over the input data. Space complexity remains constant as there are no data structures that grow with the input size.

Conclusion

By following the encrypted strategy guide, we could strategize our moves in the Rock Paper Scissors game to achieve the highest possible score. The solution demonstrates how a systematic approach to decoding instructions and implementing a rule-based system can lead to successful outcomes in problem-solving.

Stay tuned for more code and challenges as we continue our Advent of Code journey!