I was wondering if someone could review my object oriented design for my Noughts & Crosses program. Yesterday I posted a procedural version and now I've done an OOP version.
Can someone tell me what I've done well, what I haven't done well, and provide any suggestions on how I can improve this program? I included inheritance to practice with dynamic polymorphism. I haven't done error checking so treat my program how it's supposed to be entered.
#include <iostream>
#include <vector>
#include <map>
#include <utility>
#include <algorithm>
bool ClaimSquare(std::vector<std::map<int, unsigned char>>& grid, int move, const unsigned char player)
{
for (auto& vec : grid)
{
auto validSquare = std::find_if(vec.begin(), vec.end(), [&](auto pair) {
return pair.first == move;
});
if (validSquare != vec.end())
{
if (validSquare->second == '-')
{
validSquare->second = player;
return true;
}
else
{
std::cout << "This square has already been claimed. Choose a different square!" << std::endl;
return false;
}
}
}
}
void Displaygrid(const std::vector<std::map<int, unsigned char>>& grid)
{
for (auto const& row : grid)
{
for (auto const& cell : row)
{
if (cell.second != '-') {
std::cout << cell.second << " ";
}
else
{
std::cout << cell.first << " ";
}
}
std::cout << "\n\n";
}
}
class Player
{
private:
protected:
std::string m_type;
unsigned char m_name;
public:
std::string GetType() { return m_type; }
Player(unsigned char name, std::string&& type = "Player") :m_name(name),m_type(type) {}
virtual ~Player() = default;
virtual unsigned char GetName() { return m_name; }
};
class Human : public Player
{
public:
Human(unsigned char name) :Player(name, "Human") {}
std::string GetType() { return m_type; }
};
class Robot : public Player
{
public:
Robot(unsigned char name) :Player(name, "Robot"){}
std::string GetType() { return m_type; }
};
class Game
{
private:
std::vector<Player*> m_p;
public:
Game(Player *p1, Player*p2)
{
m_p.push_back(p1);
m_p.push_back(p2);
}
//Does anyone know if there's a better way of checking for winner?
bool CheckForAWinner(std::vector<std::map<int, unsigned char>>& m_board, const unsigned char key)
{
if (m_board.at(0).at(1) == key && m_board.at(0).at(2) == key && m_board.at(0).at(3) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(1).at(4) == key && m_board.at(1).at(5) == key && m_board.at(1).at(6) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(2).at(7) == key && m_board.at(2).at(8) == key && m_board.at(2).at(9) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(0).at(1) == key && m_board.at(1).at(4) == key && m_board.at(2).at(7) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(0).at(2) == key && m_board.at(1).at(5) == key && m_board.at(2).at(8) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(0).at(3) == key && m_board.at(1).at(6) == key && m_board.at(2).at(9) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(0).at(1) == key && m_board.at(1).at(5) == key && m_board.at(2).at(9) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else if (m_board.at(2).at(7) == key && m_board.at(1).at(5) == key && m_board.at(0).at(3) == key) {
std::cout << key << " is the winner" << std::endl;
return true;
}
else
{
return false;
}
}
void play(std::vector<std::map<int, unsigned char>> &board)
{
int currentPlayer = 1;
Player *ref = nullptr;
do
{
int move = 0;
currentPlayer = (currentPlayer + 1) % 2;
do
{
Displaygrid(board);
std::cout << m_p.at(currentPlayer)->GetType() << ": " << m_p.at(currentPlayer)->GetName() << " turn: " << std::endl;
std::cout << "Enter a number on the grid (e.g. 1): ";
std::cin >> move;
}
while (ClaimSquare(board, move, m_p.at(currentPlayer)->GetName()) == false);
}
while (CheckForAWinner(board,m_p.at(currentPlayer)->GetName()) == false);
}
};
int main() {
std::vector<std::map<int, unsigned char>>grid =
{
{std::make_pair(1, '-'), std::make_pair(2, '-'), std::make_pair(3, '-') },
{ std::make_pair(4,'-'), std::make_pair(5,'-'), std::make_pair(6,'-') },
{ std::make_pair(7,'-'), std::make_pair(8,'-'), std::make_pair(9,'-') }
};
Player *player = new Human('O');
Player *player2 = new Robot('X');
Player* robot = new Robot('O');
Player* robot2 = new Robot('X');
//Game 1: Human vs Human
Game HumanVsHuman(player, player2);
HumanVsHuman.play(grid);
//The robot doesn't work yet. Just treat it as a human. Point is to demonstrate polymorphisim.
Game RobotvsHumanGame(robot, robot2);
RobotvsHumanGame.play(grid);
//deleting memory used
delete player;
delete player2;
//deleting memory used
delete robot;
delete robot2;
}