// Team member 1 // Name: Sandipsinh Rathod // Email: sdr5549@psu.edu // Team member 2 // Name: Sapan Shah // Email: scs6041@psu.edu // // Program homework 5 // Class: CMPSC 330 // Current Date: 6/12/24 9:15 PM // Due Date: 6/12/24 11:59 PM #include "ss.h" extern "C" IPlayer *PlayerFactory() { return new StrategicPlayer1(); } using namespace std; string StrategicPlayer1::PlayerInfo() { return "Sandipsinh Rathod (sdr5549@psu.edu), Sapan Shah (scs6041@psu.edu)"; } 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; } void StrategicPlayer1::EventAddBox(char box, const Loc &loc) { board(loc) = box; } Loc StrategicPlayer1::SelectLineLocation() { vector empty_lines; ListEmptyLines(empty_lines); // Step 1: Look for a move to complete a box Loc move = FindBoxCompletingMove(); if (move.row != -1) { return move; } // Step 2: Force opponent into bad moves move = ForceOpponentMistake(empty_lines); if (move.row != -1) { return move; } // Step 3: Fall back to the optimal move return FindOptimalMove(); } StrategicPlayer1::~StrategicPlayer1() { Close(); } Loc StrategicPlayer1::FindBoxCompletingMove() { vector empty_lines; ListEmptyLines(empty_lines); for (const Loc &loc: empty_lines) { int row = loc.row, col = loc.col; if (DoesMoveCompleteBox(row, col)) { return loc; } } return Loc(-1, -1); } bool StrategicPlayer1::DoesMoveCompleteBox(int row, int col) { if (!(row & 1) && col & 1) { return (CountBoxLines(row - 1, col) == 3 || CountBoxLines(row + 1, col) == 3); } else if (row & 1 && !(col & 1)) { return (CountBoxLines(row, col - 1) == 3 || CountBoxLines(row, col + 1) == 3); } return false; } Loc StrategicPlayer1::ForceOpponentMistake(const vector &empty_lines) { Loc best_move(-1, -1); for (const Loc &loc: empty_lines) { if (!DoesMoveCreateChain(loc.row, loc.col)) { return loc; } } return best_move; } 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; } bool StrategicPlayer1::DoesMoveCreateChain(int row, int col) { board(row, col) = name; bool creates_chain = false; if (!(row & 1) && col & 1) { if (CountBoxLines(row - 1, col) == 2 || CountBoxLines(row + 1, col) == 2) { creates_chain = true; } } else if (row & 1 && !(col & 1)) { if (CountBoxLines(row, col - 1) == 2 || CountBoxLines(row, col + 1) == 2) { creates_chain = true; } } board(row, col) = ' '; return creates_chain; } int StrategicPlayer1::EvaluateMoveCost(int row, int col) { int cost = 0; if (!(row & 1) && col & 1) { // Horizontal line cost += CountBoxLines(row - 1, col); cost += CountBoxLines(row + 1, col); } else if (row & 1 && !(col & 1)) { // Vertical line cost += CountBoxLines(row, col - 1); cost += CountBoxLines(row, col + 1); } return cost; } int StrategicPlayer1::CountBoxLines(int row, int col) { if (row < 0 || row >= board.GetRows() || col < 0 || col >= board.GetCols()) { return 0; } int count = 0; 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); } } } }