| 133 | # this class represents a tic-tac-toe game |
| 134 | # is a CS101-type of project |
| 135 | class Environment: |
| 136 | def __init__(self): |
| 137 | self.board = np.zeros((LENGTH, LENGTH)) |
| 138 | self.x = -1 # represents an x on the board, player 1 |
| 139 | self.o = 1 # represents an o on the board, player 2 |
| 140 | self.winner = None |
| 141 | self.ended = False |
| 142 | self.num_states = 3**(LENGTH*LENGTH) |
| 143 | |
| 144 | def is_empty(self, i, j): |
| 145 | return self.board[i,j] == 0 |
| 146 | |
| 147 | def reward(self, sym): |
| 148 | # no reward until game is over |
| 149 | if not self.game_over(): |
| 150 | return 0 |
| 151 | |
| 152 | # if we get here, game is over |
| 153 | # sym will be self.x or self.o |
| 154 | return 1 if self.winner == sym else 0 |
| 155 | |
| 156 | def get_state(self): |
| 157 | # returns the current state, represented as an int |
| 158 | # from 0...|S|-1, where S = set of all possible states |
| 159 | # |S| = 3^(BOARD SIZE), since each cell can have 3 possible values - empty, x, o |
| 160 | # some states are not possible, e.g. all cells are x, but we ignore that detail |
| 161 | # this is like finding the integer represented by a base-3 number |
| 162 | k = 0 |
| 163 | h = 0 |
| 164 | for i in range(LENGTH): |
| 165 | for j in range(LENGTH): |
| 166 | if self.board[i,j] == 0: |
| 167 | v = 0 |
| 168 | elif self.board[i,j] == self.x: |
| 169 | v = 1 |
| 170 | elif self.board[i,j] == self.o: |
| 171 | v = 2 |
| 172 | h += (3**k) * v |
| 173 | k += 1 |
| 174 | return h |
| 175 | |
| 176 | def game_over(self, force_recalculate=False): |
| 177 | # returns true if game over (a player has won or it's a draw) |
| 178 | # otherwise returns false |
| 179 | # also sets 'winner' instance variable and 'ended' instance variable |
| 180 | if not force_recalculate and self.ended: |
| 181 | return self.ended |
| 182 | |
| 183 | # check rows |
| 184 | for i in range(LENGTH): |
| 185 | for player in (self.x, self.o): |
| 186 | if self.board[i].sum() == player*LENGTH: |
| 187 | self.winner = player |
| 188 | self.ended = True |
| 189 | return True |
| 190 | |
| 191 | # check columns |
| 192 | for j in range(LENGTH): |