Skip to content

Instantly share code, notes, and snippets.

@u1i
Created July 2, 2023 08:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save u1i/09735edf24a368ce8515131aac02c8bf to your computer and use it in GitHub Desktop.
Save u1i/09735edf24a368ce8515131aac02c8bf to your computer and use it in GitHub Desktop.
2048 Game in Python
import curses
from random import randrange, choice
from collections import defaultdict
# Initialize the game
actions = ['Up', 'Down', 'Left', 'Right']
keys = [ord('w'), ord('s'), ord('a'), ord('d')]
actions_dict = dict(zip(keys, actions))
def transpose(field):
return [list(row) for row in zip(*field)]
def invert(field):
return [row[::-1] for row in field]
class Game2048:
def __init__(self, size=4, win_value=2048):
self.size = size
self.win_value = win_value
self.reset()
def reset(self):
self.score = 0
self.board = [[0] * self.size for _ in range(self.size)]
self.spawn()
self.spawn()
def spawn(self):
new_element = 4 if randrange(100) > 89 else 2
(i, j) = choice([(i, j) for i in range(self.size) for j in range(self.size) if self.board[i][j] == 0])
self.board[i][j] = new_element
def move(self, direction):
def move_row_left(row):
def tighten(row):
new_row = [i for i in row if i != 0]
new_row += [0] * (len(row) - len(new_row))
return new_row
def merge(row):
pair = False
new_row = []
for i in range(len(row)):
if pair:
new_row.append(2 * row[i])
self.score += 2 * row[i]
pair = False
else:
if i + 1 < len(row) and row[i] == row[i + 1]:
pair = True
new_row.append(0)
else:
new_row.append(row[i])
return new_row
return tighten(merge(tighten(row)))
moves = {}
moves['Left'] = lambda field: [move_row_left(row) for row in field]
moves['Right'] = lambda field: invert(moves['Left'](invert(field)))
moves['Up'] = lambda field: transpose(moves['Left'](transpose(field)))
moves['Down'] = lambda field: transpose(moves['Right'](transpose(field)))
if direction in moves:
if self.move_possible(direction):
self.board = moves[direction](self.board)
self.spawn()
return True
else:
return False
def move_possible(self, direction):
def row_left_possible(row):
def change(i):
if row[i] == 0 and row[i + 1] != 0:
return True
if row[i] != 0 and row[i] == row[i + 1]:
return True
return False
return any(change(i) for i in range(len(row) - 1))
checks = {}
checks['Left'] = lambda field: any(row_left_possible(row) for row in field)
checks['Right'] = lambda field: checks['Left'](invert(field))
checks['Up'] = lambda field: checks['Left'](transpose(field))
checks['Down'] = lambda field: checks['Right'](transpose(field))
if direction in checks:
return checks[direction](self.board)
else:
return False
def is_game_over(self):
return all(self.move_possible(action) is False for action in actions)
def is_win(self):
return any(any(tile >= self.win_value for tile in row) for row in self.board)
def draw(self, screen):
help_string1 = '(W)Up (S)Down (A)Left (D)Right'
help_string2 = ' R)Restart (Q)Exit'
win_string = ' You Win!'
def cast(string):
screen.addstr(string + '\n')
def draw_separator():
cast('+------' * self.size + '+')
def draw_row(row):
cast(''.join('|{: ^6} '.format(num) if num > 0 else '| ' for num in row) + '|')
screen.clear()
cast('SCORE: ' + str(self.score))
if self.is_win():
screen.addstr(win_string)
else:
if self.is_game_over():
cast(' Game Over!')
else:
cast('')
draw_separator()
for row in self.board:
draw_row(row)
draw_separator()
cast(help_string1)
cast(help_string2)
def play(self, screen):
def get_user_action(screen):
char = 'N'
while char not in actions_dict:
char = screen.getch()
return actions_dict[char]
self.reset()
self.draw(screen)
while True:
action = get_user_action(screen)
if action == 'Restart':
self.reset()
elif action == 'Exit':
break
elif self.move(action):
if self.is_win():
self.draw(screen)
break
self.draw(screen)
def main(stdscr):
game = Game2048()
game.play(stdscr)
curses.wrapper(main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment