• python之2048


      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 'WASDRQwasdrq']
      8 actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']
      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_dict:    
     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['Down']  = 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(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         help_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 + '
    ')
     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 = 0
    102             cast(separator[draw_hor_separator.counter])
    103             draw_hor_separator.counter += 1
    104 
    105         def draw_row(row):
    106             cast(''.join('|{: ^5} '.format(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 2
    127         (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_element
    129 
    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
    133                 if row[i] == 0 and row[i + 1] != 0: # Move
    134                     return True
    135                 if row[i] != 0 and row[i + 1] == row[i]: # Merge
    136                     return True
    137                 return False
    138             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['Down']  = lambda field:                              
    151                 check['Right'](transpose(field))
    152 
    153         if direction in check:
    154             return check[direction](self.field)
    155         else:
    156             return False
    157 
    158 def main(stdscr):
    159     def init():
    160         #重置游戏棋盘
    161         game_field.reset()
    162         return 'Game'
    163 
    164     def not_game(state):
    165         #画出 GameOver 或者 Win 的界面
    166         game_field.draw(stdscr)
    167         #读取用户输入得到action,判断是重启游戏还是结束游戏
    168         action = get_user_action(stdscr)
    169         responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环
    170         responses['Restart'], responses['Exit'] = 'Init', 'Exit' #对应不同的行为转换到不同的状态
    171         return responses[action]
    172 
    173     def game():
    174         #画出当前棋盘状态
    175         game_field.draw(stdscr)
    176         #读取用户输入得到action
    177         action = get_user_action(stdscr)
    178 
    179         if action == 'Restart':
    180             return 'Init'
    181         if action == 'Exit':
    182             return 'Exit'
    183         if game_field.move(action): # move successful
    184             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': game
    196         }
    197 
    198     curses.use_default_colors()
    199     game_field = GameField(win=32)
    200 
    201 
    202     state = 'Init'
    203 
    204     #状态机开始循环
    205     while state != 'Exit':
    206         state = state_actions[state]()
    207 
    208 curses.wrapper(main)

  • 相关阅读:
    python基础2
    python基础1
    25 CSS3盒子模型
    24 CSS3新增选择器
    23 html5新特性
    22 css初始化
    21 布局技巧
    20 溢出的文字显示省略号
    19 vertical-align 属性应用
    18 CSS三角 用户界面样式
  • 原文地址:https://www.cnblogs.com/jacen789/p/5320826.html
Copyright © 2020-2023  润新知