• 用Python写一个贪吃蛇


    最近在学Python,想做点什么来练练手,命令行的贪吃蛇一般是C的练手项目,但是一时之间找不到别的,就先做个贪吃蛇来练练简单的语法。

      由于Python监听键盘很麻烦,没有C语言的kbhit(),所以这条贪吃蛇不会自己动,运行效果如下:

      

    要求:用#表示边框,用*表示食物,o表示蛇的身体,O表示蛇头,使用wsad来移动

    Python版本:3.6.1

    系统环境:Win10

    类:

      board:棋盘,也就是游戏区域

      snake:贪吃蛇,通过记录身体每个点来记录蛇的状态

      game:游戏类

      本来还想要个food类的,但是food只需要一个坐标,和一个新建,所以干脆使用list来保存坐标,新建food放在game里面,从逻辑上也没有太大问题

    源码

    # Write By Guobao
    # 2017/4//7
    #
    # 贪吃蛇
    # 用#做边界,*做食物,o做身体和头部
    # python 3.6.1
    
    import copy
    import random
    import os
    import msvcrt
    
    # the board class, used to put everything
    class board:
    
        __points =[]
    
        def __init__(self):
            self.__points.clear()
            for i in range(22):
                line = []
                if i == 0 or i == 21:
                    for j in range(22):
                        line.append('#')
                else:
                    line.append('#')
                    for j in range(20):
                        line.append(' ')
                    line.append('#')
                self.__points.append(line)
    
        def getPoint(self, location):
            return self.__points[location[0]][location[1]]
    
        def clear(self):
            self.__points.clear()
            for i in range(22):
                line = []
                if i == 0 or i == 21:
                    for j in range(22):
                        line.append('#')
                else:
                    line.append('#')
                    for j in range(20):
                        line.append(' ')
                    line.append('#')
                self.__points.append(line)
    
        def put_snake(self, snake_locations):
            # clear the board
            self.clear()
    
            # put the snake points
            for x in snake_locations:
                self.__points[x[0]][x[1]] = 'o'
    
            # the head
            x = snake_locations[len(snake_locations) - 1]
            self.__points[x[0]][x[1]] = 'O'
    
        def put_food(self, food_location):
            self.__points[food_location[0]][food_location[1]] = '*'
    
        def show(self):
            os.system("cls")
            for i in range(22):
                for j in range(22):
                    print(self.__points[i][j], end='')
                print()
    
    # the snake class
    class snake:
        __points = []
    
        def __init__(self):
            for i in range(1, 6):
                self.__points.append([1, i])
    
        def getPoints(self):
            return self.__points
    
        # move to the next position
        # give the next head
        def move(self, next_head):
            self.__points.pop(0)
            self.__points.append(next_head)
    
        # eat the food
        # give the next head
        def eat(self, next_head):
            self.__points.append(next_head)
    
        # calc the next state
        # and return the direction
        def next_head(self, direction='default'):
    
            # need to change the value, so copy it
            head = copy.deepcopy(self.__points[len(self.__points) - 1])
    
            # calc the "default" direction
            if direction == 'default':
                neck = self.__points[len(self.__points) - 2]
                if neck[0] > head[0]:
                    direction = 'up'
                elif neck[0] < head[0]:
                    direction = 'down'
                elif neck[1] > head[1]:
                    direction = 'left'
                elif neck[1] < head[1]:
                    direction = 'right'
    
            if direction == 'up':
                head[0] = head[0] - 1
            elif direction == 'down':
                head[0] = head[0] + 1
            elif direction == 'left':
                head[1] = head[1] - 1
            elif direction == 'right':
                head[1] = head[1] + 1
            return head
    
    # the game
    class game:
    
        board = board()
        snake = snake()
        food = []
        count = 0
    
        def __init__(self):
            self.new_food()
            self.board.clear()
            self.board.put_snake(self.snake.getPoints())
            self.board.put_food(self.food)
    
        def new_food(self):
            while 1:
                line = random.randint(1, 20)
                column = random.randint(1, 20)
                if self.board.getPoint([column, line]) == ' ':
                    self.food = [column, line]
                    return
    
        def show(self):
            self.board.clear()
            self.board.put_snake(self.snake.getPoints())
            self.board.put_food(self.food)
            self.board.show()
    
    
        def run(self):
            self.board.show()
    
            # the 'w a s d' are the directions
            operation_dict = {b'w': 'up', b'W': 'up', b's': 'down', b'S': 'down', b'a': 'left', b'A': 'left', b'd': 'right', b'D': 'right'}
            op = msvcrt.getch()
    
            while op != b'q':
                if op not in operation_dict:
                    op = msvcrt.getch()
                else:
                    new_head = self.snake.next_head(operation_dict[op])
    
                    # get the food
                    if self.board.getPoint(new_head) == '*':
                        self.snake.eat(new_head)
                        self.count = self.count + 1
                        if self.count >= 15:
                            self.show()
                            print("Good Job")
                            break
                        else:
                            self.new_food()
                            self.show()
    
                    # 反向一Q日神仙
                    elif new_head == self.snake.getPoints()[len(self.snake.getPoints()) - 2]:
                        pass
    
                    # rush the wall
                    elif self.board.getPoint(new_head) == '#' or self.board.getPoint(new_head) == 'o':
                        print('GG')
                        break
    
                    # normal move
                    else:
                        self.snake.move(new_head)
                        self.show()
                op = msvcrt.getch()
    
    game().run()

    笔记:

      1.Python 没有Switch case语句,可以利用dirt来实现

      2.Python的=号是复制,复制引用,深复制需要使用copy的deepcopy()函数来实现

      3.即使在成员函数内,也需要使用self来访问成员变量,这和C++、JAVA很不一样

    2017.4.11 更新

      完成了贪吃蛇之后,我开始打一个简单的学生信息管理系统,内容简单,数据量小,但是可以用上MVC架构,又可以更好的训练。过程中发现自己在贪吃蛇中有一个致命的问题,虽然在贪吃蛇中,这个问题并不会影响结果。

      先看board类中的部分代码:

     1 class board:
     2 
     3     __points =[]
    4 # 后面不重要

    咋一看没有问题,但是看初始化__point的位置,并不是在__init__()中第一次初始化,这种情况下,__point是一个类变量,而不是一个成员变量,如果__point是一个不可变的类型(如整形),那可能不会看出什么影响,但是当它是一个可变的类型,如list,就会有很大的问题,看我在命令行上的试验:

    ①整形例子

    到此为止,和我一开始的想法没有冲突,请看下面:

    惊讶的发现可以直接通过类名来访问到num变量,而且还一直保持着最初的值,还能变

    ②list例子

    试验的时候心理活动:嗯→很正常→就该这样→卧槽???

    这时候可以再来一句:

    分析:整形例子中,当我修改num的值,其实是让num指向了新的内存,所以会有c1,c2有着各自的num值;

    而在list例子中,当我修改cc的值,修改的是cc指向的内存的值,cc一直指向同一个内存

    个人理解:不论哪一个例子,都是在复制类变量,所以会有这种现象

    贪吃蛇中,因为Snake和board我都只有一个实例,所以没有明显的问题。

    与此相关可以看这篇博客:http://www.cnblogs.com/duanv/p/5947525.html

    函数的默认参数中也有相似的问题,可以看:http://blog.jobbole.com/42706/#article-comment

  • 相关阅读:
    未让换行符弄错了数据
    REPLICATE
    内存 商业智能
    sql
    PageMethods介绍
    在ASP.NET AJAX中如何判断浏览器及计算其宽高
    用JavaScript实现网页图片等比例缩放
    js技巧收集(200多个)(转自:asp.net中文俱乐部)
    C#调用ORACLE存储过程返回结果集及函数
    Using PageMethods to access Session data
  • 原文地址:https://www.cnblogs.com/guobaoxu/p/6680512.html
Copyright © 2020-2023  润新知