moveBoard.CS
unknown
csharp
2 years ago
11 kB
15
Indexable
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using static GameBoard;
//
// This class is created as a "scratch pad" for the AI. Before deciding its next move, the AI will make a copy of the current board on to
// its move board. This class has functions to determine the possible moves, based on one move on the board, and it can evaluate each move (to use with minimax)
//
// SEARCH For TODO s for hints on where you complete you code...
public class moveBoard {
#region Properties
public GameBoard.PLAYERS_ID MaximizingPlayer // Keeps track of which player is maximizing (i.e. AI)
{
get
{
return maximizingPlayer;
}
set
{
maximizingPlayer = value;
}
}
public Move Root // the root node of the game tree (very first move, depth = 0 for top of tree, the PossibleMoves for the root node will contain all possible moves for an empty game board).
{
get
{
return rootMove;
}
set
{
rootMove = value;
}
}
#endregion
#region Private Data Members
private const int NO_SCORE = 0; //TODO: Determine the values for the evaluate function
private const int WIN_SCORE = 1000;
private const int LOSE_SCORE = -1000;
private const int TIE_SCORE = 0;
private Move rootMove;
private GameBoard.PLAYERS_ID maximizingPlayer; // This is the AI player
private bool isMoveGameFinished;
#endregion
#region Public Members
public Move[,] gameMoveBoard;
//Constructor for the moveBoard
public moveBoard()
{
rootMove = new Move(-1, -1);
gameMoveBoard = new Move[GameBoard.MAX_ROWS, GameBoard.MAX_COLUMNS];
InitMoveBoard();
}
// Adds the "nextMove" for "nextMovePlayer" to the move board. TODO: use this in the minimax function to test a move on the board
public void makeMove( Move nextMove, GameBoard.PLAYERS_ID nextMovePlayer )
{
// Add move to our scratch pad game board.
AddMovetoGameMoveBoard(nextMove,nextMovePlayer);
nextMove.SetOccupied(nextMovePlayer);
// After the nextMove is made then create a list of children with the remaining possible moves.
AddPossibleMovesForNextMove(nextMove);
}
// Clears the "nextMove" from the gameMoveBoard. TODO: use this in the minimax function to remove the move from the board so another move can be tested.
public void RemoveMoveFromGameMoveBoard(Move nextMove)
{
//clear the board with the move by the currentplayer
gameMoveBoard[nextMove.Row, nextMove.Column].ClearOccupied();
}
//Initializes the move board ( this is the scratch pad for the AI )
public void InitMoveBoard()
{
rootMove.ClearChildrenList();
isMoveGameFinished = false;
maximizingPlayer = GameBoard.PLAYERS_ID.PLAYER_NONE;
for (int i = 0; i < GameBoard.MAX_ROWS; i++)
{
for(int j = 0; j < GameBoard.MAX_COLUMNS; j++)
{
gameMoveBoard[i,j] = new Move(i,j); //Inits move for scratch pad gameMoveBoard
gameMoveBoard[i,j].Score = 0;
}
}
}
// Copies the actual game board to the scratch pad (gameMoveBoard) so AI can look ahead.
public void SetCurrentGameBoardToMoveBoard(GameBoard.PLAYERS_ID initPlayer)
{
for (int i = 0; i < GameBoard.MAX_ROWS; i++)
{
for(int j = 0; j < GameBoard.MAX_COLUMNS; j++)
{
gameMoveBoard[i,j].Occupied = GameBoard.gameBoard[i,j].Occupied;
gameMoveBoard[i,j].PlayerID = GameBoard.gameBoard[i,j].PlayerID;
}
}
// Set up the root node to match the current game board.
MaximizingPlayer = initPlayer;
rootMove.PlayerID = initPlayer;
rootMove.Score = NO_SCORE;
AddPossibleMovesForNextMove(rootMove);
}
public int EvalBoardForAI()
{
int boardScore = TIE_SCORE;
//
// TODO: Complete this function with your OWN code.
// Determine if there is a win, loss or tie and return appropriate score
// If not a win loss or tie, evaluate the board based on your OWN strategy (how do you play the game?)
// and return score accordingly
//
if (CheckForWinner(PLAYERS_ID.PLAYER_ONE))
{
boardScore = LOSE_SCORE;
}
if(CheckForWinner(PLAYERS_ID.PLAYER_TWO))
{
boardScore = WIN_SCORE;
}
return boardScore;
}
public bool IsGameOver()
{
isMoveGameFinished = false;
// CheckForWinner(PLAYERS_ID.PLAYER_ONE);
// CheckForWinner(PLAYERS_ID.PLAYER_TWO);
//TODO: Determing when the game is over on the AI board (scratch board) gameMoveBoard, will need for MiniMax function in gameboard.cs
// Will need to use functions that check if there is a win, loss or tie (see TODO CHECK functions at end of file), if there is a win/loss or tie return true
if(CheckForWinner(PLAYERS_ID.PLAYER_ONE))
{
isMoveGameFinished = true;
}
else if (CheckForWinner(PLAYERS_ID.PLAYER_TWO))
{
isMoveGameFinished = true;
}
if(isMoveGameFinished == false)
{
isMoveGameFinished = CheckForTie();
}
return isMoveGameFinished;
}
public bool CheckForTie()
{
bool gameTied = true;
//Assumes that there is not a win on the board (assumes other function checks for win).
//If there is not a win or loss on the board and the there are no unoccupied spots then there is a tie.
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (!gameMoveBoard[i,j].Occupied)
{
gameTied = false;
}
}
}
return gameTied;
}
public bool CheckForWinner(PLAYERS_ID IDtoPASS)
{
bool rowsWin = false;
bool columnsWin = false;
bool diagonalWin = false;
int count = 0;
if (WinConditions(rowsWin, columnsWin, diagonalWin) == false)
{
for (int r = 0; r < MAX_ROWS; r++)
{
count = 0;
for (int c = 0; c < MAX_COLUMNS; c++)
{
PLAYERS_ID playerTurnID = gameMoveBoard[r, c].PlayerID;
if (playerTurnID == IDtoPASS)
{
count++;
}
if (count == CONNECT_NUM)
{
rowsWin = true;
break;
}
}
if (rowsWin == true) { break; }
}
} //Check Rows
if(WinConditions(rowsWin, columnsWin, diagonalWin) == false)
{
{
for (int c = 0; c < MAX_COLUMNS; c++)
{
count = 0;
for (int r = 0; r < MAX_ROWS; r++)
{
PLAYERS_ID playerTurnID = gameMoveBoard[r,c].PlayerID;
if(playerTurnID == IDtoPASS)
{
count++;
if (count == CONNECT_NUM){ columnsWin = true; break;}
}
}
if (count == CONNECT_NUM)
{
break;
}
}
}
} //Check Columns
if(WinConditions(rowsWin, columnsWin,diagonalWin) == false)
{
count = 0;
for (int r = 0; r < MAX_ROWS; r++)
{
for (int c = 0;c < MAX_COLUMNS; c++)
{
PLAYERS_ID playerTurnID = gameMoveBoard[c, r].PlayerID;
if(playerTurnID == IDtoPASS && r == c)
{
count++;
if (count == CONNECT_NUM)
{
diagonalWin = true;
break;
}
}
}
if (diagonalWin == true)
{
break;
}
}
count = 0;
for (int r = MAX_ROWS - 1; r > 0; r--)
{
count = 0;
for (int c = 0; c < MAX_COLUMNS; c++)
{
PLAYERS_ID playerTurnID = gameMoveBoard[c, r].PlayerID;
if (playerTurnID == IDtoPASS)
{
count++;
if (count == CONNECT_NUM)
{
diagonalWin = true;
break;
}
}
if (diagonalWin == true)
{
break;
}
}
}
} //Check Diagonals
if(rowsWin || columnsWin || diagonalWin)
{
return true;
}
else
{
return false;
}
}
public bool WinConditions(bool rowsWin, bool columnsWin, bool diagonalWin)
{
if (rowsWin == true || columnsWin == true || diagonalWin == true)
{
return true;
}
else
{
return false;
}
} //Check if any win has occurred.
#endregion
#region Private Functions
// Goes through the entire board and sets all the possible moves for "nextMove".
private void AddPossibleMovesForNextMove(Move nextMove)
{
for (int i = 0; i < GameBoard.MAX_ROWS; i++)
{
for (int j = 0; j < GameBoard.MAX_COLUMNS; j++)
{
if (!gameMoveBoard[i, j].Occupied)
{
Move posMove = new Move();
gameMoveBoard[i, j].Copy(posMove);
nextMove.PossibleMoves.Add(posMove);
}
}
}
}
// Directly sets the nextMovePlayer to the nextMove position on the gameMoveBoard.
private void AddMovetoGameMoveBoard(Move nextMove, GameBoard.PLAYERS_ID nextMovePlayer)
{
// Update the board with the move by the currentplayer.
gameMoveBoard[nextMove.Row, nextMove.Column].SetOccupied(nextMovePlayer);
}
#endregion
}
Editor is loading...