Python_da12--2048作业

一、基础版本

流程图:


设计思路:

游戏分为<初始化init><游戏中game><胜利win><失败gameover>四个状态;
main函数中主要有init函数,game函数和not_game函数,函数的返回值作为字典的key值,
函数作为value值生成字典,循环捕获key值,通过key值的变化来调用函数,使整个程序循环运转!
1).init函数
初始化创建数据的函数,在捕获用户操作restart时返回此函数,函数返回值为key值game,去进行游戏操作
2).game函数
该函数主要分为,画表格(将初始化的数据按一定格式画出来),不湖欧用户操作进行移动,移动完进行结束
游戏条件(胜利|失败)判断,不满足条件返回key值game,继续进行游戏操作,满足则返回key值win|gameover
进行游戏外设置(重置|退出)操作
3).not_game函数
主要进行游戏结束用户选择操作,捕获用户操作,restart返回key值init,重新游戏。exit退出游戏
import curses
from itertools import chain
from random import choice, randint


class GameField(object):
    def __init__(self, width=4, height=4, win_value=2048):
        self.width = width
        self.height = height
        self.win_value = win_value
        self.score = 0
        self.highscore = 0
        self.reset()

    def reset(self):
        """重置棋盘"""
        if self.score > self.win_value:
            self.highscore = self.score
        self.score = 0

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

        self.random_create()
        self.random_create()

    def random_create(self):
        """初始化棋盘时, 在随机位置生成2或者4, 2的可能性大, 4的可能性少"""
        # 可能出现的问题: 随机生成的i,j位置原本已经有值。 解决方法:
        while True:
            i, j = choice(range(self.width)), choice(range(self.height))
            if self.field[i][j] == 0:
                self.field[i][j] = 4 if randint(1, 100) > 80 else 2
                break

    def draw(self, stdscr):
        def draw_sep():
            line = '+' + '----+' * self.width
            stdscr.addstr(line + '\n')

        def draw_row(row):  # [2,0,2,0]
            draw_one_row = "".join(['|{:^4}'.format(num)
                                    if num != 0  else '|    ' for num in row]) + '|'

            stdscr.addstr(draw_one_row + '\n')

        # 清屏
        stdscr.clear()
        stdscr.addstr('SCORE:' + str(self.score) + '\n')
        if self.highscore != 0:
            stdscr.addstr("HIGHSCORE:" + str(self.highscore) + '\n\n')

        for row in self.field:
            draw_sep()
            draw_row(row)
        draw_sep()

        if self.is_win():
            stdscr.addstr('You win!' + '\n')
        if self.is_gameover():
            stdscr.addstr('Game Over!' + '\n')
        stdscr.addstr("                上下左右键" + '\n')
        stdscr.addstr("       (R)Restart (Q)Exit" + '\n')

    def is_win(self):
        return max(chain(*self.field)) >= self.win_value

    def is_gameover(self):
        """任何方向都不能移动时"""
        return not any([self.move_is_possible(direction)
                        for direction in ['Up', 'Down', 'Right', 'Left']])

    @staticmethod
    def invert(field):
        # 对于列表每一行进行反转
        return [row[::-1] for row in field]

    @staticmethod
    def tranpose(field):
        """对于列表转置, 可以间接求向上移动的可能性"""
        return [list(row) for row in zip(*field)]

    def move_is_possible(self, direction):
        def move_left_possible(row):
            """判断列表中的一行是否可以移动"""

            # 0 2, 0 4, 2 2, 4 2
            # 0 0
            # # 1. 判断两个元素是否可以移动?
            # 4,2,2,2
            def is_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

            # len(row)-1 =4-1 = 3
            # i= 0,1,2
            # 依次遍历每一行的每一个元素, 判断是否可以移动, 只要有一个时可以移动的, 返回True
            return any([is_change(i) for i in range(len(row) - 1)])

        check = {}

        check['Left'] = lambda field: any([move_left_possible(row) for row in field])
        # check['Right'] = lambda  field: any([ move_left_possible(row) for row in invert(field)])
        # 判断每行内容反转后的field能否向左移动, 即原field能否向右移动;
        check['Right'] = lambda field: check['Left'](self.invert(field))
        # 判断转置后的field能否向左移动, 即原field能否向上移动;
        check['Up'] = lambda field: check['Left'](self.tranpose(field))
        # 判断转置后的field能否向右移动, 即原field能否向下移动;
        check['Down'] = lambda field: check['Right'](self.tranpose(field))

        if direction in check:
            return check[direction](self.field)
        else:
            return False

    def move(self, direction):

        def move_row_left(row):
            def tight(row):
                """把所有非0的聚集在最左边"""
                new_row = [item for item in row if item != 0]
                new_row += [0 for item in range(len(row) - len(new_row))]
                return new_row

            def merge(row):
                # 从左向右依次遍历, 如果两个值相等, 那么左边*2, 右边=0,
                for i in range(len(row) - 1):  # 0,1,2,3
                    if row[i] == row[i + 1]:
                        row[i] *= 2
                        row[i + 1] = 0
                        self.score += row[i]
                return row

            return tight(merge(tight(row)))

        moves = {}

        moves['Left'] = lambda field: [move_row_left(row) for row in field]

        moves['Right'] = lambda field: self.invert([move_row_left(row) for row in self.invert(field)])

        moves['Up'] = lambda field: self.tranpose([move_row_left(row) for row in self.tranpose(field)])

        moves['Down'] = lambda field: self.tranpose(moves['Right'](self.tranpose(field)))

        if direction in moves:
            if self.move_is_possible(direction):
                self.field = moves[direction](self.field)
                self.random_create()
                return True
            else:
                return False


def get_user_action(stdscr):
    action = stdscr.getch()
    if action == curses.KEY_UP:
        return 'Up'
    if action == curses.KEY_DOWN:
        return 'Down'
    if action == curses.KEY_LEFT:
        return 'Left'
    if action == curses.KEY_RIGHT:
        return 'Right'
    if action == ord('r'):
        return 'Restart'
    if action == ord('q'):
        return 'Exit'


def main(stdscr):
    def init():
        # 初始化棋盘;
        game_field.reset()
        return 'Game'

    def game():
        # 画棋盘
        game_field.draw(stdscr)
        # 获取用户的操作
        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'

    def not_game(state):
        game_field.draw(stdscr)
        while True:
            action = get_user_action(stdscr)
            if action == 'Restart':
                return 'Init'
            if action == 'Exit':
                return 'Exit'

    state_actions = {
        'Init': init,
        'Game': game,
        'Win': lambda: not_game('Win'),
        # ‘Init’, 'Exit'
        'GameOver': lambda: not_game('GameOver')
    }

    game_field = GameField(win_value=2048)

    state = 'Init'

    while state != 'Exit':
        state = state_actions[state]()


curses.wrapper(main)

二、双人模式

import curses
from itertools import chain
from random import choice , randint

class GameFiled(object):
    def __init__(self,wight=4,hight=4,win_value=2048):
        """创建游戏的属性"""
        self.wight = wight
        self.hight = hight
        self.win_value = win_value
        self.score1 = 0
        self.score2 = 0
        self.file1 = []
        self.file2 = []

    def recreate_file(self):
        """重置棋盘"""

        self.file1 = [[0 for i in range(self.wight)] for j in range(self.hight)]
        self.file2 = [[0 for i in range(self.wight)] for j in range(self.hight)]

        self.create_randem(self.file1)
        self.create_randem(self.file1)
        self.create_randem(self.file2)
        self.create_randem(self.file2)

    def create_randem(self,file):
        """在棋盘中最初的两个数字"""
        while True:
            i,j = choice(range(self.wight)) , choice(range(self.hight))
            if file[i][j] == 0:
                file[i][j] =4 if randint(0,100)>90 else 2
                break

    def draw(self,stdscr):
        def draw_sep():
            """画横线"""
            line = '+'+'----+'*self.wight
            stdscr.addstr(line +'\n')

        def draw_row(row):  # [2,0,2,0]
            draw_one_row = "".join(['|{:^4}'.format(num)
                                    if num != 0  else '|    ' for num in row]) + '|'
            stdscr.addstr(draw_one_row + '\n')

        stdscr.clear()

        stdscr.addstr('Player1_score:'+str(self.score1)+ ' \n')
        """画棋盘1"""
        for row in self.file1:
            draw_sep()
            draw_row(row)
        draw_sep()

        stdscr.addstr('Player2_score:' + str(self.score2) + ' \n')
        """画棋盘2"""
        for row in self.file1:
            draw_sep()
            draw_row(row)
        draw_sep()

        if self.is_win():
            if self.file1 > self.file2:
                stdscr.addstr('Player1 Win' + '\n')
            elif self.file1 < self.file2:
                stdscr.addstr('Player2 Win' + '\n')
        if self.is_gameover():
            stdscr.addstr('All GameOver' + '\n')

        stdscr.addstr('1P:Up Down Left Right\n2P:W A S D\n(R)Restart(Q)Exit\n')


    def is_win(self):
        """定义判断输赢的函数<chain将多个列表内的值链成一个新列表>"""
        return max(chain(*self.file1)) >= self.win_value or \
               max(chain(*self.file2)) >= self.win_value

    def is_gameover(self):
        return (not any([self.move_possible(direction)
                 for direction in ['Up', 'Down', 'Right', 'Left']])) and\
               (not any([self.move_possible1(direction)
                 for direction in ['Up1', 'Down1', 'Right1', 'Left1']]))
    @staticmethod
    def invert(filed):
        """对每一行进行反转"""
        return (row[::-1] for row in filed)

    @staticmethod
    def tranpose(field):
        """对于列表转置, 可以间接求向上移动的可能性"""
        return [list(row) for row in zip(*field)]

    def move_possible(self, direction):
        def leftrow_move_possible(row):
            def is_move(i):
                if row[i] == 0 and row[i+1] != 0:
                    return True
                if row[i] == row[i+1] !=0:
                    return True
                return False
            return any([is_move(i) for i in range(len(row) - 1)])
        possible = {}
        possible['Left'] = lambda filed : any([leftrow_move_possible(row) for row in filed])
        possible['Right'] = lambda filed: possible['Left'](self.invert(filed))
        possible['Up'] = lambda filed:possible['Left'](self.tranpose(filed))
        possible['Down'] = lambda filed :possible['Right'](self.tranpose(filed))

        if direction in possible:
            return possible[direction](self.file1)
        else:
            return False


    def move_possible1(self, direction):
        def leftrow_move_possible(row):
            def is_move(i):
                if row[i] == 0 and row[i+1] != 0:
                    return True
                if row[i] == row[i+1] !=0:
                    return True
                return False
            return any([is_move(i) for i in range(len(row) - 1)])
        possible = {}
        possible['Left1'] = lambda filed : any([leftrow_move_possible(row) for row in filed])
        possible['Right1'] = lambda filed: possible['Left1'](self.invert(filed))
        possible['Up1'] = lambda filed:possible['Left1'](self.tranpose(filed))
        possible['Down1'] = lambda filed :possible['Right1'](self.tranpose(filed))

        if direction in possible:
            return possible[direction](self.file2)
        else:
            return False

    def move(self,direction):
        def leftrow_move(row):
            def tight(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):
                for i in range(len(row)-1):
                    if row[i] == row[i+1]:
                        row[i] = row[i]*2
                        row[i+1] = 0
                        self.score1 += row[i]
                return row
            return tight(merge(tight(row)))

        def leftrow_move1(row):
            def tight(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):
                for i in range(len(row)-1):
                    if row[i] == row[i+1]:
                        row[i] = row[i]*2
                        row[i+1] = 0
                        self.score2 += row[i]
                return row
            return tight(merge(tight(row)))

        moves = {}
        moves['Left'] = lambda filed: [leftrow_move(row) for row in filed]
        moves['Right'] = lambda filed: self.invert([leftrow_move(row) for row in self.invert(filed)])
        moves['Up'] = lambda filed: self.tranpose([leftrow_move(row) for row in self.tranpose(filed)])
        moves['Down'] = lambda filed: self.tranpose(moves['Right'](self.tranpose(filed)))

        moves1 = {}
        moves1['Left1'] = lambda filed: [leftrow_move1(row) for row in filed]
        moves1['Right1'] = lambda filed: self.invert([leftrow_move1(row) for row in self.invert(filed)])
        moves1['Up1'] = lambda filed: self.tranpose([leftrow_move1(row) for row in self.tranpose(filed)])
        moves1['Down1'] = lambda filed: self.tranpose(moves1['Right1'](self.tranpose(filed)))

        if self.move_possible(direction):
            self.file1 = moves[direction](self.file1)
            self.create_randem(self.file1)
            return True
        elif self.move_possible1(direction):
            self.file2 = moves[direction](self.file2)
            self.create_randem(self.file2)
            return True
        else:
            return False

