zoukankan      html  css  js  c++  java
  • 【python】2048

    来源:https://www.shiyanlou.com/courses/368

     实验楼的2048程序,在linux下可实现通过终端游戏。

    主要学习的知识点:

    1.状态机函数实现,用字典将状态和函数相对应,返回状态再通过字典调用相关函数

    2.字典的值可以是函数名,也可以是lambda匿名函数。 lambda:25  这种是没有输入的匿名函数

    3.defaultdict可以指定字典默认类型

    4.hasattr可以查找是否有指定属性

    5.函数可以定义在函数中,如果一个函数A只在函数B中使用,可以在B中定义A

    6. 注意如下写法

    choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])

    7. zip, any函数的使用

    8. 如果有函数A,则可以定义A.var这样的变量。在代码中可以实现类似C的静态变量的效果。

    import curses  #?
    from random import randrange, choice
    from collections import defaultdict
    
    
    letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']
    actions = ['Up','Left','Down','Right','Restart','Exit']
    actions_dict = dict(zip(letter_codes, actions * 2))  #?
    
    def get_user_action(keyboard):
        char = "N"
        while char not in actions_dict:
            char = keyboard.getch()
        return actions_dict[char]
        
    def transpose(field):
        return [list(row) for row in zip(*field)]
    
    def invert(field):
        return [row[::-1] for row in field]
    
    class GameField(object):
        def __init__(self, height=4, width=4, win=2048):
            self.height = height
            self.width = width
            self.win_value = 2048
            self.score = 0
            self.highscore = 0
            self.reset()
        
    
        
        def reset(self):
            if self.score > self.highscore:
                self.highscore = self.score
            self.score = 0
            self.field = [[0 for i in range(self.width)] for j in range(self.height)]
            self.spawn()
            self.spawn()
        
        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 for i in range(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])
                    assert len(new_row) == len(row)
                    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_is_possible(direction):
                    self.field = moves[direction](self.field)
                    self.spawn()
                    return True
                else:
                    return False
        
        def is_win(self):
            return any(any(i >= self.win_value for i in row) for row in self.field)
        
        def is_gameover(self):
            return not any(self.move_is_possible(move) for move in actions)
        
    
        
        def draw(self, screen):
            help_string1 = '(W)Up (S)Down (A)Left (D)Right'
            help_string2 = '      (R)Restart (Q)Exit'
            gameover_string = '            GAME OVER'
            win_string = '             YOU WIN!'
            
            def cast(string):
                screen.addstr(string + '
    ')
            
            #绘制水平分割线
            def draw_hor_separator():
                line = '+' + ('+------' * self.width + '+')[1:]
                separator = defaultdict(lambda: line)
                if not hasattr(draw_hor_separator, "counter"):
                    draw_hor_separator.counter = 0
                cast(separator[draw_hor_separator.counter])
                draw_hor_separator.counter += 1
            
            def draw_row(row):
                cast(''.join('|{: ^5} '.format(num) if num > 0 else '|      ' for num in row) + '|')
            
            screen.clear()
            cast('SCORE: ' + str(self.score))
            if 0 != self.highscore:
                cast('HIGHSCORE: ' + str(self.highscore))
            
            for row in self.field:
                draw_hor_separator()
                draw_row(row)
            
            draw_hor_separator()
            
            if self.is_win():
                cast(win_string)
            else:
                if self.is_gameover():
                    cast(gameover_string)
                else:
                    cast(help_string1)
            cast(help_string2)
        def spawn(self): #随机生成一个2或者4
            new_element = 4 if randrange(100) > 89 else 2
            (i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])
            self.field[i][j] = new_element
    
        def move_is_possible(self, direction):
            def row_is_left_movable(row):
                def change(i):
                    if row[i] == 0 and row[i + 1] != 0: #可以移动
                        return True
                    if row[i] != 0 and row[i + 1] == row[i]: #可以合并
                        return True
                    return False
                return any(change(i) for i in range(len(row) - 1))
            
            check = {}
            check['Left'] = lambda field: any(row_is_left_movable(row) for row in field)
            check['Right'] = lambda field: check['Left'](invert(field))
            check['Up'] = lambda field: check['Left'](transpose(field))
            check['Down'] = lambda field: check['Right'](transpose(field))
            
            if direction in check:
                return check[direction](self.field)
            else:
                return False
    def main(stdscr):
        
        def init():
            #重置游戏
            game_field.reset()
            return 'Game'
        
        def not_game(state):
            #画出GameOver或者Win的界面
            game_field.draw(stdscr)
            #读取用户输入得到action,判断是重启还是结束游戏
            action = get_user_action(stdscr)
            responses = defaultdict(lambda: state)   #? 默认是当前状态,没有行为就会一直在当前界面循环
            responses['Restart'], responses['Exit'] = 'Init', 'Exit'
            return responses[action]
        
        def game():
            #画出当前棋盘状态
            game_field.draw(stdscr)
            #读取用户输入得到action
            action = get_user_action(stdscr)
            if action == 'Restart':
                return 'Init'
            if action == 'Exit':
                return 'Exit'
            if game_field.move(action):#成功移动了一步
                if game_field.is_win():
                    return 'Win'
                if game_field.is_gameover():
                    return 'Gameover'
            return 'Game'
        
        state_actions = {
                'Init': init,
                'Win': lambda: not_game('Win'),
                'Gameover': lambda: not_game('Gameover'),
                'Game': game
            }
        
        curses.use_default_colors()
        game_field = GameField(win=32)
        
        state = 'Init'
        
        #状态机开始循环
        while state != 'Exit':
            state = state_actions[state]()
        
    curses.wrapper(main)
  • 相关阅读:
    Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.
    DHCP "No subnet declaration for xxx (no IPv4 addresses)" 报错
    Centos安装前端开发常用软件
    kubernetes学习笔记之十:RBAC(二)
    k8s学习笔记之StorageClass+NFS
    k8s学习笔记之ConfigMap和Secret
    k8s笔记之chartmuseum搭建
    K8S集群集成harbor(1.9.3)服务并配置HTTPS
    Docker镜像仓库Harbor1.7.0搭建及配置
    Nginx自建SSL证书部署HTTPS网站
  • 原文地址:https://www.cnblogs.com/dplearning/p/5702063.html
Copyright © 2011-2022 走看看