Skip to content

Commit 101d3a4

Browse files
Merge pull request #2524 from Shikhar9425/patch-8
2048.py
2 parents 2abb4b2 + 1218eec commit 101d3a4

File tree

2 files changed

+287
-0
lines changed

2 files changed

+287
-0
lines changed

AI-driven 2048(New game)/2048.py

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
import random
2+
import copy
3+
4+
class AI2048:
5+
def __init__(self, board):
6+
self.board = board
7+
8+
def get_empty_cells(self):
9+
empty_cells = []
10+
for i in range(len(self.board)):
11+
for j in range(len(self.board[i])):
12+
if self.board[i][j] == 0:
13+
empty_cells.append((i, j))
14+
return empty_cells
15+
16+
def get_max_tile(self):
17+
return max(map(max, self.board))
18+
19+
def move_left(self):
20+
merged = []
21+
for row in self.board:
22+
new_row = [tile for tile in row if tile != 0]
23+
for i in range(len(new_row) - 1):
24+
if new_row[i] == new_row[i + 1]:
25+
new_row[i] *= 2
26+
new_row[i + 1] = 0
27+
merged.append(new_row[i])
28+
new_row = [tile for tile in new_row if tile != 0]
29+
new_row.extend([0] * (len(row) - len(new_row)))
30+
self.board[self.board.index(row)] = new_row
31+
return merged
32+
33+
def move_right(self):
34+
self.flip_board()
35+
merged = self.move_left()
36+
self.flip_board()
37+
return merged
38+
39+
def move_up(self):
40+
self.transpose_board()
41+
merged = self.move_left()
42+
self.transpose_board()
43+
return merged
44+
45+
def move_down(self):
46+
self.transpose_board()
47+
merged = self.move_right()
48+
self.transpose_board()
49+
return merged
50+
51+
def get_score(self):
52+
return sum(map(sum, self.board))
53+
54+
def get_heuristic_score(self):
55+
max_tile = self.get_max_tile()
56+
empty_cells = len(self.get_empty_cells())
57+
smoothness = self.calculate_smoothness()
58+
monotonicity = self.calculate_monotonicity()
59+
60+
# Weighted sum of different heuristics
61+
return 0.1 * self.get_score() + 2.7 * empty_cells + 1.0 * smoothness + 1.5 * monotonicity + 3.0 * max_tile
62+
63+
def calculate_smoothness(self):
64+
smoothness = 0
65+
for i in range(len(self.board)):
66+
for j in range(len(self.board[i])):
67+
if self.board[i][j] != 0:
68+
value = math.log2(self.board[i][j])
69+
for (dx, dy) in [(-1, 0), (0, -1), (1, 0), (0, 1)]:
70+
x, y = i + dx, j + dy
71+
if 0 <= x < len(self.board) and 0 <= y < len(self.board[i]) and self.board[x][y] != 0:
72+
neighbor_value = math.log2(self.board[x][y])
73+
smoothness -= abs(value - neighbor_value)
74+
return smoothness
75+
76+
def calculate_monotonicity(self):
77+
monotonicity = [0, 0, 0, 0]
78+
for i in range(len(self.board)):
79+
current = 0
80+
next = current + 1
81+
while next < 4:
82+
while next < 4 and self.board[i][next] == 0:
83+
next += 1
84+
if next >= 4:
85+
next -= 1
86+
current_value = 0 if self.board[i][current] == 0 else math.log2(self.board[i][current])
87+
next_value = 0 if self.board[i][next] == 0 else math.log2(self.board[i][next])
88+
if current_value > next_value:
89+
monotonicity[0] += next_value - current_value
90+
elif next_value > current_value:
91+
monotonicity[1] += current_value - next_value
92+
current = next
93+
next += 1
94+
95+
for j in range(len(self.board[0])):
96+
current = 0
97+
next = current + 1
98+
while next < 4:
99+
while next < 4 and self.board[next][j] == 0:
100+
next += 1
101+
if next >= 4:
102+
next -= 1
103+
current_value = 0 if self.board[current][j] == 0 else math.log2(self.board[current][j])
104+
next_value = 0 if self.board[next][j] == 0 else math.log2(self.board[next][j])
105+
if current_value > next_value:
106+
monotonicity[2] += next_value - current_value
107+
elif next_value > current_value:
108+
monotonicity[3] += current_value - next_value
109+
current = next
110+
next += 1
111+
112+
return max(monotonicity)
113+
114+
def get_children_states(self):
115+
children = []
116+
for move in ['left', 'right', 'up', 'down']:
117+
new_board = copy.deepcopy(self.board)
118+
merged = self.move(new_board, move)
119+
if merged:
120+
children.append((new_board, merged))
121+
return children
122+
123+
def get_best_move(self, depth=3):
124+
moves = ['left', 'right', 'up', 'down']
125+
best_score = float('-inf')
126+
best_move = random.choice(moves)
127+
for move in moves:
128+
new_board = copy.deepcopy(self.board)
129+
merged = self.move(new_board, move)
130+
if merged:
131+
child = AI2048(new_board)
132+
score = self.expectimax(child, depth - 1, False)
133+
if score > best_score:
134+
best_score = score
135+
best_move = move
136+
return best_move
137+
138+
def expectimax(self, node, depth, is_maximizing):
139+
if depth == 0:
140+
return node.get_heuristic_score()
141+
142+
if is_maximizing:
143+
max_eval = float('-inf')
144+
children = node.get_children_states()
145+
for child_board, merged in children:
146+
child = AI2048(child_board)
147+
eval = self.expectimax(child, depth - 1, False)
148+
max_eval = max(max_eval, eval)
149+
return max_eval
150+
else:
151+
total_score = 0
152+
empty_cells = node.get_empty_cells()
153+
for cell in empty_cells:
154+
child_board = copy.deepcopy(node.board)
155+
child_board[cell[0]][cell[1]] = 2
156+
child = AI2048(child_board)
157+
eval = self.expectimax(child, depth - 1, True)
158+
total_score += eval
159+
return total_score / len(empty_cells)
160+
161+
def move(self, board, direction):
162+
merged = []
163+
if direction == 'left':
164+
merged = self.move_left(board)
165+
elif direction == 'right':
166+
merged = self.move_right(board)
167+
elif direction == 'up':
168+
merged = self.move_up(board)
169+
elif direction == 'down':
170+
merged = self.move_down(board)
171+
return merged
172+
173+
def move_left(self, board):
174+
merged = []
175+
for row in board:
176+
new_row = [tile for tile in row if tile != 0]
177+
for i in range(len(new_row) - 1):
178+
if new_row[i] == new_row[i + 1]:
179+
new_row[i] *= 2
180+
new_row[i + 1] = 0
181+
merged.append(new_row[i])
182+
new_row = [tile for tile in new_row if tile != 0]
183+
new_row.extend([0] * (len(row) - len(new_row)))
184+
board[board.index(row)] = new_row
185+
return merged
186+
187+
def move_right(self, board):
188+
self.flip_board(board)
189+
merged = self.move_left(board)
190+
self.flip_board(board)
191+
return merged
192+
193+
def move_up(self, board):
194+
self.transpose_board(board)
195+
merged = self.move_left(board)
196+
self.transpose_board(board)
197+
return merged
198+
199+
def move_down(self, board):
200+
self.transpose_board(board)
201+
merged = self.move_right(board)
202+
self.transpose_board(board)
203+
return merged
204+
205+
def flip_board(self, board):
206+
for row in board:
207+
row.reverse()
208+
209+
def transpose_board(self, board):
210+
board[:] = [list(i) for i in zip(*board)]
211+
212+
def print_board(board):
213+
for row in board:
214+
print(row)
215+
print()
216+
217+
if __name__ == "__main__":
218+
board = [
219+
[0, 2, 2, 4],
220+
[0, 2, 0, 4],
221+
[0, 4, 2, 0],
222+
[0, 0, 2, 2]
223+
]
224+
225+
ai = AI2048(board)
226+
print("Initial Board:")
227+
print_board(ai.board)
228+
229+
while True:
230+
if ai.get_empty_cells():
231+
move = ai.get_best_move()
232+
print(f"Moving {move}")
233+
ai.move(move)
234+
print_board(ai.board)
235+
else:
236+
print("No more moves possible.")
237+
break

AI-driven 2048(New game)/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
Package/Script Name: AI-Driven 2048
2+
3+
Short description: AI-Driven 2048 is a Python package that implements an AI player for the popular 2048 game using the Expectimax algorithm. The AI player tries to maximize the score by making informed decisions to achieve higher tile values and ultimately reaching the 2048 tile.
4+
5+
Functionalities/Scripts:
6+
7+
AI2048 class: Implements the AI player for the 2048 game using the Expectimax algorithm.
8+
get_best_move(): Returns the best move (left, right, up, or down) for the current board state based on the Expectimax algorithm.
9+
Setup Instructions:
10+
11+
Ensure you have Python installed on your system (Python 3.6 or higher).
12+
Install the required libraries using pip:
13+
bash
14+
Copy code
15+
pip install numpy
16+
Download the AI2048.py file from the repository or package.
17+
Explanation of Script:
18+
The AI2048 class represents the AI player for the 2048 game. It has methods to calculate the heuristic score, perform moves (left, right, up, down), generate children states, and use the Expectimax algorithm to choose the best move based on the current board state.
19+
20+
Usage:
21+
22+
Create a 4x4 board with the initial tile configuration. The value 0 represents an empty cell.
23+
python
24+
Copy code
25+
board = [
26+
[0, 2, 2, 4],
27+
[0, 2, 0, 4],
28+
[0, 4, 2, 0],
29+
[0, 0, 2, 2]
30+
]
31+
Initialize the AI2048 class with the board configuration.
32+
python
33+
Copy code
34+
from AI2048 import AI2048
35+
36+
ai = AI2048(board)
37+
To get the best move for the current board state, call the get_best_move() method.
38+
python
39+
Copy code
40+
best_move = ai.get_best_move()
41+
print("Best Move:", best_move)
42+
Perform the best move and update the board state accordingly.
43+
python
44+
Copy code
45+
ai.move(best_move)
46+
Output:
47+
The script will output the best move (left, right, up, or down) based on the current board state.
48+
49+
Author:
50+
Shikhar9425

0 commit comments

Comments
 (0)