#捕获玩家的操作
def get_action(stdscr):
    action = stdscr.getch()
    if action == curses.KEY_UP:
        return 'Up'
    if action == curses.KEY_DOWN:
        return 'Down'
    if action == curses.KEY_LEFT:
        return 'Left'
    if action == curses.KEY_RIGHT:
        return 'Right'
    if action == ord('w'):
        return 'Up1'
    if action == ord('s'):
        return 'Down1'
    if action == ord('a'):
        return 'Left1'
    if action == ord('d'):
        return 'Right1'
    if action == ord('r'):
        return 'Restart'
    if action == ord('q'):
        return 'Exit'

def main(stdscr):
    """调用游戏类"""

    def init():
        game_filed.recreate_file()
        return 'Game'

    def game():  # 游戏内函数
        game_filed.draw(stdscr)  # 画棋盘
        action = get_action(stdscr)  # 获取用户操作
        if action == 'Restart':  # 重置游戏
            return 'Init'
        if action == 'Exit':
            return 'Exit'
        if game_filed.move(action):  # 其他操作让其移动
            # 每次移动后判断输或者赢
            if game_filed.is_win():
                return 'Win'
        return 'Game'  # 再次返回游戏函数

    def not_game():  # 定义游戏外函数
        game_filed.draw(stdscr)  # 画棋盘
        while True:
            action = get_action(stdscr)
            if action == 'Restart':  # 重置游戏
                return 'Init'
            if action == 'Exit':  # 退出
                return 'Exit'

    status_filed = {'Init': init,
                    'Game': game,
                    'Win': not_game,
                    'GameOver': not_game
                    }
    game_filed = GameFiled(win_value=2048)

    status = 'Init'

    while status != "Exit":
        status = status_filed[status]()

curses.wrapper(main)

猜你喜欢

转载自blog.csdn.net/biu_biu_0329/article/details/80538748
da