Connect Four Game

Hi everyone,

I am trying to implement Minimax with alpha-beta pruning method into my game "Connect Four" and also add scores to players and i have a hard time to finish this project. Basically i need to implement AI where computer tries to get as many points as possible. Prompt will allow you to enter characters from 'a' to 'g', which indicate the column and also you can enter '?' which gives you a hint where to put your 'O'(it is also considered AI because computer will tell you that). After your (human) turn, the machine will inspect all the possible turns by placing 'x' move to the board and select the one with the highest score. The board is reset. In the second round, the machine applies the human turn by placing 'o' move to the board in the same way and selects the best turn. This means that the machine is allowing you (human) to play in two consecutive rounds (double play). In this way, the machine can find out a devastating turn missed from its own computation of turns, in which case by preoccupying that endangered position by placing 'x' (thus not allowing to place 'o') the machine can avoid immediate lose and continue the game. This is not a deep-thinker player, and therefore the machine may easily lose. As far as scores i will give you a sample of output

a b c d e f g
| . | . | . | . | . | . | . |
| . | . | . | . | . | . | . |
| . | . | . | . | . | . | . |
| . | . | . | x | . | . | . |
| . | . | . | x | . | o | . |
| . | x | . | o | o | x | o |

Enter your turn: ?
If you chose (a) - H (0, 0), V (0, 3), L (0, 0), R (0, 3), total score 8
If you chose (b) - H (0, 2), V (0, 3), L (0, 2), R (0, 4), total score 13
If you chose (c) - H (2, 0), V (0, 3), L (0, 2), R (0, 0), total score 11
If you chose (d) - H (0, 6), V (0, 2), L (2, 3), R (0, 5), total score 72
If you chose (e) - H (1, 1), V (1, 3), L (0, 0), R (1, 2), total score 14
If you chose (f) - H (0, 2), V (1, 3), L (0, 4), R (1, 2), total score 17
If you chose (g) - H (1, 1), V (1, 3), L (0, 3), R (0, 0), total score 13

As you can see H is horizontal with the first value - player's mark and the second value - empty spaces. To calculate scores you add all spaces+2*player's marks. This is the score for all H, V, L, R. Example:
Hint will tell you where you can place your circle, if you chose (a)
(1+0)*2+(3+3)=8 where 1 is your chosen 'o'. If you chose (c) (2+1)*2+5(spaces)=11. If you got 3 'o's in H or V or R or L you will get extra 50 points. You will get 100 points if you get all 4 'o'. If you have any questions feel free to ask. Code is below what i did so far.
PS: no need to help me with the other Horizontal, Right and Left code I did it.
Just with scoring. Thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  #include <iostream>
#include <iomanip>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <cassert>
using namespace std;

struct MyGameDef { // professional way to define global enumerable values. 
  enum Player { Human, Progm, Empty }; 
  Player m_player;
  MyGameDef (const Player p) : m_player(p) {}
  operator Player() const { return m_player; }
};

class Cell {       // representing a cell of a board.
  MyGameDef::Player m_occu; // marked 'Empty', 'Human', and 'Progm'.
public:
  Cell() : m_occu(MyGameDef::Empty) {}
  void setTurn(const MyGameDef::Player p) { assert(!isOccupied()); m_occu = p; }
  bool isOccupied() const { return m_occu != MyGameDef::Empty; }
  bool isMe(const MyGameDef::Player p) const { return m_occu == p; }
  void erase() { m_occu = MyGameDef::Empty; }
  friend ostream& operator<<(ostream& o, const Cell& c) {
    char mark;
    switch(c.m_occu) {
    case MyGameDef::Empty: return o << " . ";
    case MyGameDef::Human: return o << " o ";
    case MyGameDef::Progm: return o << " x ";
    default: abort();
    }
  }
};

class Eval {
  int m_conn; // connected to me.
  int m_poss; // possible spaces.
public:
  Eval(const int c = 0, const int p = 0) : m_conn(c), m_poss(p) {}
  bool isConnect4() const { return m_conn >= 3; }
  bool isWinning()  const { return m_conn == 2 && m_poss >= 1; }
  int getValue()  const { return m_conn * 2 + m_poss; }
  friend ostream& operator<<(ostream& o, const Eval& e) {
    return o << "(" << e.m_conn << ", " << e.m_poss << ")";
  }
};  
  
