diff --git a/harshit/custom_player.cxx b/harshit/custom_player.cxx new file mode 100644 index 0000000..9d8eb61 --- /dev/null +++ b/harshit/custom_player.cxx @@ -0,0 +1,122 @@ +#include "custom_player.h" +#include +#include // for rand +#include // for time +using namespace std; + +// Factory function for dynamic library loading +extern "C" IPlayer* PlayerFactory() { + return new CustomPlayer(); +} + +// Constructor +CustomPlayer::CustomPlayer() { + srand(time(0)); +} + +// Destructor +CustomPlayer::~CustomPlayer() {} + +// Initializes the player with the board size and player symbols +void CustomPlayer::Init(int dots_in_rows, int dots_in_cols, char _player_box, char _player_line) { + board.AllocateBoard(dots_in_rows, dots_in_cols); + player_box = _player_box; + player_line = _player_line; + empty_lines = new Loc[board.GetRows() * board.GetCols()]; +} + +// Cleans up dynamically allocated memory +void CustomPlayer::Close() { + board.FreeBoard(); + delete[] empty_lines; +} + +// Returns the player info +std::string CustomPlayer::PlayerInfo() { + return "Custom Strategic Player"; +} + +// Updates the board when a line is added +void CustomPlayer::EventAddLine(char bar, const Loc& loc) { + board(loc) = bar; +} + +// Updates the board when a box is completed +void CustomPlayer::EventAddBox(char box, const Loc& loc) { + board(loc) = box; +} + +// Updates the list of available line locations +void CustomPlayer::ListEmptyLines() { + empty_lines_count = 0; + for (int r = 0; r < board.GetRows(); r++) { + for (int c = 0; c < board.GetCols(); c++) { + if (board(r, c) == ' ' && Loc(r, c).IsLineLocation()) { + empty_lines[empty_lines_count++] = Loc(r, c); + } + } + } +} + +// Helper function to check if a line completes a box +bool CustomPlayer::DoesLineCompleteBox(const Loc& loc) { + if (loc.IsLineHorizontalLocation()) { + if (loc.row > 0 && board(loc.row - 1, loc.col) != ' ' && + board(loc.row - 1, loc.col - 1) != ' ' && board(loc.row - 1, loc.col + 1) != ' ') + return true; + if (loc.row < board.GetRows() - 1 && board(loc.row + 1, loc.col) != ' ' && + board(loc.row + 1, loc.col - 1) != ' ' && board(loc.row + 1, loc.col + 1) != ' ') + return true; + } else if (loc.IsLineVerticalLocation()) { + if (loc.col > 0 && board(loc.row, loc.col - 1) != ' ' && + board(loc.row - 1, loc.col - 1) != ' ' && board(loc.row + 1, loc.col - 1) != ' ') + return true; + if (loc.col < board.GetCols() - 1 && board(loc.row, loc.col + 1) != ' ' && + board(loc.row - 1, loc.col + 1) != ' ' && board(loc.row + 1, loc.col + 1) != ' ') + return true; + } + return false; +} + +// Helper function to avoid giving the opponent a chance to complete a box +bool CustomPlayer::WouldGiveOpponentBox(const Loc& loc) { + // Temporarily add the line to the board + board(loc) = player_line; + + // Check if the opponent can complete a box in the next move + for (int r = 0; r < board.GetRows(); r++) { + for (int c = 0; c < board.GetCols(); c++) { + if (board(r, c) == ' ' && Loc(r, c).IsLineLocation() && + DoesLineCompleteBox(Loc(r, c))) { + board(loc) = ' '; // Revert the move + return true; + } + } + } + + // Revert the move + board(loc) = ' '; + return false; +} + +// Determines the next move +Loc CustomPlayer::SelectLineLocation() { + ListEmptyLines(); + + // Strategy: Prioritize moves that complete a box + for (int i = 0; i < empty_lines_count; i++) { + if (DoesLineCompleteBox(empty_lines[i])) { + return empty_lines[i]; + } + } + + // Avoid moves that give the opponent a chance to complete a box + for (int i = 0; i < empty_lines_count; i++) { + if (!WouldGiveOpponentBox(empty_lines[i])) { + return empty_lines[i]; + } + } + + // Otherwise, pick a random move + return empty_lines[rand() % empty_lines_count]; +} \ No newline at end of file diff --git a/harshit/custom_player.h b/harshit/custom_player.h new file mode 100644 index 0000000..f617333 --- /dev/null +++ b/harshit/custom_player.h @@ -0,0 +1,54 @@ +#ifndef __CUSTOM_PLAYER__ +#define __CUSTOM_PLAYER__ + +#include "player.h" +#include "common.h" +#include "board.h" +#include +#include + +class CustomPlayer : public IPlayer { +private: + Board board; // Game board to track state + char player_box; // Character representing the player's boxes + char player_line; // Character representing the player's lines + Loc* empty_lines; // Array to store available line locations + int empty_lines_count; // Number of available line locations + +public: + CustomPlayer(); + ~CustomPlayer(); + + // Initializes the player with board details and player symbols + void Init(int dots_in_rows, int dots_in_cols, char player_box, char player_line) override; + + // Cleans up dynamically allocated memory + void Close() override; + + // Returns the player information + std::string PlayerInfo() override; + + // Called when a line is added to the board + void EventAddLine(char bar, const Loc& loc) override; + + // Called when a box is completed on the board + void EventAddBox(char box, const Loc& loc) override; + + // Determines the next move based on the current state of the board + Loc SelectLineLocation() override; + +private: + // Updates the list of available line locations + void ListEmptyLines(); + + // Helper function to check if a line completes a box + bool DoesLineCompleteBox(const Loc& loc); + + // Helper function to avoid giving the opponent a chance to complete a box + bool WouldGiveOpponentBox(const Loc& loc); + + // Evaluate the best line location strategically + Loc GetBestStrategicMove(); +}; + +#endif \ No newline at end of file diff --git a/strategic_player1.cxx b/strategic_player1.cxx index ba6573d..79bc139 100644 --- a/strategic_player1.cxx +++ b/strategic_player1.cxx @@ -23,11 +23,11 @@ void StrategicPlayer1::Close() { } void StrategicPlayer1::EventAddLine(char bar, const Loc &loc) { - board(loc) = bar; // Update the board with the added line + board(loc) = bar; } void StrategicPlayer1::EventAddBox(char box, const Loc &loc) { - board(loc) = box; // Update the board with the assigned box + board(loc) = box; } Loc StrategicPlayer1::SelectLineLocation() { @@ -69,9 +69,9 @@ Loc StrategicPlayer1::FindBoxCompletingMove() { } bool StrategicPlayer1::DoesMoveCompleteBox(int row, int col) { - if (row % 2 == 0 && col % 2 == 1) { // Horizontal line + if (!(row & 1) && col & 1) { return (CountBoxLines(row - 1, col) == 3 || CountBoxLines(row + 1, col) == 3); - } else if (row % 2 == 1 && col % 2 == 0) { // Vertical line + } else if (row & 1 && !(col & 1)) { return (CountBoxLines(row, col - 1) == 3 || CountBoxLines(row, col + 1) == 3); } return false; @@ -82,7 +82,7 @@ Loc StrategicPlayer1::ForceOpponentMistake(const vector &empty_lines) { for (const Loc &loc: empty_lines) { if (!DoesMoveCreateChain(loc.row, loc.col)) { - return loc; // Choose the first safe move + return loc; } } @@ -112,11 +112,11 @@ bool StrategicPlayer1::DoesMoveCreateChain(int row, int col) { bool creates_chain = false; - if (row % 2 == 0 && col % 2 == 1) { + if (!(row & 1) && col & 1) { if (CountBoxLines(row - 1, col) == 2 || CountBoxLines(row + 1, col) == 2) { creates_chain = true; } - } else if (row % 2 == 1 && col % 2 == 0) { + } else if (row & 1 && !(col & 1)) { if (CountBoxLines(row, col - 1) == 2 || CountBoxLines(row, col + 1) == 2) { creates_chain = true; } @@ -129,10 +129,10 @@ bool StrategicPlayer1::DoesMoveCreateChain(int row, int col) { int StrategicPlayer1::EvaluateMoveCost(int row, int col) { int cost = 0; - if (row % 2 == 0 && col % 2 == 1) { // Horizontal line + if (!(row & 1) && col & 1) { // Horizontal line cost += CountBoxLines(row - 1, col); cost += CountBoxLines(row + 1, col); - } else if (row % 2 == 1 && col % 2 == 0) { // Vertical line + } else if (row & 1 && !(col & 1)) { // Vertical line cost += CountBoxLines(row, col - 1); cost += CountBoxLines(row, col + 1); }