#! /usr/bin/python3 import random, copy, curses class G2048(): def __init__(self): self.board = [] self.board_line = 3 self.board_size = self.board_line**2 for i in range(self.board_size): self.board.insert(i,None) self.moved = False self.stdscr = curses.initscr() self.undo = ['u','r'] self.up = ['k','w'] #straight self.left = ['h','a'] #straight self.down = ['j','s'] #back self.right = ['l','d'] #back self.line = self.left + self.right self.column = self.up + self.down def game_logic(self, l): oldHash = hash(tuple(l)) line_active= True merged = False while line_active: for i in range(self.board_line-1): if l[i] == None and l[i+1] != None: l.pop(i) l.insert(i+1,None) elif l[i] != None and l[i] == l[i+1] and merged != True: mi=l.pop(i) l.insert(i,int(mi)*2) l.pop(i+1) l.insert(i+1,None) merged = True oldHash = hash(tuple(l)) self.moved = True newHash = hash(tuple(l)) if oldHash == newHash: # print('Exiting: Boxes didn't move') line_active = False else: # print('Repeating: Boxes moved') oldHash = newHash self.moved = True return l def reverse(self, rl, m): if m in self.left + self.up: gl = self.game_logic(rl) #k else: gl = self.game_logic(rl[::-1])[::-1] #j return gl def movement(self): self.stdscr.addstr(10, 0, '\nMove the numbers: ') m = self.stdscr.getkey() self.moved=False board_temp=copy.deepcopy(self.board) self.move(m) if m not in self.undo and self.moved == True: self.board_reset = copy.deepcopy(board_temp) def move(self, m): if m in self.line: for i in range(0,self.board_size,self.board_line): rl = self.board[i:i+self.board_line] self.board[i:i+self.board_line] = self.reverse(rl,m) elif m in self.column: for i in range(self.board_line): rl = self.board[i::self.board_line] self.board[i::self.board_line] = self.reverse(rl,m) elif m in self.undo: self.board = self.board_reset else: raise ValueError('Can not move this way') def print_board(self): for i in range(0,self.board_size,self.board_line): self.stdscr.addstr(i, 0, '{!s:<4}'.join(' '*(self.board_line+1)).format(*self.board[i:i+self.board_line])) self.stdscr.refresh() def add_number(self): indices = [] indices = [i for i, x in enumerate(self.board) if x == None] self.li=len(indices) p = random.choice(indices) self.board[p] = random.choices([2,4],weights=[80,20])[0] self.stdscr.addstr(13, 0, '\nNew number at position '+str(p+1)) self.stdscr.addstr(15, 0,str(self.li)+str(p)+str(indices)+' ') def run(self, *args): self.game_state = True self.add_number() self.board_reset = copy.deepcopy(self.board) while self.game_state: self.print_board() #self.check_playable() try: self.movement() except ValueError: #continue pass self.stdscr.addstr(13, 0, 'MOVED ') if self.moved == False: self.stdscr.addstr(13, 0, 'DID NOT MOVE') #TODO: Fix continue breaks game over but fixes undo continue try: self.add_number() except IndexError: # catch game over here self.game_state = False self.stdscr.addstr(15, 0, 'Game Over') #print('Game Over') def check_playable(self): l=0 for i in ['h','j','k','l']: if self.li == 1 and self.moved == False: self.move(i) l=l+1 self.game_state = False #print('Game Over') #curses.endwin() #self.print_board() if l==4: self.stdscr.addstr(15, 0, 'Game Over') def close(self): state = True while state: self.stdscr.addstr(16, 0, 'Press q to exit: ') m = self.stdscr.getkey() if m == 'q': state = False curses.endwin() game = G2048() curses.wrapper(game.run) game.close()