@@ -233,14 +233,13 @@ export class ConnectFourGame {
233
233
left_pointer_y ++ ;
234
234
}
235
235
while (
236
- right_pointer_x + 1 < CONNECT_FOUR_COLUMN_COUNT - 1 &&
236
+ right_pointer_x + 1 < CONNECT_FOUR_COLUMN_COUNT && // used to be an extra -1, fixed bug
237
237
right_pointer_y - 1 >= 0 &&
238
238
state . columns [ right_pointer_x + 1 ] . tokens [ right_pointer_y - 1 ] == sign
239
239
) {
240
240
right_pointer_x ++ ;
241
241
right_pointer_y -- ;
242
242
}
243
-
244
243
if ( right_pointer_x - left_pointer_x + 1 >= 4 ) {
245
244
return true ;
246
245
}
@@ -259,6 +258,8 @@ export class ConnectFourGame {
259
258
// newly placed token
260
259
const horizontalIndex = columnIndex ;
261
260
const verticalIndex = state . columns [ columnIndex ] . fill - 1 ;
261
+ //console.log(horizontalIndex);
262
+ //console.log(verticalIndex);
262
263
const column = state . columns [ columnIndex ] ;
263
264
const sign : ConnectFourGameSign = state . columns [ columnIndex ] . tokens [ verticalIndex ] ;
264
265
@@ -271,11 +272,11 @@ export class ConnectFourGame {
271
272
state . winType = ConnectFourWinType . Horizontal ;
272
273
state . status = this . determineWinner ( sign ) ;
273
274
} else if ( this . checkForDiagonalLBRTWin ( state , horizontalIndex , verticalIndex , sign ) ) {
274
- // Check for diagonal win (left top right bottom )
275
+ // Check for diagonal win (left bottom right top )
275
276
state . winType = ConnectFourWinType . DiagonalLBRT ;
276
277
state . status = this . determineWinner ( sign ) ;
277
278
} else if ( this . checkForDiagonalLTRBWin ( state , horizontalIndex , verticalIndex , sign ) ) {
278
- // Check for diagonal win (left bottom right top )
279
+ // Check for diagonal win (left top right bottom )
279
280
state . winType = ConnectFourWinType . DiagonalLTRB ;
280
281
state . status = this . determineWinner ( sign ) ;
281
282
} else if ( state . columns . every ( ( column ) => column . fill === 6 ) ) {
@@ -411,19 +412,19 @@ ${this.state.player2Username}: ${getEmojiFromSign(this.state.player2Sign)}
411
412
// Player1TimeOut = 5,
412
413
// Player2TimeOut = 6,
413
414
// Unknown = 7,
414
- private updateState = ( state : ConnectFourGameState , columnNumber : number , turn : number ) : ConnectFourGameState => {
415
+ private updateState = ( state : ConnectFourGameState , columnNumber : number , turn : ConnectFourGameSign ) : ConnectFourGameState => {
415
416
const fill : number = state . columns [ columnNumber ] . fill ;
416
- if ( turn === 1 ) { //means its Codeybot's turn
417
- state . columns [ columnNumber ] . tokens [ fill ] = 3 ;
417
+ if ( turn === ConnectFourGameSign . Player2 ) {
418
+ state . columns [ columnNumber ] . tokens [ fill ] = ConnectFourGameSign . Player2 ;
418
419
} else {
419
- state . columns [ columnNumber ] . tokens [ fill ] = 2 ;
420
+ state . columns [ columnNumber ] . tokens [ fill ] = ConnectFourGameSign . Player1 ;
420
421
}
421
422
state . columns [ columnNumber ] . fill = state . columns [ columnNumber ] . fill + 1 ;
422
423
return state ;
423
424
}
424
425
425
426
// returns number of possible wins remaining
426
- private possibleWins = ( state : ConnectFourGameState , opponentSign : number ) : number => {
427
+ private possibleWins = ( state : ConnectFourGameState , opponentSign : ConnectFourGameSign ) : number => {
427
428
let possibleWins : number = 0 ;
428
429
// check vertical
429
430
for ( let i = 0 ; i < CONNECT_FOUR_COLUMN_COUNT ; i ++ ) {
@@ -463,51 +464,49 @@ ${this.state.player2Username}: ${getEmojiFromSign(this.state.player2Sign)}
463
464
464
465
// takes a ConnectFourGameState and evaluates it according to heuristic function
465
466
private evaluate = ( state : ConnectFourGameState ) : number => {
466
- let codeyPoints : number = this . possibleWins ( state , 2 ) ; // 3 represents Codeybot sign
467
- let opponentPoints : number = this . possibleWins ( state , 3 ) ; // 2 represents player1 sign
467
+ let codeyPoints : number = this . possibleWins ( state , ConnectFourGameSign . Player1 ) ; // 3 represents Codeybot sign
468
+ let opponentPoints : number = this . possibleWins ( state , ConnectFourGameSign . Player2 ) ; // 2 represents player1 sign
468
469
return codeyPoints - opponentPoints ;
469
470
}
470
471
471
472
// from perspective of Codeybot, +infinity means Codeybot win, -infinity means Player1 wins
472
- // turn = 1, means it's Codeybot's turn, turn = -1 means it's opponent's turn
473
473
// returns the best possible score that can be achieved, given that Player1 plays optimally
474
- private miniMax = ( state : ConnectFourGameState , depth : number , turn : number ) : number => {
475
- if ( state . status === 2 ) { // means draw
474
+ private miniMax = ( state : ConnectFourGameState , depth : number , turn : ConnectFourGameSign ) : number => {
475
+ if ( state . status === ConnectFourGameStatus . Draw ) {
476
476
return 0 ;
477
477
}
478
- if ( state . status === 3 ) { // means Player1 wins
478
+ if ( state . status === ConnectFourGameStatus . Player1Win ) {
479
479
return - Infinity ;
480
480
}
481
- if ( state . status === 4 ) { // means Player 2 wins
481
+ if ( state . status === ConnectFourGameStatus . Player2Win ) {
482
482
return Infinity ;
483
483
}
484
484
if ( depth === 0 ) {
485
485
return this . evaluate ( state ) ; //heuristic function to evaluate state of game
486
486
}
487
487
488
488
// if it is Codeybot's turn, we want to find move that maximizes score
489
- if ( turn === 1 ) {
489
+ const column_choices : number [ ] = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
490
+ if ( turn === ConnectFourGameSign . Player2 ) {
490
491
let value : number = - Infinity ;
491
- const column_choices : number [ ] = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
492
492
for ( const column_choice of column_choices ) {
493
493
if ( state . columns [ column_choice ] . fill < CONNECT_FOUR_ROW_COUNT ) {
494
494
let newState : ConnectFourGameState = JSON . parse ( JSON . stringify ( state ) ) ;
495
495
this . updateState ( newState , column_choice , turn ) ;
496
- this . setStatus ( newState , column_choice ) ;
497
- value = Math . max ( value , this . miniMax ( newState , depth - 1 , turn * - 1 ) ) ;
496
+ this . setStatus ( newState , column_choice ) ; // setStatus assumes newState has already been updated with chip
497
+ value = Math . max ( value , this . miniMax ( newState , depth - 1 , ConnectFourGameSign . Player1 ) ) ;
498
498
}
499
499
}
500
500
return value ;
501
- } else { // (turn = -1) it is Player 1's turn, so we want to find minimum score (this assumes Player 1 plays optimally)
501
+ } else { //it is Player 1's turn, so we want to find minimum score (this assumes Player 1 plays optimally)
502
502
let value : number = Infinity ;
503
- const column_choices : number [ ] = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 ] ;
504
503
for ( const column_choice of column_choices ) {
505
504
// if selected column is not already full, recurse down the branch
506
505
if ( state . columns [ column_choice ] . fill < CONNECT_FOUR_ROW_COUNT ) {
507
506
let newState : ConnectFourGameState = JSON . parse ( JSON . stringify ( state ) ) ;
508
507
this . updateState ( newState , column_choice , turn ) ;
509
508
this . setStatus ( newState , column_choice ) ;
510
- value = Math . min ( value , this . miniMax ( newState , depth - 1 , turn * - 1 ) ) ;
509
+ value = Math . min ( value , this . miniMax ( newState , depth - 1 , ConnectFourGameSign . Player2 ) ) ;
511
510
}
512
511
}
513
512
return value ;
@@ -519,9 +518,9 @@ ${this.state.player2Username}: ${getEmojiFromSign(this.state.player2Sign)}
519
518
for ( let i = 0 ; i < 7 ; i ++ ) {
520
519
if ( state . columns [ i ] . fill < CONNECT_FOUR_ROW_COUNT ) {
521
520
let newState : ConnectFourGameState = JSON . parse ( JSON . stringify ( state ) ) ; // make a deep copy of game state
522
- this . updateState ( newState , i , 1 ) ;
521
+ this . updateState ( newState , i , ConnectFourGameSign . Player2 ) ;
523
522
this . setStatus ( newState , i ) ;
524
- column_scores [ i ] = this . miniMax ( newState , 4 , - 1 ) ;
523
+ column_scores [ i ] = this . miniMax ( newState , 4 , ConnectFourGameSign . Player1 ) ;
525
524
}
526
525
}
527
526
let value = - Infinity ;
@@ -619,10 +618,6 @@ export const getStateAsString = (state: ConnectFourGameState): string => {
619
618
return result ;
620
619
} ;
621
620
622
- // export const getCodeyConnectFourSign = (): ConnectFourGameSign => {
623
- // return getRandomIntFrom1(7);
624
- // };
625
-
626
621
export const updateColumn = ( column : ConnectFourColumn , sign : ConnectFourGameSign ) : boolean => {
627
622
const fill : number = column . fill ;
628
623
if ( fill < CONNECT_FOUR_ROW_COUNT ) {
0 commit comments