zoukankan      html  css  js  c++  java
  • 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()
  • 相关阅读:
    Java8新特性一览表
    FastDFS 单机部署指南
    EntityManager的Clear方法的使用
    元类
    python中的函数的分类
    python中的多任务
    正则表达式
    GIL和copy
    文件管理
    logging日志模块配置
  • 原文地址:https://www.cnblogs.com/nocomment/p/13046470.html
Copyright © 2011-2022 走看看