#include #include #include "strategic_player1.h" #include "common.h" extern "C" IPlayer* PlayerFactory() { return new StrategicPlayer1(); } using namespace std; string StrategicPlayer1::PlayerInfo() { return "Big MAN Smol PP"; } void StrategicPlayer1::Init(int board_rows, int board_cols, char box_type, char line_type) { this->box_name = box_type; this->name = line_type; int blank_line_count = 0; board.AllocateBoard(board_rows, board_cols, blank_line_count); } void StrategicPlayer1::Close() { board.FreeBoard(); } void StrategicPlayer1::EventAddLine(char bar, const Loc& loc) { board(loc) = bar; // Update the board with the added line } void StrategicPlayer1::EventAddBox(char box, const Loc& loc) { board(loc) = box; // Update the board with the assigned box } Loc StrategicPlayer1::SelectLineLocation() { Loc box_completing_move = FindBoxCompletingMove(); if (box_completing_move.row != -1 && box_completing_move.col != -1) { return box_completing_move; // Prioritize moves that complete a box } return FindOptimalMove(); // Fall back to a heuristic-based optimal move } StrategicPlayer1::~StrategicPlayer1() { Close(); } // Private helper functions Loc StrategicPlayer1::FindBoxCompletingMove() { vector empty_lines; ListEmptyLines(empty_lines); for (const Loc& loc : empty_lines) { int row = loc.row, col = loc.col; // Check if adding a line at this location completes a box if ((row % 2 == 0 && col % 2 == 1) || (row % 2 == 1 && col % 2 == 0)) { if (DoesMoveCompleteBox(row, col)) { return loc; // Return the first box-completing move found } } } return Loc(-1, -1); // No box-completing move found } bool StrategicPlayer1::DoesMoveCompleteBox(int row, int col) { // Check adjacent boxes based on the move's orientation if (row % 2 == 0 && col % 2 == 1) { // Horizontal line return (CountBoxLines(row - 1, col) == 3 || CountBoxLines(row + 1, col) == 3); } else if (row % 2 == 1 && col % 2 == 0) { // Vertical line return (CountBoxLines(row, col - 1) == 3 || CountBoxLines(row, col + 1) == 3); } return false; } Loc StrategicPlayer1::FindOptimalMove() { vector empty_lines; ListEmptyLines(empty_lines); int min_cost = numeric_limits::max(); Loc best_move(-1, -1); for (const Loc& loc : empty_lines) { int cost = EvaluateMoveCost(loc.row, loc.col); if (cost < min_cost) { min_cost = cost; best_move = loc; } } return best_move; } int StrategicPlayer1::EvaluateMoveCost(int row, int col) { int cost = 0; // Evaluate the "cost" of the move by summing the number of sides completed for adjacent boxes if (row % 2 == 0 && col % 2 == 1) { // Horizontal line cost += CountBoxLines(row - 1, col); cost += CountBoxLines(row + 1, col); } else if (row % 2 == 1 && col % 2 == 0) { // Vertical line cost += CountBoxLines(row, col - 1); cost += CountBoxLines(row, col + 1); } return cost; } int StrategicPlayer1::CountBoxLines(int row, int col) { // Ensure the location is within bounds if (row < 0 || row >= board.GetRows() || col < 0 || col >= board.GetCols()) { return 0; } int count = 0; // Check all four sides of the box if (board(row - 1, col) != ' ') count++; // Top if (board(row + 1, col) != ' ') count++; // Bottom if (board(row, col - 1) != ' ') count++; // Left if (board(row, col + 1) != ' ') count++; // Right return count; } void StrategicPlayer1::ListEmptyLines(vector& empty_lines) { for (int r = 0; r < board.GetRows(); r++) { for (int c = 0; c < board.GetCols(); c++) { Loc loc(r, c); if (loc.IsLineLocation() && board(r, c) == ' ') { empty_lines.push_back(loc); // Add all empty line locations to the list } } } }