@@ -23,7 +23,7 @@ public static void main(String args[]) throws IOException {
2323 largeBoard .play (2 , opponentMove );
2424 algorithm .root = algorithm .root .getChild (opponentMove );
2525 algorithm .root .parent = null ;
26- algorithm .construct (largeBoard , 2 );
26+ algorithm .construct (largeBoard , 1 );
2727 System .err .println (largeBoard );
2828 }
2929 final int validActionCount = Integer .parseInt (in .readLine ());
@@ -36,12 +36,13 @@ public static void main(String args[]) throws IOException {
3636 largeBoard .play (1 , bestMove );
3737 algorithm .root = algorithm .root .getChild (bestMove );
3838 algorithm .root .parent = null ;
39- algorithm .construct (largeBoard , 1 );
39+ algorithm .construct (largeBoard , 2 );
4040 System .err .println (largeBoard );
4141 }
4242 }
4343}
4444
45+ //todo: write unit tests for each function
4546class MCTS {
4647 public static final int TIME_OUT = 50 ;
4748 public static final double CONSTANT = 10000d ;
@@ -51,7 +52,7 @@ public int suggestMove() {
5152 return root .getChildren ()
5253 .stream ()
5354 .max (Comparator .comparingDouble (node -> node .wins / (double ) node .plays + node .plays / CONSTANT ))
54- .map (c -> c .col )
55+ .map (c -> c .move )
5556 .orElseThrow (() -> new RuntimeException ("No moves to play!" ));
5657 }
5758
@@ -60,7 +61,8 @@ public void construct(final LargeBoard board, int player) {
6061 while (System .currentTimeMillis () - startTime <= TIME_OUT ) {
6162 TreeNode current = root ;
6263 int position = current .selectChild (board );
63- while (current .getChild (position ) != null ) {
64+ //todo: Why do you check for canPlay?
65+ while (board .canPlay (position ) && current .getChild (position ) != null ) {
6466 current = current .getChild (position );
6567 board .play (player , position );
6668 position = current .selectChild (board );
@@ -80,15 +82,15 @@ public void construct(final LargeBoard board, int player) {
8082class TreeNode {
8183 private static final Random random = new Random ();
8284 public static final int SIMULATION_CONSTANT = 50 ;
83- public final int col ;
85+ public final int move ;
8486 public int plays ;
8587 public double wins ;
8688 public TreeNode parent ;
8789 private final int player ;
8890 private Map <Integer , TreeNode > children = new HashMap <>();
8991
90- public TreeNode (final int col , final TreeNode parent , final int player ) {
91- this .col = col ;
92+ public TreeNode (final int move , final TreeNode parent , final int player ) {
93+ this .move = move ;
9294 this .parent = parent ;
9395 this .player = player ;
9496 }
@@ -98,21 +100,39 @@ public int selectChild(final LargeBoard board) {
98100 .stream ()
99101 .max (Comparator .comparingDouble (TreeNode ::getUtility ));
100102 double maxUtility = child .map (TreeNode ::getUtility ).orElse (0d );
101- int bestColumn = child .map (c -> c .col ).orElse (0 );
103+ int bestColumn = child .map (c -> c .move ).orElse (0 );
102104 final Set <Integer > expandedSet = children .keySet ();
103105 final int currentBoardIndex = board .currentBoard ();
104- int max = 81 ;
105- int i = 0 ;
106106 if (currentBoardIndex != -1 ) {
107- i = (currentBoardIndex / 3 ) * 27 + (currentBoardIndex % 3 ) * 3 ;
108- max = i + 21 ;
109- }
110- for (; i < max ; i ++) {
111- if (board .canPlay (i ) && !expandedSet .contains (i )) {
112- final double utility = Math .sqrt (Math .log (plays + 1 )) + (0.05 / Math .abs (9 / 2.0 - i ));
113- if (utility > maxUtility ) {
114- maxUtility = utility ;
115- bestColumn = i ;
107+ int start = (currentBoardIndex / 3 ) * 27 + (currentBoardIndex % 3 ) * 3 ;
108+ for (int x = 0 ; x < 3 ; x ++, start ++) {
109+ for (int y = 0 ; y < 3 ; y ++) {
110+ int i = start + y * 9 ;
111+ if (board .canPlay (i ) && !expandedSet .contains (i )) {
112+ final double utility = Math .sqrt (Math .log (plays + 1 )) + (0.05 / Math .abs (40 - i ));
113+ if (utility > maxUtility ) {
114+ maxUtility = utility ;
115+ bestColumn = i ;
116+ }
117+ }
118+ }
119+ }
120+ } else {
121+ for (int boardIndex = 0 ; boardIndex < 9 ; boardIndex ++) {
122+ if ((board .largeOccupied & (1 << boardIndex )) == 0 ) {
123+ int start = (boardIndex / 3 ) * 27 + (boardIndex % 3 ) * 3 ;
124+ for (int x = 0 ; x < 3 ; x ++, start ++) {
125+ for (int y = 0 ; y < 3 ; y ++) {
126+ int i = start + y * 9 ;
127+ if (board .canPlay (i ) && !expandedSet .contains (i )) {
128+ final double utility = Math .sqrt (Math .log (plays + 1 )) + (0.05 / Math .abs (40 - i ));
129+ if (utility > maxUtility ) {
130+ maxUtility = utility ;
131+ bestColumn = i ;
132+ }
133+ }
134+ }
135+ }
116136 }
117137 }
118138 }
@@ -127,19 +147,34 @@ private double simulate(final LargeBoard board, int player) {
127147 final int numberOfMovesPlayed = board .movesPlayed ;
128148 final int originalPlayer = player ;
129149 while (board .result () == -1 ) {
150+ int movesToPlay = 0 ;
130151 final int currentBoardIndex = board .currentBoard ();
131- int max = 81 ;
132- int position = 0 ;
152+ final int possibilities [] = new int [currentBoardIndex != -1 ? 9 : 81 ];
133153 if (currentBoardIndex != -1 ) {
134- position = (currentBoardIndex / 3 ) * 27 + (currentBoardIndex % 3 ) * 3 ;
135- max = position + 21 ;
136- }
137- final int possibilities [] = new int [max - position ];
138- int movesToPlay = 0 ;
139- for (; position < max ; position ++) {
140- if (board .canPlay (position )) {
141- possibilities [movesToPlay ] = position ;
142- movesToPlay ++;
154+ int start = (currentBoardIndex / 3 ) * 27 + (currentBoardIndex % 3 ) * 3 ;
155+ for (int x = 0 ; x < 3 ; x ++, start ++) {
156+ for (int y = 0 ; y < 3 ; y ++) {
157+ int position = start + y * 9 ;
158+ if (board .canPlay (position )) {
159+ possibilities [movesToPlay ] = position ;
160+ movesToPlay ++;
161+ }
162+ }
163+ }
164+ } else {
165+ for (int boardIndex = 0 ; boardIndex < 9 ; boardIndex ++) {
166+ if ((board .largeOccupied & (1 << boardIndex )) == 0 ) {
167+ int start = (boardIndex / 3 ) * 27 + (boardIndex % 3 ) * 3 ;
168+ for (int x = 0 ; x < 3 ; x ++, start ++) {
169+ for (int y = 0 ; y < 3 ; y ++) {
170+ int position = start + y * 9 ;
171+ if (board .canPlay (position )) {
172+ possibilities [movesToPlay ] = position ;
173+ movesToPlay ++;
174+ }
175+ }
176+ }
177+ }
143178 }
144179 }
145180 if (movesToPlay == 0 ) {
@@ -188,14 +223,14 @@ public TreeNode getChild(final int col) {
188223 @ Override
189224 public String toString () {
190225 return "TreeNode{" +
191- "\n col =" + col +
226+ "\n move =" + move +
192227 ", \n plays=" + plays +
193228 ", \n wins=" + wins +
194- ", \n parent=" + (parent == null ? -1 : parent .col ) +
229+ ", \n parent=" + (parent == null ? -1 : parent .move ) +
195230 ", \n player=" + player +
196231 ", \n children=" + children .values ()
197232 .stream ()
198- .map (c -> "MOVE: " + c . col + " WINS: " + c .wins + " PLAYS: " + c .plays + "\n " )
233+ .map (node -> "MOVE: " + node . move + " WINS: " + node .wins + " PLAYS: " + node .plays + "\n " )
199234 .collect (Collectors .joining ("\n " )) +
200235 '}' ;
201236 }
@@ -318,9 +353,9 @@ public int currentBoard() {
318353 @ Override
319354 public String toString () {
320355 return "LargeBoard{" +
321- "\n largeBoard=" + largeBoard +
322- ", \n largeCaptures=" + largeCaptures +
323- ", \n largeOccupied=" + largeOccupied +
356+ "\n largeBoard=" + Integer . toBinaryString ( largeBoard ) +
357+ ", \n largeCaptures=" + Integer . toBinaryString ( largeCaptures ) +
358+ ", \n largeOccupied=" + Integer . toBinaryString ( largeOccupied ) +
324359 ", \n movesPlayed=" + movesPlayed +
325360 ", \n moves=" + Arrays .toString (moves ) +
326361 ", \n boards=" + Arrays .deepToString (boards ) +
0 commit comments