zoukankan      html  css  js  c++  java
  • Python 008- 游戏2048

      1 #-*- coding:utf-8 -*-
      2 import curses
      3 from random import randrange, choice # generate and place new tile
      4 from collections import defaultdict
      5 
      6 # user`s action
      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 = win
     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('HIGHSCORE: ' + str(self.highscore))
    112         for row in self.field:
    113             #print the ---
    114             draw_hor_separator()
    115             #print the number we get
    116             draw_row(row)
    117         draw_hor_separator()
    118         if self.is_win():
    119             cast(win_string)
    120         else:
    121             if self.is_gameover():
    122                 cast(gameover_string)
    123             else:
    124                 cast(help_string1)
    125         cast(help_string2)
    126 
    127     #Get a radom number from1~100,if this number is larger than 89,then print 2
    128     def spawn(self):
    129         new_element = 4 if randrange(100) > 89 else 2
    130         (i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])
    131         self.field[i][j] = new_element
    132 
    133     def move_is_possible(self, direction):
    134         def row_is_left_movable(row): 
    135             def change(i): # true if there'll be change in i-th tile
    136                 if row[i] == 0 and row[i + 1] != 0: # Move
    137                     return True
    138                 if row[i] != 0 and row[i + 1] == row[i]: # Merge
    139                     return True
    140                 return False
    141             return any(change(i) for i in range(len(row) - 1))
    142 
    143         check = {}
    144         check['Left']  = lambda field:                              
    145                 any(row_is_left_movable(row) for row in field)
    146 
    147         check['Right'] = lambda field:                              
    148                  check['Left'](invert(field))
    149 
    150         check['Up']    = lambda field:                              
    151                 check['Left'](transpose(field))
    152 
    153         check['Down']  = lambda field:                              
    154                 check['Right'](transpose(field))
    155 
    156         if direction in check:
    157             return check[direction](self.field)
    158         else:
    159             return False
    160 
    161 def main(stdscr):
    162     def init():
    163         #重置游戏棋盘
    164         game_field.reset()
    165         return 'Game'
    166 
    167     def not_game(state):
    168         #画出 GameOver 或者 Win 的界面
    169         game_field.draw(stdscr)
    170         #读取用户输入得到action,判断是重启游戏还是结束游戏
    171         action = get_user_action(stdscr)
    172         responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环
    173         responses['Restart'], responses['Exit'] = 'Init', 'Exit' #对应不同的行为转换到不同的状态
    174         return responses[action]
    175 
    176     def game():
    177         #画出当前棋盘状态
    178         game_field.draw(stdscr)
    179         #读取用户输入得到action
    180         action = get_user_action(stdscr)
    181 
    182         if action == 'Restart':
    183             return 'Init'
    184         if action == 'Exit':
    185             return 'Exit'
    186         if game_field.move(action): # move successful
    187             if game_field.is_win():
    188                 return 'Win'
    189             if game_field.is_gameover():
    190                 return 'Gameover'
    191         return 'Game'
    192 
    193 
    194     state_actions = {
    195             'Init': init,
    196             'Win': lambda: not_game('Win'),
    197             'Gameover': lambda: not_game('Gameover'),
    198             'Game': game
    199         }
    200 
    201     curses.use_default_colors()
    202 
    203     # 设置终结状态最大数值为 2048
    204     game_field = GameField(win=2048)
    205 
    206 
    207     state = 'Init'
    208 
    209     #状态机开始循环
    210     while state != 'Exit':
    211         state = state_actions[state]()
    212 
    213 curses.wrapper(main)

    游戏代码来源于网络,仅供参考。

  • 相关阅读:
    Ubuntu oracle SDK替换OpenJDK
    用update-alternatives管理java版本
    安卓配置
    CS 159: Advanced Topics in Machine Learning: Structured Prediction
    ros bag 代码操作
    vim 方式快捷编辑代码
    文件权限
    操作系统连不上网
    github权限管理
    nmap基本命令使用
  • 原文地址:https://www.cnblogs.com/hustcser/p/8907799.html
Copyright © 2011-2022 走看看