| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- // ----------------------------------------------------------------
- // From Game Programming in C++ by Sanjay Madhav
- // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
- //
- // Released under the BSD License
- // See LICENSE in root directory for full details.
- // ----------------------------------------------------------------
- #include "Board.h"
- #include "Random.h"
- BoardState::BoardState()
- {
- for (int i = 0; i < 6; i++)
- {
- for (int j = 0; j < 7; j++)
- {
- mBoard[i][j] = Empty;
- }
- }
- }
- std::vector<BoardState*> BoardState::GetPossibleMoves(SquareState player) const
- {
- std::vector<BoardState*> retVal;
- // For each column, find if a move is possible
- for (int col = 0; col < 7; col++)
- {
- for (int row = 5; row >= 0; row--)
- {
- if (mBoard[row][col] == BoardState::Empty)
- {
- retVal.emplace_back(new BoardState(*this));
- retVal.back()->mBoard[row][col] = player;
- break;
- }
- }
- }
- return retVal;
- }
- bool BoardState::IsTerminal() const
- {
- // Is the board full?
- if (IsFull())
- {
- return true;
- }
- // Is there a four-in-a-row?
- int fourInRow = GetFourInARow();
- if (fourInRow != 0)
- {
- return true;
- }
- return false;
- }
- float BoardState::GetScore() const
- {
- // If the board is full, the score is 0
- if (IsFull())
- {
- return 0.0f;
- }
- // Is there a four-in-a-row?
- int fourInRow = GetFourInARow();
- if (fourInRow != 0)
- {
- return static_cast<float>(fourInRow);
- }
- return CalculateHeuristic();
- }
- bool BoardState::IsFull() const
- {
- bool isFull = true;
- for (int i = 0; i < 6; i++)
- {
- for (int j = 0; j < 7; j++)
- {
- if (mBoard[i][j] == Empty)
- {
- isFull = false;
- }
- }
- }
- return isFull;
- }
- int BoardState::GetFourInARow() const
- {
- // Returns -1 if yellow wins, 1 if red wins, 0 otherwise
- // Check if there's a row with four in a row
- for (int row = 0; row < 6; row++)
- {
- for (int col = 0; col < 4; col++)
- {
- if (mBoard[row][col] == mBoard[row][col + 1] &&
- mBoard[row][col] == mBoard[row][col + 2] &&
- mBoard[row][col] == mBoard[row][col + 3])
- {
- if (mBoard[row][col] == BoardState::Yellow)
- {
- return -1;
- }
- else if (mBoard[row][col] == BoardState::Red)
- {
- return 1;
- }
- }
- }
- }
- // Check if there's a column with four in a row
- for (int col = 0; col < 7; col++)
- {
- for (int row = 0; row < 3; row++)
- {
- if (mBoard[row][col] == mBoard[row + 1][col] &&
- mBoard[row][col] == mBoard[row + 2][col] &&
- mBoard[row][col] == mBoard[row + 3][col])
- {
- if (mBoard[row][col] == BoardState::Yellow)
- {
- return -1;
- }
- else if (mBoard[row][col] == BoardState::Red)
- {
- return 1;
- }
- }
- }
- }
- // Check if there's a right diagonal four in a row
- for (int col = 0; col < 4; col++)
- {
- for (int row = 0; row < 3; row++)
- {
- if (mBoard[row][col] == mBoard[row + 1][col + 1] &&
- mBoard[row][col] == mBoard[row + 2][col + 2] &&
- mBoard[row][col] == mBoard[row + 3][col + 3])
- {
- if (mBoard[row][col] == BoardState::Yellow)
- {
- return -1;
- }
- else if (mBoard[row][col] == BoardState::Red)
- {
- return 1;
- }
- }
- }
- }
- // Check if there's a left diagonal for in a row
- for (int col = 0; col < 4; col++)
- {
- for (int row = 3; row < 6; row++)
- {
- if (mBoard[row][col] == mBoard[row - 1][col + 1] &&
- mBoard[row][col] == mBoard[row - 2][col + 2] &&
- mBoard[row][col] == mBoard[row - 3][col + 3])
- {
- if (mBoard[row][col] == BoardState::Yellow)
- {
- return -1;
- }
- else if (mBoard[row][col] == BoardState::Red)
- {
- return 1;
- }
- }
- }
- }
- return 0;
- }
- float BoardState::CalculateHeuristic() const
- {
- // TODO: You could change this to calculate an actual heuristic
- return 0.0f;
- }
- bool TryPlayerMove(BoardState* state, int column)
- {
- // Find the first row in that column that's available
- // (if any)
- for (int row = 5; row >= 0; row--)
- {
- if (state->mBoard[row][column] == BoardState::Empty)
- {
- state->mBoard[row][column] = BoardState::Yellow;
- return true;
- }
- }
- return false;
- }
- void CPUMove(BoardState* state)
- {
- // For now, this just randomly picks one of the possible moves
- std::vector<BoardState*> moves = state->GetPossibleMoves(BoardState::Red);
- int index = Random::GetIntRange(0, moves.size() - 1);
- *state = *moves[index];
- // Clear up memory from possible moves
- for (auto state : moves)
- {
- delete state;
- }
- }
|