python:图形界面演示八皇后搜索过程

Posted 不如这样

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python:图形界面演示八皇后搜索过程相关的知识,希望对你有一定的参考价值。

用到了pygame,主要是这个方便演示:

框架用了pygame+thinker,感觉上是不相容的,因为用了pygame,底层它实现,你怎么可能再用thinker呢,它也有自己的一套,结果国外高手把这两个整合在一起了,有好的方面,一个表示图形切换简单,一个有按钮。

八皇后问题用了全排列:8的8次方中排列,那么状态0->8^8个,然后取(8^n)的余数再整除(8^(n-1)),就是,每一排的对应位置,然后调用局面检查函数,这里函数不返回true,false,而是返回出错行,因为这一行出错了,以后的行进行的牌列,检查,全是无用功,直接状态+8^(n-1),就是他这一行的下一个状态对应数值。实际这个逻辑和所有快速搜索是一模一样的。就好比用了8个for循环,哪一个出错,直接next哪一个

由于需要画面演示,八皇后求解要做成类,每一次不是返回全部,而是当前的局面,取一个局面函数queen_next_rows(),这样返回一个局面的数据,每次pygame,loop的时候,可以画面显示管理把结果交给CMG.printAll(res)

画面演示中,需要打印两个棋盘(当然这个背景实际不复杂,复杂的可能画1000多条线),这里用了下面语句,就是可以把画面上花了许多力气作出的图,保存起来,下一次直接打印保存的rect(到底是不是rect其实不明白,只知道这样才行),网上找了半天,没找到,最后好不容易试出来的:

 

            select_rect = CMG.screen.subsurface(0,0,800,570)
            CMG.screen_rect = select_rect.copy()

 

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)
    YELLOW = (255, 255, 0)
    blocksize = 0
    step = 0
    last_answer = None
    backgr = None
    screen_rect = 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
        CMG.screen_rect = None
        #如果存在对象成员
        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
        if CMG.screen_rect == None:
            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)
            select_rect = CMG.screen.subsurface(0,0,800,570)
            CMG.screen_rect = select_rect.copy()
        else:
            self.screen.blit(CMG.screen_rect,(0,0))
        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)), 0)
        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.YELLOW, ((x,y), (CMG.blocksize-6, CMG.blocksize-6)), 0)

        #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()

 

以上是关于python:图形界面演示八皇后搜索过程的主要内容,如果未能解决你的问题,请参考以下文章

八皇后--python代码

什麽是“八皇后问题”?

八皇后问题

八皇后问题遗传算法实现(python版)

八皇后问题求解的C语言程序的实现

第五第六课------递推+记忆话搜索+搜索八皇后(思想是做梦)+各种剪枝思想