Skip to content

Instantly share code, notes, and snippets.

@chrilves
Created December 22, 2021 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrilves/1894848b51724bd2b937dc63496873f7 to your computer and use it in GitHub Desktop.
Save chrilves/1894848b51724bd2b937dc63496873f7 to your computer and use it in GitHub Desktop.
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class Day21_Dirac_Dice2 {
public static void main(String[] args) {
int player1Starting = 4;
int player2Starting = 8;
Result part2 = part2(player1Starting, player2Starting);
System.out.println(part2.player1Wins + " " + part2.player2Wins);
}
/** Given a game state, returns the number of universes where
* each player wins from this game state.
*/
private static Result playGame(Game game) {
// The winning player wins in this universe.
if (game.player1Wins()) {
return new Result(1,0);
}
if (game.player2Wins()) {
return new Result(0,1);
}
/* The game is not won, yet.
The function is called recursively on every possible dice outcome (diceSum).
There can be several combination leading to a given sum, so we need
to multiply the results by the number of combinations leading to this
sum.
We add all the results to give the final result for this call.
*/
return playGame(game.play(3))
.add(playGame(game.play(4)).times(3))
.add(playGame(game.play(5)).times(6))
.add(playGame(game.play(6)).times(7))
.add(playGame(game.play(7)).times(6))
.add(playGame(game.play(8)).times(3))
.add(playGame(game.play(9)));
}
// Part 2: Using quantum die.
private static Result part2(int player1Starting, int player2Starting) {
Game g = new Game(player1Starting, player2Starting, 0, 0, true);
return playGame(g);
}
/** Stote the number of times player1 and player2 win. */
static class Result {
long player1Wins;
long player2Wins;
public Result(long player1Wins, long player2Wins) {
this.player1Wins = player1Wins;
this.player2Wins = player2Wins;
}
/** Add to result together: used to sum all the results from all cases. */
public Result add(Result other) {
return new Result(this.player1Wins + other.player1Wins, this.player2Wins + other.player2Wins);
}
/** Multiply all wins by a given factor: used to account for a diceSum to be produced by several combinations */
public Result times(long k) {
return new Result(this.player1Wins * k, this.player2Wins * k);
}
}
static class Game {
int player1Position;
int player2Position;
int player1Score;
int player2Score;
boolean player1Turn;
public Game(int player1Position, int player2Position, int player1Score, int player2Score, boolean player1Turn) {
this.player1Position = player1Position;
this.player2Position = player2Position;
this.player1Score = player1Score;
this.player2Score = player2Score;
this.player1Turn = player1Turn;
}
public boolean player1Wins() {
return player1Score >= 21;
}
public boolean player2Wins() {
return player2Score >= 21;
}
/** Play one turn and return the new game state.
* Does not alter the old game state (so that it can be safely used
* in other branches.)
*/
public Game play(int diceSum) {
if (player1Wins() || player2Wins()) {
throw new RuntimeException("Game already won.");
}
if (player1Turn) {
int newPlayer1Position = (((player1Position + diceSum) - 1) % 10) + 1;
int newPlayer1Score = player1Score + newPlayer1Position;
return new Game(newPlayer1Position, player2Position, newPlayer1Score, player2Score, false);
} else {
int newPlayer2Position = (((player2Position + diceSum) - 1) % 10) + 1;
int newPlayer2Score = player2Score + newPlayer2Position;
return new Game(player1Position, newPlayer2Position, player1Score, newPlayer2Score, true);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment