150+行Python代码实现带界面的数独游戏!益智烧脑了解一下!

150行代码实现图形化数独游戏

Github地址 ,欢迎各位大佬们fork、star啥的,感谢;

今天闲着没事干,以前做过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. 遍历每个空格,填入目前为止合法的数字;
  2. 如果有数字可以填入,则继续向下一个空格;
  3. 如果没有数字可以填入,表示之前的数字有问题,则结束递归;
  4. 当递归到最后一个格子的下一个时,表示已经生成完毕,返回即可;
  5. 这个过程中对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的项目等:

源码获取加群哈:850591259

原文地址:https://www.cnblogs.com/Py1233/p/12698767.html

时间: 2024-08-02 21:11:12

150+行Python代码实现带界面的数独游戏!益智烧脑了解一下!的相关文章

150+行Python代码实现带界面的数独游戏

150行代码实现图形化数独游戏 Github地址,欢迎各位大佬们fork.star啥的,感谢: 今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独生成由递归算法实现,由shuffle保证每次游戏都是不一样的情况,have fun: 功能列表: 图形化的数独游戏: python实现,依赖pygame库: 随机生成游戏,每次运行都不一样: 数字填入后的正确性判断以及颜色提示: 显示剩余需填入的空格,已经操作的次数: 难度可选,通过修改需要填入的空

50 行 Python 代码,带你追到最心爱的人

程序员世纪难题 人们一提到程序员第一反应就是:我知道!他们工资很高啊!但大部分都是单身狗,不懂得幽默风趣,只是每天穿格子 polo 衫的宅男一个.甚至程序员自己也这样形容自己:钱多话少死的早.程序员总是爱这样黑自己.大部分的程序员都是单身这是一个不争的事实,也是程序员一个世纪难题.但程序员并不是大部分都非常的呆板,相反我认知的很多程序员都非常幽默风趣.会利用自己所学的知识,为生活,为自己心爱的人带来一些惊喜. 今天我就教大家如何做一个风趣又不失逼格的 python 程序.利用 python 每天

Python学习:50 行 Python 代码,带你追到最心爱的人

程序员世纪难题 人们一提到程序员第一反应就是:我知道!他们工资很高啊!但大部分都是单身狗,不懂得幽默风趣,只是每天穿格子 polo 衫的宅男一个.甚至程序员自己也这样形容自己:钱多话少死的早.程序员总是爱这样黑自己.大部分的程序员都是单身这是一个不争的事实,也是程序员一个世纪难题.但程序员并不是大部分都非常的呆板,相反我认知的很多程序员都非常幽默风趣.会利用自己所学的知识,为生活,为自己心爱的人带来一些惊喜. 今天我就教大家如何做一个风趣又不失逼格的 python 程序.利用 python 每天

200行Python代码实现2048

200行Python代码实现2048 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌面上的程序: LX终端(LXTerminal): Linux命令行终端,打开后会进入Bash环境,可以使用Linux命令 GVim:非常好用的编辑器,最简单的用法可以参考课程Vim编辑器 3. 环境使用 使用GVim编辑器输入实验所需的代码及文件,使用LX终端(LXTerminal)运行所需命令进行操

基于Tkinter用50行Python代码实现简易计算器

Tkinter一般是python自带的,所以代码不需要其他组件,本程序是在python2.7版本实现的. 主要涉及了tkinter的使用,函数定义和调用,匿名函数的使用,类成员函数定义等python基础知识,适合新手学习. 代码如下: from Tkinter import * #创建横条型框架 def frame(root, side): w = Frame(root) w.pack(side = side, expand = YES, fill = BOTH) return w #创建按钮

一起来写2048(160行python代码)

前言: Life is short ,you need python. --Bruce Eckel 我与2048的缘,不是缘于一个玩家,而是一次,一次,重新的ACM比赛.四月份校赛初赛,第一次碰到2048,两周后决赛再次遇到2048,后来五月份的广东省赛,又出现了2048.在这三次比赛过程中,我一次2048都没玩过..全靠队友的解释,直到昨天,我突然想起写个2048吧,于是下了个2048玩了几盘,之后就開始用python来写了,心想就不写界面了,为了简洁. 我对python并不熟悉,可是我在之前

20行Python代码爬取王者荣耀全英雄皮肤

引言 王者荣耀大家都玩过吧,没玩过的也应该听说过,作为时下最火的手机MOBA游戏,咳咳,好像跑题了.我们今天的重点是爬取王者荣耀所有英雄的所有皮肤,而且仅仅使用20行Python代码即可完成. 准备工作 爬取皮肤本身并不难,难点在于分析,我们首先得得到皮肤图片的url地址,话不多说,我们马上来到王者荣耀的官网: 我们点击英雄资料,然后随意地选择一位英雄,接着F12打开调试台,找到英雄原皮肤的图片地址: 接着,我们切换一下英雄的皮肤,会发现图片地址没有明显的变化,只是最后的数字序号改变了,我们将两

10 行 Python 代码实现模糊查询/智能提示

10 行 Python 代码实现模糊查询/智能提示 1.导语: 模糊匹配可以算是现代编辑器(如 Eclipse 等各种 IDE)的一个必备特性了,它所做的就是根据用户输入的部分内容,猜测用户想要的文件名,并提供一个推荐列表供用户选择. 样例如下: Vim (Ctrl-P) Sublime Text (Cmd-P) '模糊匹配'这是一个极为有用的特性,同时也非常易于实现. 2.问题分析: 我们有一堆字符串(文件名)集合,我们根据用户的输入不断进行过滤,用户的输入可能是字符串的一部分.我们就以下面的

10行python代码实现约瑟夫问题

什么是约瑟夫问题? 约瑟夫问题是一个有趣的数学游戏,游戏规则如下: 1.N个人围成一个圈,编号从1开始,依次到N. 2.编号为M的游戏参与者开始报数,报数从1开始,后面的人报数接龙,直到K为止,报数为K的人将出局. 3.出局者的下一个玩家接着从1开始报数,如此循环,直到剩下一个玩家时游戏结束,这个玩家就是游戏获胜者. 那么问题来了,哪个编号是游戏获胜者呢? 下面通过简单的几行python代码来解决这个问题: #!/usr/bin/env python # Joseph Problem def j