1
+ package main .java .codingame .TicTacToe ;
2
+
3
+ import java .io .BufferedReader ;
4
+ import java .io .IOException ;
5
+ import java .io .InputStreamReader ;
6
+
7
+ public class TicTacToe {
8
+ public static void main (String args []) throws IOException {
9
+ final BufferedReader in = new BufferedReader (new InputStreamReader (System .in ));
10
+ final BruteForceAlgorithm bruteForceAlgorithm = new BruteForceAlgorithm ();
11
+ final Board [][] boards = new Board [3 ][3 ];
12
+ for (int i = 0 ; i < boards .length ; i ++) {
13
+ for (int j = 0 ; j < boards [i ].length ; j ++) {
14
+ boards [i ][j ] = new Board ();
15
+ }
16
+ }
17
+ while (true ) {
18
+ String line [] = in .readLine ().split (" " );
19
+ final int opponentRow = Integer .parseInt (line [0 ]), opponentCol = Integer .parseInt (line [1 ]);
20
+ if (opponentCol >= 0 ) {
21
+ Board opponentBoard = boards [opponentRow / 3 ][opponentCol / 3 ];
22
+ opponentBoard .play (0 , (opponentRow % 3 ) * 3 + opponentCol % 3 );
23
+ System .err .println (opponentBoard );
24
+ System .err .println ((opponentRow / 3 ) + " " + (opponentCol / 3 ));
25
+ }
26
+ final int validActionCount = Integer .parseInt (in .readLine ());
27
+ Board board = boards [0 ][0 ];
28
+ int bRow = 0 , bCol = 0 ;
29
+ for (int i = 0 ; i < validActionCount ; i ++) {
30
+ line = in .readLine ().split (" " );
31
+ bRow = Integer .parseInt (line [0 ]);
32
+ bCol = Integer .parseInt (line [1 ]);
33
+ board = boards [bRow / 3 ][bCol / 3 ];
34
+ }
35
+ final int bestMove = bruteForceAlgorithm .findBestMove (board );
36
+ final int row = bestMove / 3 , col = bestMove % 3 ;
37
+ board .play (1 , bestMove );
38
+ System .out .println (((bRow / 3 ) * 3 + row ) + " " + ((bCol / 3 ) * 3 + col ));
39
+ System .err .println (board );
40
+ }
41
+ }
42
+ }
43
+
44
+ class BruteForceAlgorithm {
45
+ public int findBestMove (Board board ) {
46
+ for (int i = 0 ; i < 9 ; i ++) {
47
+ if ((board .occupied & (1 << i )) == 0 ) {
48
+ board .play (1 , i );
49
+ final boolean result = board .result (1 );
50
+ board .undo (1 , i );
51
+ if (result ) {
52
+ return i ;
53
+ }
54
+ }
55
+ }
56
+ for (int i = 0 ; i < 9 ; i ++) {
57
+ if ((board .occupied & (1 << i )) == 0 ) {
58
+ board .play (0 , i );
59
+ final boolean result = board .result (0 );
60
+ board .undo (0 , i );
61
+ if (result ) {
62
+ return i ;
63
+ }
64
+ }
65
+ }
66
+ for (int i = 0 ; i < 9 ; i ++) {
67
+ if ((board .occupied & (1 << i )) == 0 ) {
68
+ board .play (1 , i );
69
+ int waysToWin = 0 ;
70
+ for (int j = 0 ; j < 9 ; j ++) {
71
+ if ((board .occupied & (1 << j )) == 0 ) {
72
+ board .play (1 , j );
73
+ if (board .result (1 )) {
74
+ waysToWin ++;
75
+ }
76
+ board .undo (1 , j );
77
+ }
78
+ }
79
+ board .undo (1 , i );
80
+ if (waysToWin > 1 ) {
81
+ return i ;
82
+ }
83
+ }
84
+ }
85
+ int forks = 0 ;
86
+ int block = -1 ;
87
+ for (int i = 0 ; i < 9 ; i ++) {
88
+ if ((board .occupied & (1 << i )) == 0 ) {
89
+ board .play (1 , i );
90
+ int waysToWin = 0 ;
91
+ for (int j = 0 ; j < 9 ; j ++) {
92
+ if ((board .occupied & (1 << j )) == 0 ) {
93
+ board .play (0 , j );
94
+ if (board .result (0 )) {
95
+ waysToWin ++;
96
+ }
97
+ board .undo (0 , j );
98
+ }
99
+ }
100
+ board .undo (1 , i );
101
+ if (waysToWin > 1 ) {
102
+ forks ++;
103
+ block = i ;
104
+ }
105
+ }
106
+ }
107
+ if (forks > 1 ) {
108
+ for (int i = 0 ; i < 9 ; i ++) {
109
+ if ((board .occupied & (1 << i )) == 0 ) {
110
+ board .play (1 , i );
111
+ int waysToWin = 0 ;
112
+ for (int j = 0 ; j < 9 ; j ++) {
113
+ if ((board .occupied & (1 << j )) == 0 ) {
114
+ board .play (1 , j );
115
+ if (board .result (1 )) {
116
+ waysToWin ++;
117
+ }
118
+ board .undo (1 , j );
119
+ }
120
+ }
121
+ board .undo (1 , i );
122
+ if (waysToWin == 1 ) {
123
+ return i ;
124
+ }
125
+ }
126
+ }
127
+ } else if (forks == 1 ) {
128
+ return block ;
129
+ }
130
+ if ((board .occupied & 16 ) == 0 ) {
131
+ return 4 ;
132
+ }
133
+ int bestMove = -1 ;
134
+ int bestValue = Integer .MIN_VALUE ;
135
+ for (int i = 0 ; i < 9 ; i ++) {
136
+ if ((board .occupied & (1 << i )) == 0 ) {
137
+ final int result = i / 3 == 2 || i % 3 == 2 ? 1 : 2 ;
138
+ if (result > bestValue ) {
139
+ bestValue = result ;
140
+ bestMove = i ;
141
+ }
142
+ }
143
+ }
144
+ return bestMove ;
145
+ }
146
+ }
147
+
148
+ class Board {
149
+ int occupied ;
150
+ int board ;
151
+ final int winningStates [] = new int []{
152
+ 0b111_000_000,
153
+ 0b000_111_000,
154
+ 0b000_000_111,
155
+ 0b100_100_100,
156
+ 0b010_010_010,
157
+ 0b001_001_001,
158
+ 0b100_010_001,
159
+ 0b001_010_100
160
+ };
161
+
162
+ public void play (final int player , final int p ) {
163
+ final int position = 1 << p ;
164
+ if ((occupied & position ) != 0 ) {
165
+ throw new IllegalStateException ("Already occupied!" + p );
166
+ }
167
+ if (player == 1 ) {
168
+ board = board | position ;
169
+ }
170
+ occupied = occupied | position ;
171
+ }
172
+
173
+ public void undo (final int player , final int p ) {
174
+ final int position = 1 << p ;
175
+ if ((occupied & position ) == 0 ) {
176
+ throw new IllegalStateException ("Not occupied!" + p );
177
+ }
178
+ if (player == 1 ) {
179
+ board = board ^ position ;
180
+ }
181
+ occupied = occupied ^ position ;
182
+ }
183
+
184
+ public boolean result (final int player ) {
185
+ final int boardForPlayer = player == 1 ? board : ~board ;
186
+ for (final int winningState : winningStates ) {
187
+ if (winningState == (boardForPlayer & occupied & winningState )) {
188
+ return true ;
189
+ }
190
+ }
191
+ return false ;
192
+ }
193
+
194
+ @ Override
195
+ public String toString () {
196
+ return "Occupied:" + Integer .toBinaryString (occupied ) + "\n Board:" + Integer .toBinaryString (board );
197
+ }
198
+ }
0 commit comments