• python实现简易数独小游戏


    起源

    既然“数独”有一个字是“数”,人们也往往会联想到数学,那就不妨从大家都知道的数学家欧拉说起,但凡想了解数独历史的玩家在网络、书籍中搜索时,共同会提到的就是欧拉的“拉丁方块(Latin square)”。

    拉丁方块的规则:每一行(Row)、每一列(Column)均含1-N(N即盘面的规格),不重复。这与前面提到的标准数独非常相似,但少了一个宫的规则

    近代发展

    数独起源于18世纪初瑞士数学家欧拉等人研究的拉丁方阵(Latin Square)。19世纪80年代,一位美国的退休建筑师格昂斯(Howard Garns)根据这种拉丁方阵发明了一种填数趣味游戏,这就是数独的雏形。20世纪70年代,人们在美国纽约的一本益智杂志《Math Puzzles and Logic Problems》上发现了这个游戏,当时被称为填数字(Number Place),这也是公认的数独最早的见报版本。1984年一位日本学者将其介绍到了日本,发表在Nikoli公司的一本游戏杂志上,当时起名为“数字は独身に限る”(すうじはどくしんにかぎる),就改名为“数独”(すうどく),其中“数”(すう)是数字的意思,“独”(どく)是唯一的意思。后来一位前任香港高等法院的新西兰籍法官高乐德(Wayne Gould)在1997年3月到日本东京旅游时,无意中发现了 [2]  。他首先在英国的《泰晤士报》上发表,不久其他报纸也发表,很快便风靡全英国,之后他用了6年时间编写了电脑程序,并将它放在网站上(这个网站也就是著名的数独玩家论坛),后来因一些原因,网站被关闭,幸好数独大师Glenn Fowler恢复了数据,玩家论坛有了新处所。在90年代国内就有部分的益智类书籍开始刊登,南海出版社在2005年出版了《数独1-2》,随后日本著名数独制题人西尾彻也的《数独挑战》也由辽宁教育出版社出版。《北京晚报》、《扬子晚报》、《羊城晚报》、《新民晚报》、《成都商报》等等报纸媒体也先后刊登了数独游戏。

    基础解法

    排除法(摒除法)

    摒除法:用数字去找单元内唯一可填空格,称为摒除法,数字可填唯一空格称为排除法 (Hidden Single)。

    根据不同的作用范围,摒余解可分为下述三种:

    数字可填唯一空格在「宫」单元称为宫排除(Hidden Single in Box),也称宫摒除法。

    数字可填唯一空格在「行」单元称为行排除法(Hidden Single in Row),也称行摒除法。

    数字可填唯一空格在「列」单元称为列排除法(Hidden Single in Column),也称列摒除法。

    唯一余数法

    唯一余数法:用格位去找唯一可填数字,称为余数法,格位唯一可填数字称为唯余解(Naked Single)。余数法是删减等位群格位(Peer)已出现的数字的方法,每一格位的等位群格位有 20 个

     

    完整代码如下:

    1. import random
    2. import math
    3. import pygame
    4. matrix = []
    5. sds = []
    6. def get_random_unit():
    7. _num_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    8. random.shuffle(_num_list)
    9. return _num_list
    10. def print_grid(arr):
    11. for i in range(9):
    12. sds.append(arr[i])
    13. def get_row(row):
    14. row_arr = []
    15. for v in matrix[row]:
    16. if v == 0:
    17. continue
    18. row_arr.append(v)
    19. return row_arr
    20. def get_col(col):
    21. col_arr = []
    22. for i in range(9):
    23. val = matrix[i][col]
    24. if val == 0:
    25. continue
    26. col_arr.append(matrix[i][col])
    27. return col_arr
    28. def get_block(num):
    29. col_arr = []
    30. seq = num % 3
    31. col_end = 9 if seq == 0 else seq * 3
    32. row_end = int(math.ceil(num / 3) * 3)
    33. for i in range(row_end - 3, row_end):
    34. for j in range(col_end - 3, col_end):
    35. val = matrix[i][j]
    36. if val != 0:
    37. col_arr.append(matrix[i][j])
    38. return col_arr
    39. def get_block_seq(row, col):
    40. col_seq = int(math.ceil((col + 0.1) / 3))
    41. row_seq = int(math.ceil((row + 0.1) / 3))
    42. return 3 * (row_seq - 1) + col_seq
    43. def get_enable_arr(row, col):
    44. avail_arr = get_random_unit()
    45. seq = get_block_seq(row, col)
    46. block = get_block(seq)
    47. row = get_row(row)
    48. col = get_col(col)
    49. unable_arr = list(set(block + row + col))
    50. for v in unable_arr:
    51. if v in avail_arr:
    52. avail_arr.remove(v)
    53. return avail_arr
    54. def main():
    55. can_num = {}
    56. count = 0
    57. for i in range(9):
    58. matrix.append([0] * 9)
    59. num_list = get_random_unit()
    60. for row in range(3):
    61. for col in range(3):
    62. matrix[row][col] = num_list.pop(0)
    63. num_list = get_random_unit()
    64. for row in range(3, 6):
    65. for col in range(3, 6):
    66. matrix[row][col] = num_list.pop(0)
    67. num_list = get_random_unit()
    68. for row in range(6, 9):
    69. for col in range(6, 9):
    70. matrix[row][col] = num_list.pop(0)
    71. box_list = []
    72. for row in range(9):
    73. for col in range(9):
    74. if matrix[row][col] == 0:
    75. box_list.append({'row': row, 'col': col})
    76. i = 0
    77. while i < len(box_list):
    78. count += 1
    79. position = box_list[i]
    80. row = position['row']
    81. col = position['col']
    82. key = '%dx%d' % (row, col)
    83. if key in can_num:
    84. enable_arr = can_num[key]
    85. else:
    86. enable_arr = get_enable_arr(row, col)
    87. can_num[key] = enable_arr
    88. if len(enable_arr) <= 0:
    89. i -= 1
    90. if key in can_num:
    91. del (can_num[key])
    92. matrix[row][col] = 0
    93. continue
    94. else:
    95. matrix[row][col] = enable_arr.pop()
    96. i += 1
    97. print_grid(matrix)
    98. if __name__ == "__main__":
    99. main()
    100. # --------------------华丽の分割线--------------------
    101. ac_num = 0
    102. pausE = True
    103. difficulty = 3
    104. from tkinter import *
    105. from tkinter import ttk
    106. import time
    107. import pygame as py
    108. def setDiff(difF):
    109. global difficulty
    110. global diff
    111. try:
    112. difficulty = int(difF)
    113. diff.destroy()
    114. except:
    115. pass
    116. diff = Tk()
    117. diff.title('难度选择')
    118. diff.geometry('300x90')
    119. diff.resizable(0,0)
    120. Label(diff,text='选择你要挑战的难度!(0~9)',font=('微软雅黑',9)).pack()
    121. cmb = ttk.Combobox(diff)
    122. cmb.pack()
    123. cmb['value'] = (0,1,2,3,4,5,6,7,8,9)
    124. Button(diff,text='我选好了',command=lambda:setDiff(cmb.get())).pack()
    125. diff.mainloop()
    126. window = Tk()
    127. window.title('数独')
    128. window.geometry('390x500')
    129. window.resizable(0,0)
    130. begin_time = 0
    131. steps = 0
    132. rights = 0
    133. wrongs = 0
    134. dwc = difficulty*9
    135. ac_name = None
    136. list = range(1,82)
    137. try:
    138. ran = random.sample(list,dwc)
    139. except:
    140. if difficulty > 9:
    141. ran = random.sample(list,9)
    142. elif difficulty < 0:
    143. ran = random.sample(list,1)
    144. print('难度输入出现问题 你将无法通关')
    145. try:
    146. py.mixer.init()
    147. py.mixer.music.load('bg.mp3')
    148. py.mixer.music.play(-1)
    149. except:
    150. print('未检测到名为 bg.mp3 的背景音乐')
    151. def setBlock(num,name):
    152. global begin_time
    153. if begin_time == 0:
    154. begin_time = time.time()
    155. global ac_name
    156. global ac_num
    157. if ac_name != name and name != None and ac_name != None:
    158. ac_name.config(text='?',bg='orange',activebackground='orange',relief='groove')
    159. if name.cget('bg') != 'green':
    160. name.config(text='···',relief='sunken',bg='lightblue',activebackground='lightblue')
    161. ac_name = name
    162. ac_num = num
    163. else:
    164. ac_name = None
    165. def setNum(num):
    166. global ac_name
    167. global begin_time
    168. global dwc
    169. global ac_num
    170. global re
    171. global difficulty
    172. global steps
    173. global wrongs
    174. global rights
    175. global steP
    176. try:
    177. b_color = ac_name.cget('bg')
    178. if ac_num == num:
    179. ac_name.config(text='√',activebackground='green',relief='groove',bg='green')
    180. else:
    181. ac_name.config(text='×',activebackground='red',relief='groove')
    182. ac_name.flash()
    183. ac_name.flash()
    184. if ac_num == num:
    185. ac_name.config(text=str(num),activebackground='green',background='green',relief='groove')
    186. else:
    187. ac_name.config(text='?',bg='orange',activebackground='orange',relief='groove')
    188. if ac_name.cget('bg') == 'green' and b_color == 'lightblue':
    189. dwc -= 1
    190. ac_name = None
    191. rights += 1
    192. steps += 1
    193. elif b_color == 'lightblue' and ac_name.cget('bg') == 'orange':
    194. ac_name = None
    195. wrongs += 1
    196. steps += 1
    197. if dwc == 0:
    198. ac_name = None
    199. print('恭喜,你赢了!')
    200. Label(window,text='恭喜,你赢了!',font=('微软雅黑',30),bg='lightgreen').place(x=52,y=50)
    201. use_time = round(time.time()-begin_time,1)
    202. Label(window,text='用时'+str(use_time)+'秒 正确率'+str(round((rights/steps)*100,1))+'%',bg='yellow').place(x=113,y=121)
    203. re.config(text='剩余数字数量:'+str(dwc)+' 难度等级:'+str(difficulty))
    204. steP.config(text='步数:'+str(steps)+' 正确:'+str(rights)+' 错误:'+str(wrongs))
    205. ac_name = None
    206. except:
    207. pass
    208. def tipSs():
    209. '''global sds
    210. for ynfo in sds:
    211. print(ynfo)'''
    212. global ac_num
    213. global ac_name
    214. try:
    215. ac_name.config(text=str(ac_num))
    216. ac_name.flash()
    217. ac_name.config(text='···')
    218. except:
    219. pass
    220. def pauseOr(bgm):
    221. global pausE
    222. if pausE == True:
    223. py.mixer.music.pause()
    224. Button(window,text='♪',font=('楷体',7),relief='sunken',bg='white',command=lambda:pauseOr(bgm)).place(x=365,y=11)
    225. pausE = False
    226. elif pausE == False:
    227. py.mixer.music.unpause()
    228. Button(window,text='♫',font=('楷体',7),relief='sunken',bg='green',command=lambda:pauseOr(bgm)).place(x=365,y=11)
    229. pausE = True
    230. j=0
    231. i=0.7
    232. _count = 1
    233. wz = False
    234. # 这里通过win10计算器,两年前的项目写出了算法
    235. def spaceBtn(i,j,ri,rj):
    236. name = 'a'+str(i+1)+str(j+1)
    237. name = Button(window,text='?',font=('微软雅黑',10),relief='groove',bg='orange',activebackground='orange',command=lambda:setBlock(sds[i][j],name))
    238. name.place(x=rj*36,y=ri*38,width=30,height=30)
    239. def numBtn(num):
    240. Button(window,text=str(num),font=('楷体',15),relief='sunken',bg='white',activebackground='blue',command=lambda:setNum(num)).place(x=x*42+9,y=380,width=37,height=37)
    241. for info in sds:
    242. for jnfo in info:
    243. j+=1
    244. for znfo in ran:
    245. if _count == znfo:
    246. wz = True
    247. _count += 1
    248. if wz == True:
    249. spaceBtn(round(i-1),j-1,i,j)
    250. wz = False
    251. else:
    252. Label(window,text=jnfo,font=('微软雅黑',10),relief='ridge',bg='grey').place(x=j*36,y=i*38,width=30,height=30)
    253. j=0
    254. i+=1
    255. for x in range(0,9):
    256. numBtn(x+1)
    257. Button(window,text='提示',command=tipSs).place(x=50,y=430)
    258. bgm = Button(window,text='♫',font=('楷体',7),relief='sunken',bg='green',command=lambda:pauseOr(bgm)).place(x=365,y=11)
    259. re = Label(window,text='剩余数字数量:'+str(dwc)+' 难度等级:'+str(difficulty),relief='sunken')
    260. re.place(x=185,y=470)
    261. steP = Label(window,text='步数:'+str(steps)+' 正确:'+str(rights)+' 错误:'+str(wrongs),relief='sunken')
    262. steP.place(x=5,y=470)
    263. window.mainloop()

    主要外部依赖库:tkinter,pygame

    需要改动地方:    py.mixer.music.load('bg.mp3'),在同一目录准备自己喜欢的游戏背景音乐重命名为bg即可

    游戏运行效果如下:

    下拉框选择不同等级难度,开始游戏,点击问号方块再点击下方数字即可填入

    点击黄色问号方块再点击提示就会显示一秒钟的答案,之后再填入即可

    详细来源:

    用python实现带界面的数独小游戏_eyz2022的博客-CSDN博客_python 数独游戏

     

     

     

     

     

  • 相关阅读:
    12小时,教室与生产线接力 复旦MBA科创青干营首个整合实践活动日
    2023/9/17总结
    Leetcode.1465 切割后面积最大的蛋糕
    Kotlin协程分析(三)——理解协程上下文
    SQLite:TIMESTAMP类型使用
    MECE分析法
    ctf-pikachu-CSRF
    【程序员日记】---从业务编排到低代码
    springboot+vue+java药房药店在线销售管理系统
    ReentrantLock源码分析
  • 原文地址:https://blog.csdn.net/qq_38563206/article/details/127477530