Skip to content

Commit 6add44a

Browse files
committed
Adding Othello Game
Adding Othello/Reversi Game project for contributions towards the root repository.
1 parent 030e159 commit 6add44a

16 files changed

+422
-0
lines changed

Othello-Reversi-Game/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/__pycache__

Othello-Reversi-Game/Board.py

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import numpy as np
2+
3+
class Board:
4+
WHITE = -1
5+
BLACK = 1
6+
EMPTY = 0
7+
8+
def __init__(self) -> None:
9+
'''Initiliaze the Othello game board with a 8x8 numpy matrix'''
10+
self.board = np.array([0]*8, dtype = np.int8) # initiliasing 1D array with the first row of 8 zeroes
11+
self.board = self.board[np.newaxis, : ] # expanding 1D array to 2D array
12+
for _ in range(3): # increasing rows till 8
13+
self.board = np.concatenate((self.board, self.board), axis = 0)
14+
15+
# initiliasing the centre squares
16+
self.board[3, 3] = self.board[4,4] = Board.WHITE
17+
self.board[3, 4] = self.board[4,3] = Board.BLACK
18+
19+
self.black_disc_count = 2
20+
self.white_disc_count = 2
21+
22+
def all_legal_moves(self, PLAYER: int) -> set:
23+
'''Return all legal moves for the player'''
24+
OPPONENT = Board.WHITE if PLAYER == Board.BLACK else Board.BLACK
25+
26+
all_legal_moves = set()
27+
for row in range(8):
28+
for col in range(8):
29+
if self.board[row, col] == PLAYER:
30+
all_legal_moves.update(self.legal_moves(row, col))
31+
32+
return all_legal_moves
33+
34+
def legal_moves(self, row: int, col: int) -> list:
35+
'''Return all legal moves for the cell at the given position'''
36+
PLAYER = self.board[row, col]
37+
OPPONENT = Board.WHITE if PLAYER == Board.BLACK else Board.BLACK
38+
legal_moves = list()
39+
40+
# check for legal moves along the row of the cell
41+
if col >= 2:
42+
i = col - 1
43+
while i >= 0 and self.board[row, i] == OPPONENT:
44+
i -= 1
45+
if (i != col - 1 and i >= 0) and self.board[row, i] == Board.EMPTY:
46+
legal_moves.append((row, i))
47+
48+
if col <= 5:
49+
i = col + 1
50+
while i < 8 and self.board[row, i] == OPPONENT:
51+
i += 1
52+
if (i != col + 1 and i < 8) and self.board[row, i] == Board.EMPTY:
53+
legal_moves.append((row, i))
54+
55+
# check for legal moves along the column of the cell
56+
if row >= 2:
57+
i = row - 1
58+
while i >= 0 and self.board[i, col] == OPPONENT:
59+
i -= 1
60+
if (i != row - 1 and i >= 0) and self.board[i, col] == Board.EMPTY:
61+
legal_moves.append((i, col))
62+
63+
if row <= 5:
64+
i = row + 1
65+
while i < 8 and self.board[i, col] == OPPONENT:
66+
i += 1
67+
if (i != row + 1 and i < 8) and self.board[i,col] == Board.EMPTY:
68+
legal_moves.append((i, col))
69+
70+
# check for legal moves along diagonals on which the cell lies
71+
if row >= 2 and col >= 2: # diagonal from the cell towards top left
72+
r = row - 1
73+
c = col - 1
74+
while (r >= 0 and c >= 0) and self.board[r, c] == OPPONENT:
75+
r -= 1
76+
c -=1
77+
if (r != row - 1 and c != col - 1) and (r >= 0 and c >= 0) and self.board[r, c] == Board.EMPTY:
78+
legal_moves.append((r, c))
79+
80+
if row >= 2 and col <= 5: # diagonal from the cell towards top right
81+
r = row - 1
82+
c = col + 1
83+
while (r >= 0 and c < 8) and self.board[r, c] == OPPONENT:
84+
r -= 1
85+
c +=1
86+
if (r != row - 1 and c != col + 1) and (r >= 0 and c < 8) and self.board[r, c] == Board.EMPTY:
87+
legal_moves.append((r, c))
88+
89+
if row <= 5 and col <= 5: # diagonal from the cell towards bottom right
90+
r = row + 1
91+
c = col + 1
92+
while (r < 8 and c < 8) and self.board[r, c] == OPPONENT:
93+
r += 1
94+
c +=1
95+
if (r != row + 1 and c != col +1) and (r < 8 and c < 8) and self.board[r, c] == Board.EMPTY:
96+
legal_moves.append((r, c))
97+
98+
if row <= 5 and col >= 2: # diagonal from the cell towards bottom left
99+
r = row + 1
100+
c = col - 1
101+
while (r < 8 and c >= 0) and self.board[r, c] == OPPONENT:
102+
r += 1
103+
c -= 1
104+
if (r != row + 1 and c != col - 1) and (r < 8 and c >= 0) and self.board[r, c] == Board.EMPTY:
105+
legal_moves.append((r, c))
106+
107+
108+
return legal_moves
109+
110+
def set_discs(self, row: int, col: int, PLAYER: int) -> None:
111+
'''Set the discs on the board as per the move made on the given cell'''
112+
self.board[row, col] = PLAYER
113+
OPPONENT = Board.WHITE if PLAYER == Board.BLACK else Board.BLACK
114+
115+
# outflanking pieces on the right
116+
c = col + 1
117+
while c < 8 and self.board[row, c] == OPPONENT:
118+
c += 1
119+
if (c != col + 1 and c < 8) and self.board[row, c] == PLAYER: # outflanking is legal
120+
self.board[row, col:c] = PLAYER
121+
122+
# outflanking pieces on the left
123+
c = col - 1
124+
while c >= 0 and self.board[row, c] == OPPONENT:
125+
c -= 1
126+
if (c != col - 1 and c >= 0) and self.board[row, c] == PLAYER: # outflanking is ilegal
127+
self.board[row, c:col] = PLAYER
128+
129+
# outflanking pieces below
130+
r = row + 1
131+
while r < 8 and self.board[r, col] == OPPONENT:
132+
r += 1
133+
if (r != row + 1 and r < 8) and self.board[r, col] == PLAYER: # outflanking is legal
134+
self.board[row:r , col] = PLAYER
135+
136+
# outflanking pieces above
137+
r = row - 1
138+
while r >= 0 and self.board[r, col] == OPPONENT:
139+
r -= 1
140+
if (r != row - 1 and r >= 0) and self.board[r, col] == PLAYER: # outflanking is legal
141+
self.board[r:row, col] = PLAYER
142+
143+
# outflanking pieces in the diagonal from the cell towards top left
144+
r = row - 1
145+
c = col - 1
146+
while (r >= 0 and c >= 0) and self.board[r, c] == OPPONENT:
147+
r -= 1
148+
c -= 1
149+
if (r != row - 1 and c != col - 1) and (r >= 0 and c >= 0) and self.board[r, c] == PLAYER: # outflanking is legal
150+
r = row - 1
151+
c = col - 1
152+
while self.board[r, c] == OPPONENT:
153+
self.board[r, c] = PLAYER
154+
r -= 1
155+
c -= 1
156+
157+
# outflanking pieces in the diagonal from the cell towards top right
158+
r = row - 1
159+
c = col + 1
160+
while (r >= 0 and c < 8) and self.board[r, c] == OPPONENT:
161+
r -= 1
162+
c += 1
163+
if (r != row - 1 and c != col + 1) and (r >= 0 and c < 8) and self.board[r, c] == PLAYER: # outflanking is legal
164+
r = row - 1
165+
c = col + 1
166+
while self.board[r, c] == OPPONENT:
167+
self.board[r, c] = PLAYER
168+
r -= 1
169+
c += 1
170+
171+
# outflanking pieces in the diagonal from the cell towards bottom right
172+
r = row + 1
173+
c = col + 1
174+
while (r < 8 and c < 8) and self.board[r, c] == OPPONENT:
175+
r += 1
176+
c += 1
177+
if ( r != row + 1 and c != col + 1 ) and (r < 8 and c < 8) and self.board[r, c] == PLAYER: # outflanking is legal
178+
r = row + 1
179+
c = col + 1
180+
while self.board[r, c] == OPPONENT:
181+
self.board[r, c] = PLAYER
182+
r += 1
183+
c += 1
184+
185+
# outflanking pieces in the diagonal from the cell towards bottom left
186+
r = row + 1
187+
c = col - 1
188+
while (r < 8 and c >= 0) and self.board[r, c] == OPPONENT:
189+
r += 1
190+
c -= 1
191+
if (r != row + 1 and c != col - 1) and (r < 8 and c >= 0) and self.board[r, c] == PLAYER: # outflanking is legal
192+
r = row + 1
193+
c = col - 1
194+
while self.board[r, c] == OPPONENT:
195+
self.board[r, c] = PLAYER
196+
r += 1
197+
c -= 1
198+
199+
# update disc counters
200+
self.black_disc_count = self.board[self.board > 0].sum()
201+
self.white_disc_count = -self.board[self.board < 0].sum()
202+
203+
def print_board(self) -> None:
204+
print(self.board)
205+
206+
def reset_board(self) -> None:
207+
self.board.fill(Board.EMPTY)
208+
209+
# initiliasing the centre squares
210+
self.board[3, 3] = self.board[4,4] = Board.WHITE
211+
self.board[3, 4] = self.board[4,3] = Board.BLACK
212+
213+
self.black_disc_count = self.white_disc_count = 2
55.2 KB
Binary file not shown.

