Python 2048, python2048
1 #-*-coding: UTF-8-*-2 3 import curses 4 from random import randrange, choice # generate and place new tile 5 from collections import defaultdict 6 7 letter_codes = [ord (ch) for ch in 'wasdrqwasdrqqq'] 8 actions = ['up', 'left ', 'lowdown ', 'right', 'restart', 'delete'] 9 actions_dict = dict (zip (letter_codes, actions * 2) 10 11 def get_user_action (keyboard ): 12 char = "N" 13 while char not in actions_d Ict: 14 char = keyboard. getch () 15 return actions_dict [char] 16 17 def transpose (field): 18 return [list (row) for row in zip (* field)] 19 20 def invert (field): 21 return [row [:-1] for row in field] 22 23 class GameField (object): 24 def _ init _ (self, height = 4, width = 4, win = 2048): 25 self. height = height 26 self. width = width 27 self. win_value = 2048 28 self. score = 0 29 self. highscore = 0 30 self. Reset () 31 32 def reset (self): 33 if self. score> self. highscore: 34 self. highscore = self. score 35 self. score = 0 36 self. field = [[0 for I in range (self. width)] for j in range (self. height)] 37 self. spawn () 38 self. spawn () 39 40 def move (self, direction): 41 def move_row_left (row): 42 def tighten (row ): # squeese non-zero elements together 43 new_row = [I for I in row if I! = 0] 44 new_row + = [0 for I in range (len (row)-len (new_row)] 45 return new_row 46 47 def merge (row ): 48 pair = False 49 new_row = [] 50 for I in range (len (row): 51 if pair: 52 new_row.append (2 * row [I]) 53 self. score + = 2 * row [I] 54 pair = False 55 else: 56 if I + 1 <len (row) and row [I] = row [I + 1]: 57 pair = True 58 new_row.append (0) 59 else: 60 new_row.append (row [I]) 61 assert len (new_row) = Len (row) 62 return new_row 63 return tighten (merge (tighten (row) 64 65 moves ={} 66 moves ['left'] = lambda field: \ 67 [move_row_left (row) for row in field] 68 moves ['right'] = lambda field: \ 69 invert (moves ['left'] (invert (field ))) 70 moves ['up'] = lambda field: \ 71 transpose (moves ['left'] (transpose (field) 72 moves ['drop'] = lambda field: \ 73 transpose (moves ['right'] (transpose (field ))) 74 75 if direction in moves: 76 if self. move_is_possible (direction): 77 self. field = moves [direction] (self. field) 78 self. spawn () 79 return True 80 else: 81 return False 82 83 def is_win (self): 84 return any (I> = self. win_value for I in row) for row in self. field) 85 86 def is_gameover (self): 87 return not any (self. move_is_possible (move) for move in actions) 88 89 def draw (self, screen): 90 he Lp_string1 = '(W) Up (S) Down (A) Left (D) Right '91 help_string2 =' (R) Restart (Q) exit '92 gameover_string = 'game over' 93 win_string = 'you WIN! '94 def cast (string): 95 screen. addstr (string + '\ n') 96 97 def draw_hor_separator (): 98 line =' + ('+ ------' * self. width + ') [1:] 99 separator = defaultdict (lambda: line) 100 if not hasattr (draw_hor_separator, "counter "): 101 draw_hor_separator.counter = 0102 cast (separator [draw_hor_separator.counter]) 103 draw_hor_separator.counter + = 1104 105 def draw_row (row): 106 cast (''. join ('| {: ^ 5 }'. for Mat (num) if num> 0 else '|' for num in row) + '|') 107 108 screen. clear() 109 cast ('score: '+ str (self. score) 110 if 0! = Self. highscore: 111 cast ('hghscore: '+ str (self. highscore) 112 for row in self. field: 113 draw_hor_separator () 114 draw_row (row) 115 draw_hor_separator () 116 if self. is_win (): 117 cast (win_string) 118 else: 119 if self. is_gameover (): 120 cast (gameover_string) 121 else: 122 cast (help_string1) 123 cast (help_string2) 124 125 def spawn (self): 126 new_element = 4 if randrange (100)> 89 else 2127 (I, j) = choice ([(I, J) for I in range (self. width) for j in range (self. height) if self. field [I] [j] = 0]) 128 self. field [I] [j] = new_element129 130 def move_is_possible (self, direction): 131 def row_is_left_movable (row): 132 def change (I ): # true if there'll be change in I-th tile=if row [I] = 0 and row [I + 1]! = 0: # Move134 return True135 if row [I]! = 0 and row [I + 1] = row [I]: # Merge136 return true1_return False138 return any (change (I) for I in range (len (row) -1) 139 140 check = {} 141 check ['left'] = lambda field: \ 142 any (row_is_left_movable (row) for row in field) 143 144 check ['right'] = lambda field: \ 145 check ['left'] (invert (field) 146 147 check ['up'] = lambda field: \ 148 check ['left'] (transpose (field) 149 150 check ['drop'] = lambda f Ield: \ 151 check ['right'] (transpose (field) 152 153 if direction in check: 154 return check [direction] (self. field) 155 else: 156 return False157 158 def main (stdscr): 159 def init (): 160 # reset game board 161 game_field.reset () 162 return 'game' 163 164 def not_game (state): 165 # Draw the GameOver or Win interface 166 game_field.draw (stdscr) 167 # Read the user input to get the action, determine whether to restart or stop the game 168 action = get_user_action (stdscr) 169 responses = defaul Tdict (lambda: state) # The current state is used by default. If no behavior is performed, the system will loop through the current interface. For example, 170 responses ['restart'], responses ['eg'] = 'init ', 'delete' # convert different behaviors to different States 171 return responses [action] 172 173 def game (): 174 # Draw the current checker status 175 game_field.draw (stdscr) 176 # obtain action177 action = get_user_action (stdscr) 178 179 if action = 'restart': 180 return 'init '181 if action = 'eg' after reading user input ': 182 return 'exit '183 if game_field.move (action): # move successf Ul184 if game_field.is_win (): 185 return 'win' 186 if game_field.is_gameover (): 187 return 'gameover '188 return 'game' 189 190 191 state_actions = {192 'init ': Init, 193 'win': lambda: not_game ('win'), 194 'gameover': lambda: not_game ('gameover'), 195 'game': game196} 197 198 curses. use_default_colors () 199 game_field = GameField (win = 32) 200 201 202 state = 'init' 203 204 205 # state machine starts loop while state! = 'Exit ': 206 state = state_actions [state] () 207 208 curses. wrapper (main)