cmpsc330hw5/strategic_player1.cxx
Sandipsinh Rathod 3ecbd34211
tmp: add harshit
2024-12-06 20:52:13 -05:00

167 lines
4.1 KiB
C++

#include "strategic_player1.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<Loc> 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<Loc> 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<Loc> &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<Loc> empty_lines;
ListEmptyLines(empty_lines);
int min_cost = numeric_limits<int>::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<Loc> &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);
}
}
}
}