import pygame
import sys
import os
import random
import time
from pygame.locals import *
import tkinter as tk
from tkinter import *
import tkinter.messagebox # 要使用messagebox先要导入模块
class Eight_queen:
queens = 0
sts = 0
pows = None
def __init__(self,queens):
Eight_queen.queens = queens
Eight_queen.pows = [pow(queens,queens-i) for i in range(0,queens+1)]
Eight_queen.sts = 0
@staticmethod
def check(rows):
for row in range(1,len(rows)):
for i in range(row):
if abs(rows[i] - rows[row]) in (0, row - i):
return row
return 0
@staticmethod
def queen_next_rows():
if Eight_queen.sts >= Eight_queen.pows[0]:
return None
n = Eight_queen.queens
rows = [0]*n
for x in range(0,n):
rows[x]=(Eight_queen.sts%Eight_queen.pows[x])//Eight_queen.pows[x+1]
err_row = Eight_queen.check(rows)
if err_row == 0:
Eight_queen.sts += 1
return [0,rows]
else:
Eight_queen.sts += Eight_queen.pows[err_row+1]
return [1,rows]
class CMG: #画面显示管理
screen = None
map = None
gameAnswer = None
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
blocksize = 0
step = 0
last_answer = None
def __init__(self,screen):
#if CMG.screen == None:
#print("#############OS.PATH=%s"% os.path.dirname(os.path.abspath(__file__)))
CMG.screen = screen
CMG.blocksize = 350//Eight_queen.queens
#如果存在对象成员
self.init_game_info()
def init_game_info(self):
pass
def printAll(self,res):
#if CMG.step > len(CMG.gameAnswer):
# return
rtn = res[0]
rows = res[1]
if rtn == 0:
CMG.last_answer = rows[:]
CMG.screen.fill((0, 0, 0))
queens = Eight_queen.queens
for x in range(0,queens+1):
end_pos = [(x*CMG.blocksize,0),(x*CMG.blocksize,queens*CMG.blocksize)]
pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
end_pos = [(x*CMG.blocksize+400,0),(x*CMG.blocksize+400,queens*CMG.blocksize)]
pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
for y in range(0,queens+1):
end_pos = [(0,y*CMG.blocksize),(queens*CMG.blocksize,y*CMG.blocksize)]
pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
end_pos = [(400,y*CMG.blocksize),(400+queens*CMG.blocksize,y*CMG.blocksize)]
pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
for r in range(0,len(rows)):
y = r*CMG.blocksize + 3
x = rows[r] *CMG.blocksize + 3
pygame.draw.rect(CMG.screen, CMG.WHITE, ((x,y), (CMG.blocksize-6, CMG.blocksize-6)), 2)
if CMG.last_answer != None:
rows = CMG.last_answer
for r in range(0,len(rows)):
y = r*CMG.blocksize + 3
x = rows[r] *CMG.blocksize + 403
pygame.draw.rect(CMG.screen, CMG.WHITE, ((x,y), (CMG.blocksize-6, CMG.blocksize-6)), 2)
#CMG.step += 1
def moveAll(self):
pass
#------------------------------------------------
#tkinter,pygame混合区 START
#------------------------------------------------
root = tk.Tk()
root.resizable(0,0)
embed = tk.Frame(root, width = 800, height = 570) #creates embed frame for pygame window
embed.grid(columnspan = (800), rowspan = 730) # Adds grid
embed.pack(side = TOP) #packs window to the left
buttonwin = tk.Frame(root, width = 800, height = 150)
buttonwin.pack(side = BOTTOM)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((800,570))
#pygame.init()
pygame.display.init()
pygame.mixer.init()
#------------------------------------------------
#tkinter,pygame混合区 END
#------------------------------------------------
#参数,因为函数内要使用之外的变量,需要globe,因此全部打包
class PARAM:
STATUS = 0
TICK_NORMAL = 5
TICK_STEP = 30
#按钮动作区 =====================================
def get_input_data(inputcell,min,max):
if inputcell.get().isdigit():
num = int(inputcell.get())
if min<=num and num<=max:
return num
return -1
def exit_game():
global param
param.STATUS = 100
def stop_game():
global param
param.STATUS = 10
def sel_game():
global param
qs = get_input_data(inputqs,4,9)
speed = get_input_data(inputspd,11,99)
if qs == -1 or speed == -1:
return
else:
eq = Eight_queen(qs)
param.cmg = CMG(screen)
PARAM.TICK_STEP = speed
param.STATUS = 0
#控件定义区 =====================================
button_stop_b = Button(buttonwin,text = '本次演示结束', width=11, command=stop_game)
button_stop_b.place(x=700,y=30)
btnwin_qs_l = tk.Label(buttonwin, text='皇后数(4-9):')
btnwin_qs_l.place(x=530,y=70)
inputqs = StringVar()
btnwin_qs_e = tk.Entry(buttonwin, show=None,width=2,textvariable = inputqs)
btnwin_qs_e.place(x=590,y=70)
btnwin_spd_l = tk.Label(buttonwin, text='演示速度(11-99):')
btnwin_spd_l.place(x=610,y=70)
inputspd = StringVar()
btnwin_spd_e = tk.Entry(buttonwin, show=None,width=3,textvariable = inputspd)
btnwin_spd_e.place(x=710,y=70)
button_sel_b = Button(buttonwin,text = '执行', width=7, command=sel_game)
button_sel_b.place(x=740,y=65)
button_exit_b = Button(buttonwin,text = '退出画面', width=7, command=exit_game)
button_exit_b.place(x=740,y=100)
#状态,参数,循环中使用,比如STATUS=0:初次进入,1:...100:退出
param = PARAM()
eq = Eight_queen(6)
param.cmg = CMG(screen)
#------------------------------------------------
#主函数,使用pygame框架,无限LOOP对各种事件然后相应处理
#------------------------------------------------
def main():
global param
#pygame.mixer.music.play(-1)
clock = pygame.time.Clock()
while True:
#这段event代码是必须的,哪怕在这个程序中不需要,不执行的话整个框架转不动
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
#画面按钮按下后,修改param.STATUS,实际动作这里实现
if param.STATUS == 100:
#退出按钮
if tk.messagebox.askokcancel('提示', '要退出画面吗'):
break
param.STATUS = 0
elif param.STATUS == 10:
pass
elif param.STATUS == 0:
res = Eight_queen.queen_next_rows()
if res != None:
param.cmg.printAll(res)
else:
STATUS = 10
#显示游戏画面
pygame.display.flip()
#设置帧率:长期画面不操作,设置成最闲
if param.STATUS == 0:
clock.tick(param.TICK_STEP)
else:
clock.tick(param.TICK_NORMAL)
root.update()
main()