pygame写个数独

  • Post author:
  • Post category:其他


可以选关,记录最高分,可以提示错误的格子或别的乱七八糟的

"""
@author: Bre Athy
@contact: https://www.zhihu.com/people/you-yi-shi-de-hu-xi
@productware: PyCharm
@file: SodokuMaker.py
@time: 2020/4/8 16:06
"""
import pygame, sys, time, copy, SodukuUtil, json


class Color():
    black = (0, 0, 0)
    white = (255, 255, 255)
    red = (200, 0, 0)
    green = (0, 200, 0)
    bright_red = (255, 0, 0)
    bright_green = (0, 255, 0)
    grey = (88, 88, 88)
    mWhite = (255,251,240)
    blue = (0, 0, 255)


class SodokuGame():
    running = True              # 控制退出
    fontFamily = "comicsansms"  # 默认字体
    difficulty = 1              # 难度控制,三个难度:简单1 普通2 困难3
    level = 1                   # 关卡控制,1-10关
    title = "Soduku Game"       # 游戏标题
    isPaused = False            # 暂停模式
    isAnswer = False            # 答案模式
    errorCount = 0              # 错误次数
    recordFile = "record.json"  # 记录文件
    score = -1                  # 得分



    def __init__(self):
        # 游戏页面初始化
        pygame.init()
        self.clock = pygame.time.Clock()
        pygame.display.set_caption('数独游戏')           # 窗口标题
        display_size = self.display_width, self.display_height = 800, 600   # 设置窗口大小
        self.gameScreen = pygame.display.set_mode(display_size)
        self.timeStart = int(time.time())               # 时间记录器
        # 其他游戏细节
        self.timeColor = Color.grey
        self.pausedText = "Pause"
        self.pausedColor = Color.black
        # 数独初始化
        self.Sodoku = [[0] * 9 for i in range(9)]   # 数独数组
        self.Game = [[0] * 9 for i in range(9)]     # 游戏数组
        self.Answer = [[0] * 9 for i in range(9)]   # 答案数组
        self.position = (-1, -1)                    # 选中位置
        self.errorCursor = (-1, -1)                 # 错误指示
        try:
            with open(self.recordFile, "r") as f:
                self.record = json.load(f)
            assert len(self.record) == 30
        except:
            self.record = [-1] * 30                # 读取记录




    def start(self):
        # 游戏运行界面
        self.draw = self.Index
        # 开启游戏
        while self.running:
            for event in pygame.event.get():
                # 退出
                if event.type == pygame.QUIT:
                    self.exit()
                # 检测输入
                if (event.type == pygame.KEYDOWN) and (pygame.K_1 <= event.key <= pygame.K_9):
                    if (self.position != (-1, -1)) and (self.Sodoku[self.position[0]][self.position[1]] == 0):
                            self.Game[self.position[0]][self.position[1]] = event.key - 48


            # 填充背景
            self.gameScreen.fill(Color.white)
            # 绘制游戏页面
            self.draw()
            # 更新界面
            pygame.display.flip()
            self.clock.tick(120)


    def exit(self):
        # 退出游戏
        # self.file.close()
        pygame.quit()
        sys.exit()

    def fontRender(self, text, color, size, position, ttf = "comicsansms"):
        # 字体渲染
        font = pygame.font.SysFont(ttf, size)
        surf = font.render(text, True, color)
        surfRect = surf.get_rect()
        surfRect.center = position
        self.gameScreen.blit(surf, surfRect)

    def buttonRender(self, text, rectColor, floatingColor, fontColor, position, rectSize, fontSize, ttf = "comicsansms", border=0, action=None, actionArgs=None, timeDelay = True):
        # 按钮渲染
        # 绘制浮动矩形 rect(surface, color, rect, width)
        mousePositon = pygame.mouse.get_pos()  # 鼠标位置
        click = pygame.mouse.get_pressed()  # 鼠标按键
        if (position[0]+rectSize[0] > mousePositon[0] > position[0]) and (position[1]+rectSize[1] > mousePositon[1] > position[1]):
            pygame.draw.rect(self.gameScreen, floatingColor, (position, rectSize), border)
            if click[0] == 1 and action != None:
                if timeDelay:time.sleep(0.2)
                if actionArgs != None:action(actionArgs)
                else:action()
        else:
            pygame.draw.rect(self.gameScreen, rectColor, (position, rectSize), border)
        # 绘制字体
        fontPosition = position[0] + rectSize[0] / 2, position[1] + rectSize[1] / 2
        self.fontRender(text, fontColor, fontSize, fontPosition, ttf=ttf)


    def Index(self):
        # 绘制主页
        y = self.display_height / 1.5
        rectSize = self.display_width / 8, self.display_height / 12
        fontSize = 20
        def drawIndex():
            self.fontRender("Soduku Game", Color.black, 115,(self.display_width / 2, self.display_height / 3))     # 主页字体
            self.buttonRender("Start", Color.green, Color.bright_green, Color.black, (150, y), rectSize, fontSize, action=self.Difficulty_select)    # 开始按钮
            self.buttonRender("Quit", Color.red, Color.bright_red, Color.black, (550, y), rectSize, fontSize, action=self.exit)        # 关闭按钮
        self.draw = drawIndex


    def Difficulty_select(self):
        # 绘制选择难度的页面
        x = 350
        rectSize = self.display_width / 7, self.display_height / 12
        fontSize = 20

        def drawGameSelect():
            self.fontRender("Select difficulty", Color.black, 35, (self.display_width/2, self.display_height/6))
            self.buttonRender("back", Color.red, Color.bright_red, Color.black, (50, 550), rectSize, fontSize, action=self.Index)
            self.buttonRender("easy", Color.green, Color.bright_green, Color.black, (x, 200), rectSize, fontSize, action=self.Stage_select, actionArgs=1)
            self.buttonRender("general", Color.red, Color.bright_red, Color.black, (x, 300), rectSize, fontSize, action=self.Stage_select, actionArgs=2)
            self.buttonRender("difficult", Color.bright_green, Color.green, Color.black, (x, 400), rectSize, fontSize, action=self.Stage_select, actionArgs=3)
        self.draw = drawGameSelect

    def generateSoduku(self):
        # 调用接口生成数独数据
        mkr = SodukuUtil.SudoKuMaker(self.getStage())
        self.Sodoku = mkr.getArr()             # 数独数据
        self.Answer = mkr.getAnswer()          # 数独答案
        self.Game = copy.deepcopy(self.Sodoku) # 游戏数据
        self.uploader = mkr                    # 数据游标
        # 关闭模式
        self.isAnswer = False
        self.isPaused = False
        # 重置时间记录器
        self.timeStart = int(time.time())
        # 重置游标
        self.errorCursor = self.position = (-1, -1)
        # 重置错误次数
        self.errorCount = 0

    def enterGame(self, level_num):
        # 为游戏界面做准备,布置细节
        self.level = level_num
        if self.difficulty == 1:
            title = "Easy"
        elif self.difficulty == 2:
            title = "Normal"
        else:
            title = "Difficult"
        self.title = title + " Mode : level " + str(self.level)
        # 生成一组数独数据
        self.generateSoduku()
        # 正式开始游戏
        self.draw = self.LevelStart


    def Stage_select(self, difficulty):
        # 绘制关卡选择页面
        self.difficulty = difficulty

        def drawStageSelect():
            x1 = 250
            x2 = 450
            rectSize = self.display_width / 7, self.display_height / 12
            fontSize = 20
            self.fontRender("Select stage", Color.black, 35, (self.display_width / 2, self.display_height / 6))
            self.buttonRender("back", Color.red, Color.bright_red, Color.black, (50, 550), rectSize, fontSize, action=self.Difficulty_select)
            self.buttonRender("1 level", Color.green, Color.bright_green, Color.black, (x1, 200), rectSize, fontSize, action=self.enterGame, actionArgs=1)
            self.buttonRender("2 level", Color.red, Color.bright_red, Color.black, (x1, 270), rectSize, fontSize, action=self.enterGame, actionArgs=2)
            self.buttonRender("3 level", Color.green, Color.bright_green, Color.black, (x1, 340), rectSize, fontSize, action=self.enterGame, actionArgs=3)
            self.buttonRender("4 level", Color.red, Color.bright_red, Color.black, (x1, 410), rectSize, fontSize, action=self.enterGame, actionArgs=4)
            self.buttonRender("5 level", Color.green, Color.bright_green, Color.black, (x1, 480), rectSize, fontSize, action=self.enterGame, actionArgs=5)
            self.buttonRender("6 level", Color.green, Color.bright_green, Color.black, (x2, 200), rectSize, fontSize, action=self.enterGame, actionArgs=6)
            self.buttonRender("7 level", Color.red, Color.bright_red, Color.black, (x2, 270), rectSize, fontSize, action=self.enterGame, actionArgs=7)
            self.buttonRender("8 level", Color.green, Color.bright_green, Color.black, (x2, 340), rectSize, fontSize, action=self.enterGame, actionArgs=8)
            self.buttonRender("9 level", Color.red, Color.bright_red, Color.black, (x2, 410), rectSize, fontSize, action=self.enterGame, actionArgs=9)
            self.buttonRender("10 level", Color.green, Color.bright_green, Color.black, (x2, 480), rectSize, fontSize, action=self.enterGame, actionArgs=10)
        self.draw = drawStageSelect

    def LevelStart(self):
        # 游戏开始
        def renderGrid(position):
            # 渲染选中网格
            self.position = position

        def toPause():
            # 暂停
            if self.isPaused:
                self.isPaused = False
                self.pausedText = "Pause"
                self.pausedColor = Color.black
                self.timeColor = Color.grey
            else:
                self.isPaused = True
                self.pausedText = "Paused"
                self.pausedColor = self.timeColor = Color.red

        def getAnswer():
            # 查看答案
            self.isAnswer = True
            self.errorCursor = (-1, -1)
            self.Game = self.Answer

        def submitSoduku():
            # 提交答案
            if self.isAnswer:return     # 答案模式
            result = self.uploader.getWrong(self.Game)
            if not result:
                self.score = int(self.getBackTime())
                if self.record[self.level-1] == -1 or self.record[self.level-1] > int(self.getBackTime()):
                    self.record[self.level-1] = self.score
                    with open(self.recordFile, "w")as f:
                        json.dump(self.record, f)
                self.draw = self.ShowWin        # 成功
            else:
                self.errorCursor = result
                self.errorCount += 1
                if self.errorCount > 5:
                    self.draw=self.ShowLose     # 失败


        # 绘制标题与时间
        self.fontRender(self.title, Color.black, 40, (280 , 30))
        self.fontRender("Time: " + self.getBackTime(), self.timeColor, 30, (self.display_width - 130, 40))
        # 绘制操作按钮
        rectSize = 140, 60
        fontSize = 35
        self.buttonRender(self.pausedText, Color.green, Color.bright_green, self.pausedColor, (600, 200), rectSize, fontSize, action=toPause)
        if self.isAnswer: self.buttonRender("Submit", Color.grey, Color.grey, Color.black, (600, 300), rectSize, fontSize, action=submitSoduku)
        else: self.buttonRender("Submit", Color.green, Color.bright_green, Color.black, (600, 300), rectSize, fontSize, action=submitSoduku)
        rectSize = 100, 50
        fontSize = 20
        self.buttonRender("restart", Color.green, Color.bright_green, Color.black, (625, 410), rectSize, fontSize, action=self.generateSoduku)
        self.buttonRender("answer", Color.green, Color.bright_green, Color.black, (570, 480), rectSize, fontSize, action=getAnswer)
        self.buttonRender("back", Color.green, Color.bright_green, Color.black, (680, 480), rectSize, fontSize, action=self.Stage_select, actionArgs=self.difficulty)
        # 绘制九宫格
        x,y = 40,70                 # 基础位置
        length = 500 / 9            # 网格边长
        borderWidth = 1             # 边框宽度
        a,b = x+self.position[1]*length, y+self.position[0]*length
        e,f = x+self.errorCursor[1]*length, y+self.errorCursor[0]*length
        points = [(a, b), (a+length, b), (a+length, b+length), (a, b+length)]
        ## 绘制九宫格内容
        if not self.isPaused:
            for i in range(9):
                for j in range(9):
                    text = str(self.Game[i][j])
                    if text == '0':text = ""
                    position = x+j*length, y+i*length
                    if self.Game[i][j] == self.Sodoku[i][j]: fontColor = Color.black
                    else:
                        if self.isAnswer: fontColor = Color.green
                        else: fontColor = Color.blue
                    self.buttonRender(text, Color.white, Color.mWhite, fontColor, position, (length, length), 20, action=renderGrid, actionArgs=(i, j), timeDelay=False)
        ## 绘制九宫格边线
        for i in range(10):
            pygame.draw.line(self.gameScreen, Color.black, (x, y+i*length), (x+500, y+i*length), borderWidth)
            pygame.draw.line(self.gameScreen, Color.black, (x+i*length, y), (x+i*length, y+500), borderWidth)
        ## 绘制选中的格子
        if self.position != (-1, -1):
            pygame.draw.lines(self.gameScreen, Color.bright_red, 1, points, 4*borderWidth)
        ## 绘制错误游标
        if self.errorCursor != (-1, -1):
            pygame.draw.line(self.gameScreen, Color.red, (e,f), (e+length, f+length), 2*borderWidth)
            pygame.draw.line(self.gameScreen, Color.red, (e+length,f), (e, f+length), 2*borderWidth)

    def ShowWin(self):
        # 胜利的页面
        self.fontRender("You Win",Color.black, 115,(self.display_width / 2, self.display_height / 3))
        self.fontRender("Your:"+str(self.score), Color.blue, 50, (self.display_width / 2, 340))
        self.fontRender("Best:"+str(self.record[self.level-1]), Color.blue, 30, (self.display_width / 2, 420))
        def nextLevel():
            if self.level == 10:return
            else:
                self.level += 1
                self.generateSoduku()
                self.enterGame(self.level)
        self.buttonRender("Next Level", Color.green, Color.bright_green, Color.black, (480, 500), (150, 50), 20, action=nextLevel)
        self.buttonRender("Back", Color.red, Color.bright_red, Color.black, (180, 500), (150, 50), 20, action=self.Stage_select, actionArgs=self.difficulty)

    def ShowLose(self):
        # 失败的页面
        self.fontRender("You Lose",Color.black, 115,(self.display_width / 2, self.display_height / 3))
        self.buttonRender("Quit", Color.red, Color.bright_red, Color.black, (200, 400), (150, 50), 20, action=self.exit)
        self.buttonRender("Restart", Color.green, Color.bright_green, Color.black, (500, 400), (150, 50), 20, action=self.enterGame, actionArgs=self.level)



    def getStage(self):
        # 获取真实关卡数
        return int((self.difficulty - 1) * 10 + self.level)

    def getBackTime(self):
        # 获取剩余时间
        if not self.isPaused:
            self.backTime = int(time.time()) - self.timeStart
            return str(self.backTime)
        else:
            self.timeStart = int(time.time()) - self.backTime
            return str(self.backTime)



if __name__ == "__main__":
    Game = SodokuGame()
    Game.start()

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述



版权声明:本文为qq_41205771原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。