@@ -30,11 +30,12 @@ class UltimateTTT {
30
30
void printBoard () const ;
31
31
32
32
const static int NUM_INPUTS = 9 ;
33
- const static int NUM_OUTPUTS = 81 ;
33
+ const static int NUM_OUTPUTS = 90 ;
34
34
private:
35
35
bool takeTurn (const States state, const int turns);
36
36
bool isEmpty () const ;
37
37
bool isFull () const ;
38
+ bool subBoardTied (const int subBoard) const ;
38
39
39
40
Matrix toMatrix () const ;
40
41
Matrix toPlayerPerspective (const States state) const ;
@@ -47,7 +48,7 @@ class UltimateTTT {
47
48
48
49
vector<unsigned int > bestMoves (const vector<double >& input) const ;
49
50
// void printBoard() const;
50
- bool hasWon ( ) const ;
51
+ bool boardHasWon ( const uint32_t board ) const ;
51
52
52
53
vector<uint32_t > m_board;
53
54
uint32_t m_metaBoard;
@@ -69,17 +70,12 @@ template <class T1, class T2>
69
70
UltimateTTT<T1, T2>::UltimateTTT(playerContainer<T1>& player1,
70
71
playerContainer<T2>& player2, bool verbose)
71
72
: m_board(9 , (uint32_t )0 )
72
- , activeBoard(0 )
73
+ , activeBoard(4 )
73
74
, m_player1(player1)
74
75
, m_player2(player2)
75
76
, dontRevisitSquares(true )
76
77
, m_verbose(verbose){
77
78
m_metaBoard = (uint32_t )0 ;
78
- setBoardAtPos (-1 , 0 , States::playerO);
79
- setBoardAtPos (-1 , 5 , States::playerX);
80
- setBoardAtPos (-1 , 8 , States::playerX);
81
- setBoardAtPos (1 , 7 , States::playerX);
82
- setBoardAtPos (6 , 4 , States::playerX);
83
79
}
84
80
85
81
/* Plays until a player wins or the board is full.
@@ -115,7 +111,18 @@ bool UltimateTTT<T1, T2>::isEmpty() const{
115
111
template <class T1 , class T2 >
116
112
bool UltimateTTT<T1, T2>::isFull() const {
117
113
for (int i = 0 ; i < 9 ; ++i){
118
- if (getBoardAtPos (-1 , i) == States::empty){
114
+ if (getBoardAtPos (-1 , i) == States::empty
115
+ && !subBoardTied (i)){
116
+ return false ;
117
+ }
118
+ }
119
+ return true ;
120
+ }
121
+
122
+ template <class T1 , class T2 >
123
+ bool UltimateTTT<T1, T2>::subBoardTied(const int subBoard) const {
124
+ for (int i = 0 ; i < 9 ; ++i){
125
+ if (getBoardAtPos (subBoard, i) == States::empty){
119
126
return false ;
120
127
}
121
128
}
@@ -200,8 +207,12 @@ void UltimateTTT<T1, T2>::printBoard() const{
200
207
} else if (i % 2 == 0 && (i % 8 != 0 ) && j % 4 == 3 &&
201
208
(j % 16 != 15 )){
202
209
States curState = States::empty;
203
- if (metaOccupied && dontRevisitSquares && subPostion == 4 ){
204
- curState = getBoardAtPos (-1 , subBoard);
210
+ if (metaOccupied && dontRevisitSquares){
211
+ if (subPostion == 4 ){
212
+ curState = getBoardAtPos (-1 , subBoard);
213
+ } else {
214
+ curState = States::empty;
215
+ }
205
216
} else {
206
217
curState = getBoardAtPos (subBoard, subPostion);
207
218
}
@@ -226,9 +237,9 @@ void UltimateTTT<T1, T2>::printBoard() const{
226
237
*/
227
238
template <class T1 , class T2 >
228
239
Matrix UltimateTTT<T1, T2>::toMatrix() const {
229
- Matrix temp (1 , NUM_OUTPUTS);
240
+ Matrix temp (1 , NUM_OUTPUTS - 9 );
230
241
231
- for (int i = 0 ; i < NUM_OUTPUTS; ++i){
242
+ for (int i = 0 ; i < ( NUM_OUTPUTS - 9 ) ; ++i){
232
243
temp (0 , i) = (float )getBoardAtPos (i);
233
244
}
234
245
return temp;
@@ -372,47 +383,36 @@ void UltimateTTT<T1, T2>::setBoardAtPos(const int i, const States state){
372
383
int position = x % 3 + 3 * (y % 3 );
373
384
374
385
uint32_t shiftAmount = (uint32_t )(8 - position) << 1 ;
386
+ // Clear the 2-bit-wode field
387
+ m_board[subBoard] &= ~((uint32_t )3 << shiftAmount);
375
388
376
- if (subBoard < 0 ){
377
- // Clear the 2-bit-wode field
378
- m_metaBoard &= ~((uint32_t )3 << shiftAmount);
379
-
380
- // Set the new state at the 2-bit-wide field
381
- uint32_t val = (uint32_t )state;
382
- m_metaBoard |= (val << shiftAmount);
383
- } else {
384
- // Clear the 2-bit-wode field
385
- m_board[subBoard] &= ~((uint32_t )3 << shiftAmount);
386
-
387
- // Set the new state at the 2-bit-wide field
388
- uint32_t val = (uint32_t )state;
389
- m_board[subBoard] |= (val << shiftAmount);
390
- }
391
-
389
+ // Set the new state at the 2-bit-wide field
390
+ uint32_t val = (uint32_t )state;
391
+ m_board[subBoard] |= (val << shiftAmount);
392
392
}
393
393
394
- // Helper function to determine if a player has won
394
+
395
395
template <class T1 , class T2 >
396
- bool UltimateTTT<T1, T2>::hasWon( ) const {
396
+ bool UltimateTTT<T1, T2>::boardHasWon( const uint32_t board ) const {
397
397
// PlayerX
398
- if ((m_metaBoard & (uint32_t )65793 ) == (uint32_t )65793 ){ return true ;}
399
- if ((m_metaBoard & (uint32_t )4368 ) == (uint32_t )4368 ){ return true ;}
400
- if ((m_metaBoard & (uint32_t )86016 ) == (uint32_t )86016 ){ return true ;}
401
- if ((m_metaBoard & (uint32_t )1344 ) == (uint32_t )1344 ){ return true ;}
402
- if ((m_metaBoard & (uint32_t )21 ) == (uint32_t )21 ){ return true ;}
403
- if ((m_metaBoard & (uint32_t )66576 ) == (uint32_t )66576 ){ return true ;}
404
- if ((m_metaBoard & (uint32_t )16644 ) == (uint32_t )16644 ){ return true ;}
405
- if ((m_metaBoard & (uint32_t )4161 ) == (uint32_t )4161 ){ return true ;}
398
+ if ((board & (uint32_t )65793 ) == (uint32_t )65793 ){ return true ;}
399
+ if ((board & (uint32_t )4368 ) == (uint32_t )4368 ){ return true ;}
400
+ if ((board & (uint32_t )86016 ) == (uint32_t )86016 ){ return true ;}
401
+ if ((board & (uint32_t )1344 ) == (uint32_t )1344 ){ return true ;}
402
+ if ((board & (uint32_t )21 ) == (uint32_t )21 ){ return true ;}
403
+ if ((board & (uint32_t )66576 ) == (uint32_t )66576 ){ return true ;}
404
+ if ((board & (uint32_t )16644 ) == (uint32_t )16644 ){ return true ;}
405
+ if ((board & (uint32_t )4161 ) == (uint32_t )4161 ){ return true ;}
406
406
407
407
// PlayerO
408
- if ((m_metaBoard & (uint32_t )131586 ) == (uint32_t )131586 ){ return true ;}
409
- if ((m_metaBoard & (uint32_t )8736 ) == (uint32_t )8736 ){ return true ;}
410
- if ((m_metaBoard & (uint32_t )172032 ) == (uint32_t )172032 ){ return true ;}
411
- if ((m_metaBoard & (uint32_t )2688 ) == (uint32_t )2688 ){ return true ;}
412
- if ((m_metaBoard & (uint32_t )42 ) == (uint32_t )42 ){ return true ;}
413
- if ((m_metaBoard & (uint32_t )133152 ) == (uint32_t )133152 ){ return true ;}
414
- if ((m_metaBoard & (uint32_t )33288 ) == (uint32_t )33288 ){ return true ;}
415
- if ((m_metaBoard & (uint32_t )8322 ) == (uint32_t )8322 ){ return true ;}
408
+ if ((board & (uint32_t )131586 ) == (uint32_t )131586 ){ return true ;}
409
+ if ((board & (uint32_t )8736 ) == (uint32_t )8736 ){ return true ;}
410
+ if ((board & (uint32_t )172032 ) == (uint32_t )172032 ){ return true ;}
411
+ if ((board & (uint32_t )2688 ) == (uint32_t )2688 ){ return true ;}
412
+ if ((board & (uint32_t )42 ) == (uint32_t )42 ){ return true ;}
413
+ if ((board & (uint32_t )133152 ) == (uint32_t )133152 ){ return true ;}
414
+ if ((board & (uint32_t )33288 ) == (uint32_t )33288 ){ return true ;}
415
+ if ((board & (uint32_t )8322 ) == (uint32_t )8322 ){ return true ;}
416
416
417
417
return false ;
418
418
}
@@ -437,16 +437,49 @@ bool UltimateTTT<T1, T2>::takeTurn(const States state, const int turn){
437
437
}
438
438
439
439
// Make the best move from available squares
440
+ bool foundOpenSpot = false ;
440
441
for (int i = 0 ; i < NUM_OUTPUTS; ++i){
441
- if (getBoardAtPos (moves[i]) == States::empty){
442
- setBoardAtPos (moves[i], state);
443
- break ;
442
+ if (moves[i] < 9 ){
443
+ if (getBoardAtPos (activeBoard, moves[i]) == States::empty
444
+ && (getBoardAtPos (-1 , activeBoard) == States::empty
445
+ || !dontRevisitSquares)){
446
+ setBoardAtPos (activeBoard, moves[i], state);
447
+ if (getBoardAtPos (-1 , activeBoard) == States::empty
448
+ && boardHasWon (m_board[activeBoard])){
449
+ setBoardAtPos (-1 , activeBoard, state);
450
+ }
451
+ activeBoard = moves[i];
452
+ foundOpenSpot = true ;
453
+ break ;
454
+ }
455
+ }
456
+ }
457
+ if (!foundOpenSpot){
458
+
459
+ for (int i = 0 ; i < NUM_OUTPUTS; ++i){
460
+ if (moves[i] < 81 ){
461
+ int subBoard = (moves[i] % 9 ) / 3 +
462
+ 3 * (int )((int )(moves[i] / 9 ) / 3 );
463
+ if (getBoardAtPos (moves[i]) == States::empty
464
+ && (getBoardAtPos (-1 , subBoard) == States::empty
465
+ || !dontRevisitSquares)){
466
+ setBoardAtPos (moves[i], state);
467
+
468
+ if (getBoardAtPos (-1 , subBoard) == States::empty
469
+ && boardHasWon (m_board[subBoard])){
470
+ setBoardAtPos (-1 , subBoard, state);
471
+ }
472
+ activeBoard = subBoard;
473
+ break ;
474
+ }
475
+ }
444
476
}
477
+
445
478
}
446
479
447
480
// Check if the move played was a winning move
448
- if (turn >= 5 ){
449
- if (hasWon ( )){
481
+ if (turn >= 17 ){
482
+ if (boardHasWon (m_metaBoard )){
450
483
if (state == States::playerX){
451
484
m_player1.player .addToFitness (1.0 + (10.0 - turn) / 10.0 );
452
485
} else {
@@ -472,7 +505,7 @@ bool UltimateTTT<T1, T2>::takeTurn(const States state, const int turn){
472
505
473
506
474
507
// Check if the board is now full
475
- if (turn == 9 ){
508
+ if (turn == 81 ){
476
509
if (isFull ()){
477
510
m_player1.player .addToFitness (1.0 );
478
511
m_player2.player .addToFitness (1.0 );
0 commit comments