Othello-Reversi-Game/README.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<h1 align="center">⚫ Othello/Reversi ⚪ </h1>
2+
3+
A two-player, GUI-equipped, [Othello/Reversi](https://www.worldothello.org/about/about-othello/othello-rules/official-rules/english) game made in **Python3** using the `pygame` library.
4+
5+
## 📜 Description
6+
Othello is a board-game played on a 8x8 board, with 64 discs that are black on one side and white on the other. Each player gets 32 such discs, out of which 2 from each player are kept on the board in the following manner:
7+
8+
![image](https://github.com/TERNION-1121/Othello-Reversi-Game/assets/97667653/ea03fdd8-9abc-4b14-bdc9-7d983fb38041)
9+
10+
<br>
11+
12+
A move consists of "outflanking" your opponent's disc(s), then flipping the "outflanked" disc(s) to your color.
13+
To outflank means, if your disc is kept on square X, and you have another disc on square Y, such that:
14+
- X and Y lie on the same row, or
15+
- X and Y lie on the same column, or
16+
- X and Y lie on the same diagonal,
17+
18+
If any one (or more) of the above is the case while playing, then the Opponent's discs between X and Y get flipped to your color.
19+
20+
<br>
21+
22+
Example:
23+
24+
> Here White disc A was already present on the board, after placing White disc B, the row of Black discs between White disc A and B got outflanked,
25+
26+
![06a8330dc692b7631a2e50660e4a7346](https://github.com/TERNION-1121/Othello-Reversi-Game/assets/97667653/84feed70-ee16-4f4f-baad-39a3ecc148ed)
27+
28+
> And thus the outflanked Black discs flipped to White.
29+
30+
![cd51ed676fb49538035a8bf006ffbe96](https://github.com/TERNION-1121/Othello-Reversi-Game/assets/97667653/bafe9059-7a32-4d93-aaa2-bfc97a311fce)
31+
32+
For a more comprehensive explanation of the game rules, check out this [link](https://www.worldothello.org/about/about-othello/othello-rules/official-rules/english).
33+
34+
35+
### How to Play the Game 🎮
36+
1. Download the source code
37+
2. Make sure to install Python3 on your Computer along with `pip`
38+
3. Install the `numpy` and `pygame` libraries. To do this, open the terminal and type `pip install numpy` and `pip install pygame`.
39+
4. Run the `main.py` file and play the game!
40+
41+
## Author
42+
This Project was Contributed by [Vikrant Singh Bhadouriya](https://www.github.com/TERNION-1121).
43+
44+
Thanks for your kind attention!
2.53 KB
Loading
5.76 KB
Loading
16.3 KB
Loading
12.6 KB
Loading
Loading
3.62 KB
Loading
5.08 KB
Loading
Loading
Loading
5.91 KB
Loading

0 commit comments

Comments
 (0)