1
+ package com .macasaet ;
2
+
3
+ import java .io .IOException ;
4
+ import java .util .HashSet ;
5
+ import java .util .LinkedList ;
6
+ import java .util .List ;
7
+ import java .util .Objects ;
8
+ import java .util .stream .Collectors ;
9
+ import java .util .stream .StreamSupport ;
10
+
11
+ public class Day22 {
12
+
13
+ public static void main (final String [] args ) throws IOException {
14
+ try (var spliterator = new LineSpliterator (Day22 .class .getResourceAsStream ("/day-22-input.txt" ))) {
15
+ final var lines = StreamSupport .stream (spliterator , false )
16
+ .collect (Collectors .toUnmodifiableList ());
17
+
18
+ final var player1cards = new LinkedList <Integer >();
19
+ final var player2cards = new LinkedList <Integer >();
20
+ var target = player1cards ;
21
+ for (final var line : lines ) {
22
+ if (line .isBlank ()) {
23
+ target = player2cards ;
24
+ }
25
+ if (line .matches ("^[0-9]+$" )) {
26
+ target .add (Integer .parseInt (line ));
27
+ }
28
+ }
29
+ var player1 = new Player (1 , new LinkedList <>(player1cards ));
30
+ var player2 = new Player (2 , new LinkedList <>(player2cards ));
31
+
32
+ // Part 1
33
+ while (player1 .hasCards () && player2 .hasCards ()) {
34
+ final int p1 = player1 .drawTop ();
35
+ final int p2 = player2 .drawTop ();
36
+ if (p1 > p2 ) {
37
+ player1 .addToBottom (p1 );
38
+ player1 .addToBottom (p2 );
39
+ } else {
40
+ player2 .addToBottom (p2 );
41
+ player2 .addToBottom (p1 );
42
+ }
43
+ }
44
+ var winner = player1cards .isEmpty () ? player2 : player1 ;
45
+ System .out .println ("Part 1: " + winner .score ());
46
+
47
+ // Part 2
48
+ player1 = new Player (1 , new LinkedList <>(player1cards ));
49
+ player2 = new Player (2 , new LinkedList <>(player2cards ));
50
+ winner = playGame (player1 , player2 );
51
+ System .out .println ("Part 2: " + winner .score ());
52
+ }
53
+ }
54
+
55
+ protected static Player playGame (final Player player1 , final Player player2 ) {
56
+ final var rounds = new HashSet <>();
57
+ while (player1 .hasCards () && player2 .hasCards ()) {
58
+ final var round = new Round (player1 , player2 );
59
+ if (rounds .contains (round )) {
60
+ return player1 ;
61
+ }
62
+ rounds .add (round );
63
+ final int p1 = player1 .drawTop ();
64
+ final int p2 = player2 .drawTop ();
65
+ if (player1 .cardCountIsAtLeast (p1 ) && player2 .cardCountIsAtLeast (p2 )) {
66
+ final var winner = playGame (player1 .clone (p1 ), player2 .clone (p2 ));
67
+ if (winner .id == player1 .id ) {
68
+ player1 .addToBottom (p1 );
69
+ player1 .addToBottom (p2 );
70
+ } else {
71
+ player2 .addToBottom (p2 );
72
+ player2 .addToBottom (p1 );
73
+ }
74
+ } else {
75
+ if (p1 > p2 ) {
76
+ player1 .addToBottom (p1 );
77
+ player1 .addToBottom (p2 );
78
+ } else {
79
+ player2 .addToBottom (p2 );
80
+ player2 .addToBottom (p1 );
81
+ }
82
+ }
83
+ }
84
+ return player1 .hasCards () ? player1 : player2 ;
85
+ }
86
+
87
+ protected static class Player {
88
+ final int id ;
89
+ final List <Integer > deck ;
90
+
91
+ public Player (final int id , final List <Integer > deck ) {
92
+ this .id = id ;
93
+ this .deck = deck ;
94
+ }
95
+
96
+ public boolean hasCards () {
97
+ return !deck .isEmpty ();
98
+ }
99
+
100
+ public boolean cardCountIsAtLeast (final int count ) {
101
+ return deck .size () >= count ;
102
+ }
103
+
104
+ public int drawTop () {
105
+ return deck .remove (0 );
106
+ }
107
+
108
+ public void addToBottom (final int card ) {
109
+ deck .add (card );
110
+ }
111
+
112
+ public Player clone (final int cardCount ) {
113
+ return new Player (id , new LinkedList <>(deck .subList (0 , cardCount )));
114
+ }
115
+
116
+ public int score () {
117
+ int retval = 0 ;
118
+ int multiplier = deck .size ();
119
+ for (final var card : deck ) {
120
+ retval += card * (multiplier --);
121
+ }
122
+ return retval ;
123
+ }
124
+ }
125
+
126
+ protected static class Round {
127
+ private final List <Integer > x ;
128
+ private final List <Integer > y ;
129
+
130
+ public Round (final List <Integer > x , final List <Integer > y ) {
131
+ this .x = List .copyOf (x );
132
+ this .y = List .copyOf (y );
133
+ }
134
+
135
+ public Round (final Player x , final Player y ) {
136
+ this (x .deck , y .deck );
137
+ }
138
+
139
+ public int hashCode () {
140
+ return Objects .hash (x , y );
141
+ }
142
+
143
+ public boolean equals (final Object o ) {
144
+ if (this == o ) {
145
+ return true ;
146
+ } else if (o == null ) {
147
+ return false ;
148
+ }
149
+ try {
150
+ final Round other = (Round ) o ;
151
+ return Objects .equals (x , other .x ) && Objects .equals (y , other .y );
152
+ } catch (final ClassCastException cce ) {
153
+ return false ;
154
+ }
155
+ }
156
+ }
157
+ }
0 commit comments