用python写数字_用python 写游戏之数字华容道
当初对这个游戏颇有印象还是在最强大脑节目上面,何猷君以几十秒就完成了这个游戏。写2048游戏的时候,又想起了这个游戏,想着来研究一下。
游戏玩法
用尽量少的步数,尽量短的时间,将棋盘上的数字方块,按照从左到右、从上到下的顺序重新排列整齐。
效果图
游戏操作方式
第一种是通过键盘的按键来移动数字,比如按上键,需要做的操作是把13移上去。
第二种是通过鼠标点击13,13移上去。
不论采取哪种操作方式,可移动数字只能往固定的方向移动,做的操作都是把13和0位置互换即可。考虑到操作性,我们选用鼠标点击这种更为简单的操作方式。
自定义棋盘
定义棋盘的大小:4 * 4, 当然我把这个棋盘的大小做成了可自定义的属性,如果你觉得4*4没有挑战性, 还可以5 * 5 、6 * 6等等,下面以4 * 4为例做介绍。
看过我之前2048那篇文章的,一定明白接下来应该怎么做。没错,忽略棋盘背景,把棋盘看作一个4*4的二维矩阵,空白格用数字0填充:
接下来,我们应该考虑的问题是,数字的移动该怎么做?看上图的状态,此时只有0的上,右,下三格可以移动,别的都不能动。这里大家可以停顿一下考虑考虑,看看能不能找到一个移动的算法方案?
数字移动
通过数字在二维矩阵中的下标来表示数字的位置,比如8的位置是第一行、第一列即(0,0)(列表元素的下标从0开始), 第二行、第一列是(1, 0)。
上图中,13的坐标是(3,0)。当鼠标点击13时,13和0交换位置,13的位置变成(2,0)。从(3,0)到(2,0)可以看作加了一个矢量(-1,0)。那如果点击不是13, 而是(1,0)位置的3,发生的变化就是(1,0)变成(2,0),矢量是(1,0),同理(2,1)位置移到(2, 0) 矢量是(0, -1),我们得到了一个上下左右的矢量集合, 上(-1, 0), 下(1, 0), 左(0, -1), 右(0, 1) 。
游戏逻辑
游戏的逻辑就变成了,当我们随便点击一个数字时,判断该数字的位置分别在加上4个矢量后的位置上的数字是否为0,是0,就把两个位置的数字交换,不是0,不做任何变动即可。
为什么会变成这样,因为一个数字可移动的方向只有0个或者1个。
数据矩阵存放
缕清了游戏的逻辑,那在记录数据二维矩阵时,就需要记录每个数字在矩阵中的位置下标。所以我们不打算采用2048中的矩阵的记录方式,而是采用python中的dict, 把位置作为key,把数字作为value。
整个操作的逻辑就是,当我们鼠标点击时,首先获取点击的坐标(x, y),通过坐标(x, y),获取到点击了哪一行,哪一列,得到(row_index, col_index)。然后把(row_index, col_index)分别加四个矢量, 判断加矢量后的位置(row_index+vector, col_index+vector) 在不在上图中的dict中且值是否等于0, 如果等于0, 使(row_index, col_index) 和 (row_index+vector, col_index+vector)的值互换。
如何判断游戏胜利?
判断dict中的最后一位是否为0,且0之前的所有值,是否按照顺序排序, 即为胜利。字典考虑到需要顺序,所以可以采用collections库中的OrderedDict 有序字典的数据格式。
开撸代码定义全局变量
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import random
from collections import OrderedDict
import pygame
FPS = 60
SHAPE = 4 # 棋盘shape
CELL_SIZE = 100 # 方格大小
CELL_GAP_SIZE = 10 # 方格间距
MARGIN = 10 # 方格的margin
PADDING = 10 # 方格的padding
SCREEN_WIDTH = (CELL_SIZE + MARGIN) * SHAPE + MARGIN # 屏幕宽度
SCREEN_HEIGHT = (CELL_SIZE + MARGIN) * SHAPE + MARGIN # 屏幕高度
BACKGROUND_COLOR = "#92877d" # 背景颜色
BACKGROUND_EMPTY_CELL_COLOR = "#9e948a" # 空方格颜色
BACKGROUND_CELL_COLOR = "#edc22e" # 方格颜色
# 定义两个元组相加
def tuple_add(t1, t2):
return (t1[0] + t2[0], t1[1] + t2[1])
2. 算法逻辑,初始化棋盘数据,先生成正确的序列,然后随机移动一千次。如果采用随机序列,有可能游戏无解。
class Logic:
def __init__(self, shape=4):
self.shape = int(shape) if shape > 2 else 4 # 初始化形状
self.tiles = OrderedDict() # 初始化数据
self.neighbors = [ # 定义方向矢量
[1, 0], # 下
[-1, 0], # 上
[0, 1], # 右
[0, -1], # 左
]
self.click_dict = {'x': {}, 'y': {}} # 定义鼠标点击坐标转换下标的数据
self.init_load() # 初始化加载
def init_load(self):
count = 1
# 生成正确的序列
for x in range(self.shape):
for y in range(self.shape):
mark = tuple([x, y])
self.tiles[mark] = count
count += 1
self.tiles[mark] = 0
for count in range(1000): # 随机移动一千次
neighbor = random.choice(self.neighbors)
spot = tuple_add(mark, neighbor)
if spot in self.tiles:
number = self.tiles[spot]
self.tiles[spot] = 0
self.tiles[mark] = number
mark = spot
self.init_click_dict()
def init_click_dict(self):
# 初始化点击坐标转换下标的数据
for r in range(self.shape):
for c in range(self.shape):
x = MARGIN * (c + 1) + c * CELL_SIZE
x1 = x + CELL_SIZE
click_x = tuple(range(x, x1))
self.click_dict['x'][click_x] = c
y = MARGIN * (r + 1) + r * CELL_SIZE
y1 = y + CELL_SIZE
click_y = tuple(range(y, y1))
self.click_dict['y'][click_y] = r
def move(self, mark):
# 移动数据
for neighbor in self.neighbors:
spot = tuple_add(mark, neighbor)
if spot in self.tiles and self.tiles[spot] is 0:
self.tiles[spot], self.tiles[mark] = self.tiles[
mark], self.tiles[spot]
break
def click_to_move(self, x, y):
# 点击移动
x1 = None
for k, v in self.click_dict['x'].items():
if x in k:
x1 = v
if x1 is None:
return
y1 = None
for k, v in self.click_dict['y'].items():
if y in k:
y1 = v
if y1 is None:
return
self.move((y1, x1))
def is_win(self):
# 游戏结束判定
if self.tiles[(self.shape - 1, self.shape - 1)] is not 0:
return False
values = list(self.tiles.values())
for index in range(values.__len__() - 1):
if index + 1 != values[index]:
return False
return True
3. 初始化游戏和画数字的函数
def init_game():
# 初始化游戏
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('数字华容道 -- 0')
return screen
def draw_num(logic, screen):
for r in range(logic.shape):
for c in range(logic.shape):
num = logic.tiles[(r, c)]
if num is not 0:
color = pygame.Color(BACKGROUND_CELL_COLOR)
else:
color = pygame.Color(BACKGROUND_EMPTY_CELL_COLOR)
x = MARGIN * (c + 1) + c * CELL_SIZE
y = MARGIN * (r + 1) + r * CELL_SIZE
pygame.draw.rect(screen, color, (x, y, CELL_SIZE, CELL_SIZE))
if num is not 0:
font_size = int((CELL_SIZE - PADDING) / 1.3)
font = pygame.font.SysFont('arialBlod', font_size)
font_width, font_height = font.size(str(num))
screen.blit(font.render(str(num), True, (255, 255, 255)),
(x + (CELL_SIZE - font_width) / 2, y +
(CELL_SIZE - font_height) / 2 + 5))
4. 监控事件和游戏胜利事件
def press(is_game_over, logic, COUNT, counts):
for event in pygame.event.get():
if event.type == COUNT and not is_game_over: # 设置定时器,记录时间
counts += 1
pygame.display.set_caption('数字华容道 -- {}'.format(counts))
if event.type == pygame.QUIT: # 点击关闭按钮退出
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP: # 鼠标点击
if event.button == 1 and not is_game_over:
x, y = event.pos
logic.click_to_move(int(x), int(y)) # 点击移动
elif event.type == pygame.KEYDOWN and event.key == 13: # 游戏结束,回车重开
return True
if COUNT:
return counts
def game_win(screen, logic, clock, text='You Win!'):
font = pygame.font.SysFont('Blod', int(SCREEN_WIDTH / 4))
font_width, font_height = font.size(str(text))
while True:
if press(True, logic, None, None):
break
screen.fill(pygame.Color(BACKGROUND_COLOR))
draw_num(logic, screen)
screen.blit(font.render(str(text), True, (0, 0, 0)),
((SCREEN_WIDTH - font_width) / 2,
(SCREEN_HEIGHT - font_height) / 2))
pygame.display.update()
clock.tick(FPS)
5. 主函数
def main():
screen = init_game()
clock = pygame.time.Clock()
logic = Logic(SHAPE)
COUNT = pygame.USEREVENT + 1
pygame.time.set_timer(COUNT, 1000)
seconds = 0 # 记录时间
while True:
if logic.is_win(): # 判断游戏是否胜利
break
seconds = press(False, logic, COUNT, seconds) # 监控按键
screen.fill(pygame.Color(BACKGROUND_COLOR)) # 填充背景
draw_num(logic, screen) # 画数字
pygame.display.update()
clock.tick(FPS)
game_win(screen, logic, clock, text='Time:' + str(seconds))
if __name__ == "__main__":
while True:
main()
200行左右完成。
游戏运行
左上角有记录游戏时间。打代码的shy:用Python 写游戏之 2048zhuanlan.zhihu.com打代码的shy--用python写游戏系列github.com
初来乍到,请多关照。
用python写数字_用python 写游戏之数字华容道相关推荐
- python 网页编程_通过Python编程检索网页
python 网页编程 The internet and the World Wide Web (WWW), is probably the most prominent source of info ...
- python 时间序列预测_使用Python进行动手时间序列预测
python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...
- python 概率分布模型_使用python的概率模型进行公司估值
python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...
- java 分裂数字_分裂的补充:超越数字,打印物理可视化
java 分裂数字 As noted in my earlier Nightingale writings, color harmony is the process of choosing colo ...
- python写金字塔_金字塔python开发手册
python API 基本方法 编写策略过程中所需要使用的基本函数.其中init和handle_bar是必须实现的两个方法,其余是可选择实现的方法. init (必须实现) init(context) ...
- 用python读取股票价格_使用Python写一个量化股票提醒系统
大家在没有阅读本文之前先看下python的基本概念, Python是一种解释型.面向对象.动态数据类型的高级程序设计语言. Python由Guido van Rossum于1989年底发明,第一个公开 ...
- python写炒股软件_使用Python写一个量化股票提醒系统
大家在没有阅读本文之前先看下python的基本概念, Python是一种解释型.面向对象.动态数据类型的高级程序设计语言. Python由Guido van Rossum于1989年底发明,第一个公开 ...
- python 写命令行界面_使用Python进行命令行界面编程?
在本节中,我们将使用python开发命令行界面.但是在我们深入研究程序之前,让我们首先了解命令行. 由于存在计算机程序,因此一直在使用命令行,并且命令行是基于命令构建的.命令行程序是从Shell或命令 ...
- python七段数码管绘制单个数字_使用Python的turtle库实现七段数码管绘制
七段数码管绘制: 七段数码管是由7段数码管拼接而成,每段有亮或不亮两种情况,改进的七段数码管还包括一个小数点位置. 七段数码管能形成2^7=128种状态,其中部分状态能够显示易于人们理解的数字或字母含 ...
- python中八进制_在Python中以八进制格式输入数字
python中八进制 Syntax to convert octal value to an integer (decimal format), 将八进制值转换为整数(十进制格式)的语法, int(o ...
最新文章
- java中全大写字符_Java 大写字符串中的字符
- 威驰fs高配和低配有什么区别_“电子手刹”和“机械手刹”的区别有多大?很多车主不清楚...
- 安川最小巧机器人_2020工博会,安川展品前瞻(机器人篇)
- 平台型时间信号强度曲线_哥测的不是BET,是氮气等温吸脱附曲线
- Rclone for Android – 云服务/网盘文件管理工具 Rclone 的 Android 客户端
- 你真的了解分层架构吗?——写给被PetShop毒害的朋友们 (转)
- 电商商城系统活动设计
- 万兆网卡驱动_家庭基础万兆网络——最简单的方案
- ASM磁盘的添加与删除
- js基础知识汇总12
- win7开机动画怎么换
- 51单片机lcd1602显示(模块)
- 传统人工势场法---经典算法
- windows10安装NVIDIA显卡驱动+cuda10.0教程
- aliddns ipv6_python脚本实现ipv6的ddns功能
- 【ACM- OJ】《六度分离》C++
- 物联网卡零售应用的真实案例
- Python和R的GUI图形化编程与用户界面
- 无人机与卡车联合配送 - README
- form表单AJAX提交
热门文章
- Windows 10截屏动画失效怎么恢复?
- TCP/IP常见英文缩写释义
- 病毒周报(071029至071104)
- 感光电路板制作(转收藏)
- 牛客c语言数组,牛客网学习笔记 - C/C++
- uni 根目录路径_如何解决uniapp图片路径错误问题
- php mysql用户登录_php mysql实现用户登录功能的代码示例
- windows失败计算机关闭,win10电脑关机失败怎么办|win10系统正确关机的详细方法
- 3gpp协议_【5G学习笔记】3GPP 5G协议分类清单大全
- zippo油和zorro油的区别_干式和油侵式变压器的概念和区别