'Check moves in othello/reversi [Python 3]
I'm currently trying to create the game of othello (aka, reversi) in python 3.
I have huge problems with the section of the program where it shall evaluate if a move is valid or not.
What I want to create:
- Check if a position on the board is empty or not
- Check if there are any neighbours of the opposite color
- If there are such neighbours, continue in that direction and see if we can reach one of our own pieces without crossing an empty position.
I have tried many different functions but i cant get it right...
In the link down below is my latest attempt,
Solution 1:[1]
Check if a position on the board is empty or not
The first thing that comes to mind is to represent the board as a string, where every character in the string represents the state of that square, starting from 0 (top left) to 63 (bottom right).
For example, say you represented a square being occupied by a white by "o", for black, "x", and an empty square would be ".", for the starting state, it would be:
board = "...........................ox......xo..........................."
Then if you wanted to check whether a square is empty or not, you would check whether that character is empty:
if board[0] == ".":
#Square 0 (top left corner) is empty!
Check if there are any neighbours of the opposite color
For this, you could pre-store tuples of directions that correspond to all of a square's neighbours (this will also be helpful for calculating possible moves):
DIRECTIONS = [
(0, -1), #Up
(1, -1), #Up-Right
(1, 0), #Right
(1, 1), #Down-Right
(0, 1), #Down
(-1, 1), #Down-Left
(-1, 0), #Left
(-1, -1), #Up-Left
]
Where the first item of the tuple is the amount to move horizontally, and the second item being the amount to move vertically. So if you wanted to find neighbors of the opposite color, you would get the index of the current square:
row, col = index // 8, index % 8 # To convert from an index from string to (x, y) values
Then loop through the directions, and check what color the neighbor is using the logic from above.
current = board[index]
for x, y in DIRECTIONS:
r, c = index // (8), index % (8)
r += y
c += x
tile = board[r * 8 + c]
if tile != current and tile != ".": #Not same color, and not empty, so must be opposite color
#Do stuff
Now since that is pretty basic code, it doesn't cover possibilities where the current tile is on an edge on the corner, where the index would go to an incorrect position, looping around. One possibility is to just hardcode those cases in, and ignore those directions, however another (possibly more elegant way) can be used as well. Instead of representing the board as a 64-character string, you can represent it as a 100-character string to include a border like so:
? ? ? ? ? ? ? ? ? ?
? . . . . . . . . ?
? . . . . . . . . ?
? . . . . . . . . ?
? . . . . . . . . ?
? . . . . . . . . ?
? . . . . . . . . ?
? . . . . . . . . ?
? . . . . . . . . ?
? ? ? ? ? ? ? ? ? ?
Then you can simply check if the "neighbor" is part of the border (in this case represented by a question mark, but can be anything else besides the ones you use to represent empty spaces and discs).
However, you will need to account for the fact that you have to convert indices from a 8x8 board to 10x10 board (and convert back) appropriately.
If there are such neighbors, continue in that direction and see if we can reach one of our own pieces without crossing an empty position.
This is pretty simple once you implement the above logic, you will just need a while loop to check tiles in a certain direction, and whether they can be taken if we reach the original's color.
SIZE = 8
DIRECTIONS = [....]
BORDERCHAR = "?"
def add_border(board):
edge = BORDERCHAR * (SIZE + 2)
new_board = edge
for i in range(0, SIZE ** 2, SIZE):
new_board += BORDERCHAR + board[i:i + SIZE] + BORDERCHAR
new_board += edge
return new_board
def possible_moves(board, token):
board = add_border(board) #Converting to 10x10
moves = []
if token == "x":
other = "o"
else:
other = "x"
for space in [i for i, j in enumerate(board) if j == "."]:
for x, y in DIRECTIONS:
r, c = space // (SIZE + 2), space % (SIZE + 2)
r += y
c += x
tile = board[r * (SIZE + 2) + c]
#Checking to see if we reach one of the original discs
entered = False
while tile == other:
entered = True
r += y
c += x
tile = board[r * (SIZE + 2) + c]
if entered is True and tile == token:
moves.append((space // (SIZE + 2), space % (SIZE + 2)))
break
moves = [(r - 1) * (SIZE) + (c - 1) for r, c in moves] #Converting back to 8x8
return moves
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |