async void PlayMove(int gc, int gr, int bc, int br, int cc, int cr, Boolean isHuman) { UIEnabled = false; // show last turn icon if this is the very first move if (lastMoveCol == -1 || lastMoveRow == -1) { LastTurnImg.Visibility = Windows.UI.Xaml.Visibility.Visible; } lastMoveState = game.PlayMove(currentPlayer, bc, br, cc, cr); if (game.IsMoveSuccess(lastMoveState)) { // save this as the last move lastMoveRow = gr; lastMoveCol = gc; // stop any flash animations ClearFlashing(); // display turn tip for the *next* player //AnimateYourTurn(); TurnImg.Source = new BitmapImage(new Uri(this.BaseUri, currentPlayer == 1 ? oturnSrc : xturnSrc)); Animations.PopUIElement( TurnImg, 0, 1, 0, 1, 0.5 * turnImgWidth, 0, 0.5 * turnImgHeight, 0, Animations.popInEasing); // flash viable boards for next turn if (game.NextBoardCol == -1) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { FlashCell(rects[i, j]); } } } else { for (int i = 3 * cc; i < 3 * (cc + 1); i++) { for (int j = 3 * cr; j < 3 * (cr + 1); j++) { FlashCell(rects[j, i]); } } } } StatusText.Text = lastMoveState.ToString(); if (game.IsMoveSuccess(lastMoveState)) { // put an X/O // get original cell coords first FillCell(gr, gc, currentPlayer == 1 ? "X" : "O"); if (soundEffectsEnabled) { // play the corresponding sound effect if (currentPlayer == 1) { wavePlayer.PlayWave("playerX"); } else { wavePlayer.PlayWave("playerO"); } } } switch (lastMoveState) { case MoveState.SUCCESS_GAME_ON: // nothing further for now break; case MoveState.SUCCESS_BOARD_WON_GAME_ON: // if the winner is not AI, color the board then greet the board winner if (!(currentPlayer == -1 && gameMode > GameMode.TwoPlayer)) { ShowRandomGreeting(); ColorBoard(bc, br, (currentPlayer == 1) ? GetColor(GameColor.BoardWonX) : GetColor(GameColor.BoardWonO)); await Task.Delay(TimeSpan.FromSeconds(greetingDurationSec)); } // color the won board ColorBoard(bc, br, (currentPlayer == 1) ? GetColor(GameColor.BoardWonX) : GetColor(GameColor.BoardWonO)); break; case MoveState.SUCCESS_BOARD_WON_GAME_DRAW: // color the won board ColorBoard(bc, br, (currentPlayer == 1) ? GetColor(GameColor.BoardWonX) : GetColor(GameColor.BoardWonO)); // then show the game over (draw) popup GameOver(); break; case MoveState.SUCCESS_BOARD_WON_GAME_WON: // color the won board ColorBoard(bc, br, (currentPlayer == 1) ? GetColor(GameColor.BoardWonX) : GetColor(GameColor.BoardWonO)); // then show the game over popup GameOver(); break; case MoveState.SUCCESS_BOARD_DRAW_GAME_WON: // color the won board ColorBoard(bc, br, GetColor(GameColor.BoardDraw)); // then show the game over popup GameOver(); break; case MoveState.SUCCESS_BOARD_DRAW_GAME_LOST: // color the won board ColorBoard(bc, br, GetColor(GameColor.BoardDraw)); // then show the game over popup currentPlayer = -1 * currentPlayer; GameOver(); break; case MoveState.SUCCESS_BOARD_WON_GAME_LOST: // color the won board ColorBoard(bc, br, (currentPlayer == 1) ? GetColor(GameColor.BoardWonX) : GetColor(GameColor.BoardWonO)); // then show the game over popup currentPlayer = -1 * currentPlayer; GameOver(); break; case MoveState.SUCCESS_BOARD_DRAW_GAME_DRAW: ColorBoard(bc, br, GetColor(GameColor.BoardDraw)); // then show the game over (draw) popup GameOver(); break; case MoveState.SUCCESS_BOARD_DRAW_GAME_ON: // color the draw board ColorBoard(bc, br, GetColor(GameColor.BoardDraw)); break; } if (game.IsSuccessAndGameON(lastMoveState)) { currentPlayer *= -1; //System.Diagnostics.Debug.WriteLine("Current player " + currentPlayer); if (isHuman && gameMode > GameMode.TwoPlayer) { int Cc, Cr; // sleep pretend we're thinking turnProgressBar.Visibility = Windows.UI.Xaml.Visibility.Visible; // Wait for AI to finish rendering await Task.Delay(TimeSpan.FromSeconds(1)); switch (gameMode) { case GameMode.AI_LVL_1: GreedyAI1.Play(game, currentPlayer, ref cc, ref cr, out Cc, out Cr, 1); break; case GameMode.AI_LVL_2: GreedyAI1.Play(game, currentPlayer, ref cc, ref cr, out Cc, out Cr, 2); break; case GameMode.AI_LVL_3: GreedyAI1.Play(game, currentPlayer, ref cc, ref cr, out Cc, out Cr, 3); break; default: Cc = -1; Cr = -1; break; } turnProgressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed; if (cc != -1) { PlayMove(cc * 3 + Cc, cr * 3 + Cr, cc, cr, Cc, Cr, false); } } } UIEnabled = true; }
private static float PlayBestGlobalMove(int[, , ,] Cells, int player, ref int Bc, ref int Br, out int Cc, out int Cr, ref int age, int maxAge) { List <int> availableBc = new List <int>(); List <int> availableBr = new List <int>(); List <int> availableCc = new List <int>(); List <int> availableCr = new List <int>(); Cc = -1; Cr = -1; if (age > maxAge) { float wins = 0; float loses = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if ( Cells[i, j, 0, 0] + Cells[i, j, 0, 1] + Cells[i, j, 0, 2] == player * 3 || Cells[i, j, 1, 0] + Cells[i, j, 1, 1] + Cells[i, j, 1, 2] == player * 3 || Cells[i, j, 2, 0] + Cells[i, j, 2, 1] + Cells[i, j, 2, 2] == player * 3 || Cells[i, j, 0, 0] + Cells[i, j, 1, 0] + Cells[i, j, 2, 0] == player * 3 || Cells[i, j, 0, 1] + Cells[i, j, 1, 1] + Cells[i, j, 2, 1] == player * 3 || Cells[i, j, 0, 2] + Cells[i, j, 1, 2] + Cells[i, j, 2, 2] == player * 3 || Cells[i, j, 0, 0] + Cells[i, j, 1, 1] + Cells[i, j, 2, 2] == player * 3 || Cells[i, j, 0, 2] + Cells[i, j, 1, 1] + Cells[i, j, 2, 0] == player * 3 ) { wins++; } else if ( Cells[i, j, 0, 0] + Cells[i, j, 0, 1] + Cells[i, j, 0, 2] == -1 * player * 3 || Cells[i, j, 1, 0] + Cells[i, j, 1, 1] + Cells[i, j, 1, 2] == -1 * player * 3 || Cells[i, j, 2, 0] + Cells[i, j, 2, 1] + Cells[i, j, 2, 2] == -1 * player * 3 || Cells[i, j, 0, 0] + Cells[i, j, 1, 0] + Cells[i, j, 2, 0] == -1 * player * 3 || Cells[i, j, 0, 1] + Cells[i, j, 1, 1] + Cells[i, j, 2, 1] == -1 * player * 3 || Cells[i, j, 0, 2] + Cells[i, j, 1, 2] + Cells[i, j, 2, 2] == -1 * player * 3 || Cells[i, j, 0, 0] + Cells[i, j, 1, 1] + Cells[i, j, 2, 2] == -1 * player * 3 || Cells[i, j, 0, 2] + Cells[i, j, 1, 1] + Cells[i, j, 2, 0] == -1 * player * 3 ) { loses++; } } } return((wins - loses) / 9); // instead retun a franction between -1 and 1 based on finished boards } FindAvailableMoves(Cells, Bc, Br, availableBc, availableBr, availableCc, availableCr); if (availableBc.Count == 0) { return(0); // instead retun a franction between -1 and 1 based on finished boards } float bestScore = -10; int bestAge = 0; for (int i = 0; i < availableBc.Count; i++) { int localAge = age; float score = -10; //int[,,,] cells = new int[3, 3, 3, 3]; GameEngine localEngine = new GameEngine(); localEngine.NextPlayer = player; int cc, cr; Array.Copy(Cells, localEngine.Cells, Cells.Length); // do not call the next line for a less smart AI localEngine.recalculateBoards(); MoveState res = localEngine.PlayMove(player, availableBc[i], availableBr[i], availableCc[i], availableCr[i]); localAge++; if (res == MoveState.SUCCESS_BOARD_WON_GAME_WON || res == MoveState.SUCCESS_BOARD_DRAW_GAME_WON) { score = 1; } else if (res == MoveState.SUCCESS_BOARD_WON_GAME_LOST || res == MoveState.SUCCESS_BOARD_DRAW_GAME_LOST) { score = -1; } else if (!localEngine.IsMoveSuccess(res)) { break; } else { score = -1 * PlayBestGlobalMove(localEngine.Cells, -1 * player, ref localEngine.NextBoardCol, ref localEngine.NextBoardRow, out cc, out cr, ref localAge, maxAge); } if (score > bestScore || (bestScore != 1 && score == bestScore && localAge >= bestAge) || (bestScore == 1 && score == bestScore && localAge <= bestAge)) { if (localAge == bestAge && score == bestScore) { if (new Random().Next() % 2 == 0) { bestScore = score; Bc = availableBc[i]; Br = availableBr[i]; Cc = availableCc[i]; Cr = availableCr[i]; bestAge = localAge; } } else { bestScore = score; Bc = availableBc[i]; Br = availableBr[i]; Cc = availableCc[i]; Cr = availableCr[i]; bestAge = localAge; } } } age = bestAge; return(bestScore); }