class Turn {
  char m_turn;
  int  m_score;
public:
  Turn(const char c = '\0', const int s = 0) : m_turn(c), m_score(s) {}
  char getTurn() const { return m_turn; }
  int getScore() const { return m_score; }
  friend bool operator<(const Turn& lhs, const Turn& rhs) {
    return lhs.m_score < rhs.m_score;
  }
  friend ostream& operator<<(ostream& o, const Turn& t) {
    return o << "\t--> (" << t.m_turn << ") with score " << t.m_score;
  }
};

class Board {       // represents Connect Four board.
  int m_row;
  int m_col;
  const int m_max;  // used to detect tie. 
  int m_num;        // the number of the marks placed.
  vector<vector<Cell> > m_map;

  Eval horizontal(const int r, const int c, const MyGameDef::Player p) const {
    int count = 0, possible = 0;
    bool connected = true;
    for (int col = c + 1, saw = 0; col < m_col && saw < 3; ++col, ++saw) { // east direction.
      if (m_map[r][col].isMe(p)) {
	if (++count > 2) { if (connected) break; } 
	continue;
      }
      connected = false;
      if (m_map[r][col].isOccupied()) break;
      ++possible;
    }
    for (int col = c - 1, saw = 0; col >= 0 && saw < 3; --col, ++saw) { // west direction.
      if (m_map[r][col].isMe(p)) {
	if (++count > 2) { if (connected); break; }
	continue;
      }
      connected = false;
      if (m_map[r][col].isOccupied()) break;
      ++possible;
    }
    return Eval(count, possible);
  }

public:
  Board(const int r = 6, const int c = 7) :
    m_row(r), m_col(c), m_max(r * c), m_num(0) { 
    vector<Cell> arow(m_col, Cell());
    for (int i = 0; i < m_row; ++i) m_map.push_back(arow);
  }  
  bool isTie() const { return m_num >= m_max; }
  bool isValid(const char c, const MyGameDef::Player p) {
    int col = c - 'a';
    if (col < 0 || col >= m_col) return false; 
    bool placed = false;
    for (int row = m_row - 1; row >= 0; --row) {
      if (m_map[row][col].isOccupied()) continue;

      placed = true;
      ++m_num;
      m_map[row][col].setTurn(p); break;
    }
    return placed;
  }
  bool isWon(const char c, const MyGameDef::Player p) const {
    int col = c - 'a', row = 0;
    for (; row < m_row; ++row) {
      if (!m_map[row][col].isOccupied()) continue;

      assert(m_map[row][col].isMe(p)); 
      break;
    }
    Eval V = vertical(row, col, p);   // check vertical line.
    Eval H = horizontal(row, col, p); // check horizontal line.
    Eval L = leftup(row, col, p);     // check leftup diagnal line.
    Eval R = rightup(row, col, p);    // check rightup diagnal line.
    return V.isConnect4() || H.isConnect4() || L.isConnect4() || R.isConnect4();
  }
  char findBestMove(const MyGameDef::Player p, const bool show = false) {
    cout << "findBestMove function not implemented." << endl;
    return char('a' + rand() % 7); // just showing the machine move.
  }
  void erase(const char c, const MyGameDef::Player p) {
    int col = c - 'a';
    for (int row = 0; row < m_row; ++row) {
      if (!m_map[row][col].isOccupied()) continue;

      assert(m_map[row][col].isMe(p)); 
      m_map[row][col].erase(); break;
    }
    --m_num;
  }
  friend ostream& operator<<(ostream& o, const Board& m) {
    o << endl;
    for (int col = 0; col < m.m_col; ++col)
      o << setw(3) << (char)('a' + col) << ' ';
    o << endl;
    for (int row = 0; row < m.m_row; ++row) {
      o << '|';
      for (int col = 0; col < m.m_col; ++col) 
	o << setw(3) << m.m_map[row][col] << '|';
      o << endl;
    }
    o << endl;
    return o;
  }
};

if u need main i will post it
Last edited on
Topic archived. No new replies allowed.