2024-12-07 02:24:11 +00:00
|
|
|
// 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"
|
2024-12-07 00:04:43 +00:00
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
extern "C" IPlayer *PlayerFactory() {
|
2024-12-07 00:04:43 +00:00
|
|
|
return new StrategicPlayer1();
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
string StrategicPlayer1::PlayerInfo() {
|
2024-12-07 01:40:19 +00:00
|
|
|
return "Sandipsinh Rathod (sdr5549@psu.edu), Sapan Shah (scs6041@psu.edu)";
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
void StrategicPlayer1::EventAddLine(char bar, const Loc &loc) {
|
2024-12-07 01:52:13 +00:00
|
|
|
board(loc) = bar;
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
void StrategicPlayer1::EventAddBox(char box, const Loc &loc) {
|
2024-12-07 01:52:13 +00:00
|
|
|
board(loc) = box;
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Loc StrategicPlayer1::SelectLineLocation() {
|
2024-12-07 01:40:19 +00:00
|
|
|
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;
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
// Step 3: Fall back to the optimal move
|
|
|
|
return FindOptimalMove();
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StrategicPlayer1::~StrategicPlayer1() {
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
Loc StrategicPlayer1::FindBoxCompletingMove() {
|
|
|
|
vector<Loc> empty_lines;
|
|
|
|
ListEmptyLines(empty_lines);
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
for (const Loc &loc: empty_lines) {
|
2024-12-07 00:04:43 +00:00
|
|
|
int row = loc.row, col = loc.col;
|
2024-12-07 01:40:19 +00:00
|
|
|
if (DoesMoveCompleteBox(row, col)) {
|
|
|
|
return loc;
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
return Loc(-1, -1);
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool StrategicPlayer1::DoesMoveCompleteBox(int row, int col) {
|
2024-12-07 01:52:13 +00:00
|
|
|
if (!(row & 1) && col & 1) {
|
2024-12-07 00:04:43 +00:00
|
|
|
return (CountBoxLines(row - 1, col) == 3 || CountBoxLines(row + 1, col) == 3);
|
2024-12-07 01:52:13 +00:00
|
|
|
} else if (row & 1 && !(col & 1)) {
|
2024-12-07 00:04:43 +00:00
|
|
|
return (CountBoxLines(row, col - 1) == 3 || CountBoxLines(row, col + 1) == 3);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
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)) {
|
2024-12-07 01:52:13 +00:00
|
|
|
return loc;
|
2024-12-07 01:40:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best_move;
|
|
|
|
}
|
|
|
|
|
2024-12-07 00:04:43 +00:00
|
|
|
Loc StrategicPlayer1::FindOptimalMove() {
|
|
|
|
vector<Loc> empty_lines;
|
|
|
|
ListEmptyLines(empty_lines);
|
|
|
|
|
|
|
|
int min_cost = numeric_limits<int>::max();
|
|
|
|
Loc best_move(-1, -1);
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
for (const Loc &loc: empty_lines) {
|
2024-12-07 00:04:43 +00:00
|
|
|
int cost = EvaluateMoveCost(loc.row, loc.col);
|
|
|
|
if (cost < min_cost) {
|
|
|
|
min_cost = cost;
|
|
|
|
best_move = loc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best_move;
|
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
bool StrategicPlayer1::DoesMoveCreateChain(int row, int col) {
|
|
|
|
board(row, col) = name;
|
|
|
|
|
|
|
|
bool creates_chain = false;
|
|
|
|
|
2024-12-07 01:52:13 +00:00
|
|
|
if (!(row & 1) && col & 1) {
|
2024-12-07 01:40:19 +00:00
|
|
|
if (CountBoxLines(row - 1, col) == 2 || CountBoxLines(row + 1, col) == 2) {
|
|
|
|
creates_chain = true;
|
|
|
|
}
|
2024-12-07 01:52:13 +00:00
|
|
|
} else if (row & 1 && !(col & 1)) {
|
2024-12-07 01:40:19 +00:00
|
|
|
if (CountBoxLines(row, col - 1) == 2 || CountBoxLines(row, col + 1) == 2) {
|
|
|
|
creates_chain = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
board(row, col) = ' ';
|
|
|
|
return creates_chain;
|
|
|
|
}
|
|
|
|
|
2024-12-07 00:04:43 +00:00
|
|
|
int StrategicPlayer1::EvaluateMoveCost(int row, int col) {
|
|
|
|
int cost = 0;
|
|
|
|
|
2024-12-07 01:52:13 +00:00
|
|
|
if (!(row & 1) && col & 1) { // Horizontal line
|
2024-12-07 00:04:43 +00:00
|
|
|
cost += CountBoxLines(row - 1, col);
|
|
|
|
cost += CountBoxLines(row + 1, col);
|
2024-12-07 01:52:13 +00:00
|
|
|
} else if (row & 1 && !(col & 1)) { // Vertical line
|
2024-12-07 00:04:43 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-12-07 01:40:19 +00:00
|
|
|
void StrategicPlayer1::ListEmptyLines(vector<Loc> &empty_lines) {
|
2024-12-07 00:04:43 +00:00
|
|
|
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) == ' ') {
|
2024-12-07 01:40:19 +00:00
|
|
|
empty_lines.push_back(loc);
|
2024-12-07 00:04:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|