150行Python代码实现带界面的数独游戏
作者:HoLoong 发布时间:2023-08-30 13:03:47
今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独生成由递归算法实现,由shuffle保证每次游戏都是不一样的情况,have fun;
功能列表:
图形化的数独游戏;
python实现,依赖pygame库;
随机生成游戏,每次运行都不一样;
数字填入后的正确性判断以及颜色提示;
显示剩余需填入的空格,已经操作的次数;
难度可选,通过修改需要填入的空的数量;
游戏界面
初始界面
过程中界面
运行方式
python main.py 15
这里的15表示需要填入的空格数量为15,理论上这个值越大,难度就越高,大家可以随机调整,或者设置容易、简单、困难、地狱等对应不同的值即可,很方便修改;
程序分析
界面部分
这部分很简单的通过pygame来实现,主要使用了其中的主循环、鼠标键盘监听、画矩形线条、字体、颜色控制等,理解起来很容易,对于这部分不太熟悉的同学,这样理解就好: pygame的主循环中一方面负责接收用户输入,一般就是鼠标和键盘,另一方面负责实时更新界面显示内容 ;
对于界面上各部分内容的绘制的函数封装
# 绘制背景部分,这里就是9*9的九宫格
def draw_background():
# white background
screen.fill(COLORS['white'])
# draw game board
pygame.draw.rect(screen,COLORS['black'],(0,0,300,900),5)
pygame.draw.rect(screen,COLORS['black'],(300,0,300,900),5)
pygame.draw.rect(screen,COLORS['black'],(600,0,300,900),5)
pygame.draw.rect(screen,COLORS['black'],(0,0,900,300),5)
pygame.draw.rect(screen,COLORS['black'],(0,300,900,300),5)
pygame.draw.rect(screen,COLORS['black'],(0,600,900,300),5)
# 将用户选中的各自背景改为蓝色块表示选中
def draw_choose():
pygame.draw.rect(screen,COLORS['blue'],(cur_j*100+5,cur_i*100+5,100-10,100-10),0)
# 绘制九宫格中的数字,包括本来就有的,以及用户填入的,本来就在的用灰色,用户填入的如何合法则为绿色,否则为红色,是一种提示
def draw_number():
for i in range(len(MATRIX)):
for j in range(len(MATRIX[0])):
_color = check_color(MATRIX,i,j) if (i,j) in BLANK_IJ else COLORS['gray']
txt = font80.render(str(MATRIX[i][j] if MATRIX[i][j] not in [0,'0'] else ''),True,_color)
x,y = j*100+30,i*100+10
screen.blit(txt,(x,y))
# 绘制最下方的当前空格子数量以及用户的操作数量
def draw_context():
txt = font100.render('Blank:'+str(cur_blank_size)+' Change:'+str(cur_change_size),True,COLORS['black'])
x,y = 10,900
screen.blit(txt,(x,y))
主循环中对上述函数的调用以及鼠标键盘事件处理
# 主循环,负责监听鼠标键盘时间,以及刷新界面内容,以及检查是否赢得了游戏
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
break
elif event.type == pygame.MOUSEBUTTONDOWN:
cur_j,cur_i = int(event.pos[0]/100),int(event.pos[1]/100)
elif event.type == event.type == pygame.KEYUP:
if chr(event.key) in ['1','2','3','4','5','6','7','8','9'] and (cur_i,cur_j) in BLANK_IJ:
MATRIX[cur_i][cur_j] = int(chr(event.key))
cur_blank_size = sum([1 if col==0 or col=='0' else 0 for row in MATRIX for col in row])
cur_change_size +=1
# background
draw_background()
# choose item
draw_choose()
# numbers
draw_number()
# point
draw_context()
# flip
pygame.display.flip()
# check win or not
if check_win(MATRIX_ANSWER,MATRIX):
print('You win, smarty ass!!!')
break
pygame.quit()
生成表示数独的二维数组
相对于界面部分,这部分在逻辑上要难一些,思路以递归为核心,辅以随机性,得到一个每次生成都不一致的数独游戏,生成思路简单描述如下:
遍历每个空格,填入目前为止合法的数字;
如果有数字可以填入,则继续向下一个空格;
如果没有数字可以填入,表示之前的数字有问题,则结束递归;
当递归到最后一个格子的下一个时,表示已经生成完毕,返回即可;
这个过程中对1~9这九个数字的遍历数字会经过shuffle处理,保证随机性而不是每次都得到同一个合法的数独数组;
生成过程代码
递归的一个优势是通常代码都很短,当然阅读性不强,欢迎大佬们改为循环;
def shuffle_number(_list):
random.shuffle(_list)
return _list
def check(matrix,i,j,number):
if number in matrix[i]:
return False
if number in [row[j] for row in matrix]:
return False
group_i,group_j = int(i/3),int(j/3)
if number in [matrix[i][j] for i in range(group_i*3,(group_i+1)*3) for j in range(group_j*3,(group_j+1)*3)]:
return False
return True
def build_game(matrix,i,j,number):
if i>8 or j>8:
return matrix
if check(matrix,i,j,number):
_matrix = [[col for col in row] for row in matrix]
_matrix[i][j] = number
next_i,next_j = (i+1,0) if j==8 else (i,j+1)
for _number in shuffle_number(number_list):
__matrix = build_game(_matrix,next_i,next_j,_number)
if __matrix and sum([sum(row) for row in __matrix])==(sum(range(1,10))*9):
return __matrix
return None
随机覆盖数独数组中的N个位置
matrix_all表示整个数独数组
matrix_blank表示部分被替换为0的用于显示的数组
blank_ij表示被覆盖位置的i和j
def give_me_a_game(blank_size=9):
matrix_all = build_game(matrix,0,0,random.choice(number_list))
set_ij = set()
while len(list(set_ij))<blank_size:
set_ij.add(str(random.choice([0,1,2,3,4,5,6,7,8]))+','+str(random.choice([0,1,2,3,4,5,6,7,8])))
matrix_blank = [[col for col in row] for row in matrix_all]
blank_ij = []
for ij in list(set_ij):
i,j = int(ij.split(',')[0]),int(ij.split(',')[1])
blank_ij.append((i,j))
matrix_blank[i][j] = 0
return matrix_all,matrix_blank,blank_ij
最后附上全部代码
大家也可以直接从我的 Github仓库 fork下来直接运行;
main.py:主流程+界面+执行
import sys
import pygame
from pygame.color import THECOLORS as COLORS
from build import print_matrix,give_me_a_game,check
def draw_background():
# white background
screen.fill(COLORS['white'])
# draw game board
pygame.draw.rect(screen,COLORS['black'],(0,0,300,900),5)
pygame.draw.rect(screen,COLORS['black'],(300,0,300,900),5)
pygame.draw.rect(screen,COLORS['black'],(600,0,300,900),5)
pygame.draw.rect(screen,COLORS['black'],(0,0,900,300),5)
pygame.draw.rect(screen,COLORS['black'],(0,300,900,300),5)
pygame.draw.rect(screen,COLORS['black'],(0,600,900,300),5)
def draw_choose():
pygame.draw.rect(screen,COLORS['blue'],(cur_j*100+5,cur_i*100+5,100-10,100-10),0)
def check_win(matrix_all,matrix):
if matrix_all == matrix:
return True
return False
def check_color(matrix,i,j):
_matrix = [[col for col in row]for row in matrix]
_matrix[i][j] = 0
if check(_matrix,i,j,matrix[i][j]):
return COLORS['green']
return COLORS['red']
def draw_number():
for i in range(len(MATRIX)):
for j in range(len(MATRIX[0])):
_color = check_color(MATRIX,i,j) if (i,j) in BLANK_IJ else COLORS['gray']
txt = font80.render(str(MATRIX[i][j] if MATRIX[i][j] not in [0,'0'] else ''),True,_color)
x,y = j*100+30,i*100+10
screen.blit(txt,(x,y))
def draw_context():
txt = font100.render('Blank:'+str(cur_blank_size)+' Change:'+str(cur_change_size),True,COLORS['black'])
x,y = 10,900
screen.blit(txt,(x,y))
if __name__ == "__main__":
# init pygame
pygame.init()
# contant
SIZE = [900,1000]
font80 = pygame.font.SysFont('Times', 80)
font100 = pygame.font.SysFont('Times', 90)
# create screen 500*500
screen = pygame.display.set_mode(SIZE)
# variable parameter
cur_i, cur_j = 0,0
cur_blank_size = int(sys.argv[1])
cur_change_size = 0
# matrix abount
MATRIX_ANSWER,MATRIX,BLANK_IJ = give_me_a_game(blank_size=cur_blank_size)
print(BLANK_IJ)
print_matrix(MATRIX)
# main loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
break
elif event.type == pygame.MOUSEBUTTONDOWN:
cur_j,cur_i = int(event.pos[0]/100),int(event.pos[1]/100)
elif event.type == event.type == pygame.KEYUP:
if chr(event.key) in ['1','2','3','4','5','6','7','8','9'] and (cur_i,cur_j) in BLANK_IJ:
MATRIX[cur_i][cur_j] = int(chr(event.key))
cur_blank_size = sum([1 if col==0 or col=='0' else 0 for row in MATRIX for col in row])
cur_change_size +=1
# background
draw_background()
# choose item
draw_choose()
# numbers
draw_number()
# point
draw_context()
# flip
pygame.display.flip()
# check win or not
if check_win(MATRIX_ANSWER,MATRIX):
print('You win, smarty ass!!!')
break
pygame.quit()
build.py:生成数独数组部分
import random
def print_matrix(matrix):
print('—'*19)
for row in matrix:
print('|'+' '.join([str(col) for col in row])+'|')
print('—'*19)
def shuffle_number(_list):
random.shuffle(_list)
return _list
def check(matrix,i,j,number):
if number in matrix[i]:
return False
if number in [row[j] for row in matrix]:
return False
group_i,group_j = int(i/3),int(j/3)
if number in [matrix[i][j] for i in range(group_i*3,(group_i+1)*3) for j in range(group_j*3,(group_j+1)*3)]:
return False
return True
def build_game(matrix,i,j,number):
if i>8 or j>8:
return matrix
if check(matrix,i,j,number):
_matrix = [[col for col in row] for row in matrix]
_matrix[i][j] = number
next_i,next_j = (i+1,0) if j==8 else (i,j+1)
for _number in shuffle_number(number_list):
#_matrixs.append(build_game(_matrix,next_i,next_j,_number))
__matrix = build_game(_matrix,next_i,next_j,_number)
if __matrix and sum([sum(row) for row in __matrix])==(sum(range(1,10))*9):
return __matrix
#return _matrixs
return None
def give_me_a_game(blank_size=9):
matrix_all = build_game(matrix,0,0,random.choice(number_list))
set_ij = set()
while len(list(set_ij))<blank_size:
set_ij.add(str(random.choice([0,1,2,3,4,5,6,7,8]))+','+str(random.choice([0,1,2,3,4,5,6,7,8])))
matrix_blank = [[col for col in row] for row in matrix_all]
blank_ij = []
for ij in list(set_ij):
i,j = int(ij.split(',')[0]),int(ij.split(',')[1])
blank_ij.append((i,j))
matrix_blank[i][j] = 0
return matrix_all,matrix_blank,blank_ij
number_list = [1,2,3,4,5,6,7,8,9]
matrix = [([0]*9) for i in range(9)]
if __name__ == "__main__":
print_matrix(build_game(matrix,0,0,random.choice(number_list)))
总结
如果刻意减少代码的话,实际应该控制在100行以内,这也充分表达了python的强大,确实可以在很短的时间内完成一些看似复杂的工作,这个例子供一些同学上手python个人觉得还是不错的,没有太复杂的用法,对界面开发有一点点了解,对递归有一些理解基本就能完全掌握这份代码,希望大家玩的开心,挑战一下50个空格呗,哈哈,反正我没通过,太难了。。。。
最后
大家可以到我的Github上看看有没有其他需要的东西,目前主要是自己做的机器学习项目、Python各种脚本工具、有意思的小项目以及Follow的大佬、Fork的项目等:
https://github.com/NemoHoHaloAi
作者:Ho Loong
Github:https://github.com/NemoHoHaloAi
Kaggle:https://www.kaggle.com/holoong9291
来源:https://www.cnblogs.com/helongBlog/p/12627863.html
猜你喜欢
- Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0。zfill()方法语法:str.zfill(width)参
- 前言和Word、Excel承载数据的能力相比,PPT的应用重点在于表演。比如一场发布会、一场演说、一次产品展示、一次客户沟通&hel
- 本文内容速览1、绘图数据准备还是使用鸢尾花iris数据集#导入本帖要用到的库,声明如下:import matplotlib.pyplot a
- 前言小伙伴a,b,c围着吃火锅,当菜上齐了,请客的主人说:开吃!,于是小伙伴一起动筷子,这种场景如何实现Event(事件)Event(事件)
- java JSP开发之Spring中Bean的使用在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例
- 本文实例为大家分享了opencv实现双边滤波的具体代码,供大家参考,具体内容如下1、2D卷积#!/usr/bin/env python3#
- 豆瓣镜像源:https://pypi.douban.com/simple/file >> setting最后点击OK即可PyCh
- python可以返回多个值,确实挺方便函数里的return只能返回一个值,但是返回类型是没是限制的因此,我们可以“返回一个 tuple类型,
- 本文实例讲述了Python list列表中删除多个重复元素操作。分享给大家供大家参考,具体如下:我们以下面这个list为例,删除其中所有值为
- 最近需要用Python写一个简易通讯录,但是对于数据存储很发愁。大家都知道,使用 Python 中的列表和字典进行存储数据是很不靠谱的,所以
- 区别:xx:公有变量,所有对象都可以访问;xxx:双下划线代表着是系统定义的名字。__xxx:双前置下划线,避免与子类中的属性命名冲突,无法
- 内容摘要:本文介绍了使用SQL语句修改数据记录的两种方法,一是使用rs.update,二是使用conn.Execute(sql),相信对初学
- Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Djang
- 1. 引入messages模块from django.contrib import messages2. 把messages写入view中@
- 这篇文章主要介绍了Python远程开发环境部署与调试过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 五、XML带来的好处 (1)更有意义的搜索 数据可被XML唯一的标识。没有XML,搜索软件必须了解每个数据库是如何构建的。这实际上是不可能的
- 才发现做了这么多的博客和视频,居然从来没有系统地做过分类网络,做一个科学的分类网络,对身体好。源码下载分类网络的常见形式常见的分类网络都可以
- 1、800*600下,网页宽度保持在778以内,就不会出现水平滚动条,高度则视版面和内容决定。2、1024*768下,网页宽度保持在1002
- 一,斑马线的数据集数据集的构成:testtrainzebra corssing:56zebra corssing:168other:54ot
- 如下所示:logprobs.new_zeros(logprobs.size())pytorch 0.4版本中用到的新建一个与logprobs