当前位置: 首页>后端>正文

用python编写的工具和游戏

一个简单的计算器

#  *_* coding:utf8 *_*
import tkinter
from functools import partial

# 按钮输入调用
def get_input(entry, argu):
    # 从entry窗口展示中获取输入的内容
    input_data = entry.get()

    # 合法运算符 : + - * / -- ** // +-
    # ------------ 输入合法性判断的优化 ------------
    # 最后一个字符不是纯数字(已经有算数符号),原窗口值不为空,且输入值为运算符
    # if not input_data[-1:].isdecimal() and (not argu.isdecimal()):
    #     if input_data[-2:] in ["--", "**", "//", "+-"]:
    #         return
    #     if (input_data[-1:] + argu) not in ["--", "**", "//", "+-"]:
    #         return
    # ------------------------------------------------

    # 出现连续+,则第二个+为无效输入,不做任何处理
    if (input_data[-1:] == '+') and (argu == '+'):
        return
    # 出现连续+--,则第三个-为无效输入,不做任何处理
    if (input_data[-2:] == '+-') and (argu == '-'):
        return
    # 窗口已经有--后面字符不能为+或-
    if (input_data[-2:] == '--') and (argu in ['-', '+']):
        return
    # 窗口已经有 ** 后面字符不能为 * 或 /
    if (input_data[-2:] == '**') and (argu in ['*', '/']):
        return
    # 输入合法将字符插入到entry窗口结尾
    entry.insert("end", argu)

# 退格(撤销输入)
def backspace(entry):
    input_len = len(entry.get())
    # 删除entry窗口中最后的字符
    entry.delete(input_len - 1)

# 清空entry内容(清空窗口)
def clear(entry):
    entry.delete(0, "end")

def calc(entry):
    input_data = entry.get()
    # 计算前判断输入内容是否为空;首字符不能为*/;*/不能连续出现3次;
    if not input_data:
        return
    clear(entry)
    # 异常捕获,在进行数据运算时如果出现异常进行相应处理
    # noinspection PyBroadException
    try:
        # eval() 函数用来执行一个字符串表达式,并返回表达式的值;并将执行结果转换为字符串
        output_data = str(eval(input_data))
    except Exception:
        # 将提示信息输出到窗口
        entry.insert("end", "Calculation error")
    else:
        # 将计算结果显示在窗口中
        if len(output_data) > 20:
            entry.insert("end", "Value overflow")
        else:
            entry.insert("end", output_data)

if __name__ == '__main__':

    root = tkinter.Tk()
    root.title("Calculator")

    # 框体大小可调性,分别表示x,y方向的可变性;
    root.resizable(0, 0)

    button_bg = 'orange'
    math_sign_bg = 'DarkTurquoise'
    cal_output_bg = 'YellowGreen'
    button_active_bg = 'gray'

    # justify:显示多行文本的时候, 设置不同行之间的对齐方式,可选项包括LEFT, RIGHT, CENTER
    # 文本从窗口左方开始显示,默认可以显示20个字符
    # row:entry组件在网格中的横向位置
    # column:entry组件在网格中的纵向位置
    # columnspan:正常情况下,一个插件只占一个单元;可通过columnspan来合并一行中的多个相邻单元
    entry = tkinter.Entry(root, justify="right", font=1)
    entry.grid(row=0, column=0, columnspan=4, padx=10, pady=10)

    def place_button(text, func, func_params, bg=button_bg, **place_params):
        # 偏函数partial,可以理解为定义了一个模板,后续的按钮在模板基础上进行修改或添加特性
        # activebackground:按钮按下后显示颜place_params色
        my_button = partial(tkinter.Button, root, bg=button_bg, padx=10, pady=3, activebackground=button_active_bg)
        button = my_button(text=text, bg=bg, command=lambda: func(*func_params))
        button.grid(**place_params)

    # 文本输入类按钮
    place_button('7', get_input, (entry, '7'), row=1, column=0, ipadx=5, pady=5)
    place_button('8', get_input, (entry, '8'), row=1, column=1, ipadx=5, pady=5)
    place_button('9', get_input, (entry, '9'), row=1, column=2, ipadx=5, pady=5)
    place_button('4', get_input, (entry, '4'), row=2, column=0, ipadx=5, pady=5)
    place_button('5', get_input, (entry, '5'), row=2, column=1, ipadx=5, pady=5)
    place_button('6', get_input, (entry, '6'), row=2, column=2, ipadx=5, pady=5)
    place_button('1', get_input, (entry, '1'), row=3, column=0, ipadx=5, pady=5)
    place_button('2', get_input, (entry, '2'), row=3, column=1, ipadx=5, pady=5)
    place_button('3', get_input, (entry, '3'), row=3, column=2, ipadx=5, pady=5)
    place_button('0', get_input, (entry, '0'), row=4, column=0, padx=8, pady=5,
                 columnspan=2, sticky=tkinter.E + tkinter.W + tkinter.N + tkinter.S)
    place_button('.', get_input, (entry, '.'), row=4, column=2, ipadx=7, padx=5, pady=5)

    # 运算输入类按钮(只是背景色不同)
    # 字符大小('+','-'宽度不一样,使用ipadx进行修正)
    place_button('+', get_input, (entry, '+'), bg=math_sign_bg, row=1, column=3, ipadx=5, pady=5)
    place_button('-', get_input, (entry, '-'), bg=math_sign_bg, row=2, column=3, ipadx=5, pady=5)
    place_button('*', get_input, (entry, '*'), bg=math_sign_bg, row=3, column=3, ipadx=5, pady=5)
    place_button('/', get_input, (entry, '/'), bg=math_sign_bg, row=4, column=3, ipadx=5, pady=5)

    # 功能输入类按钮(背景色、触发功能不同)
    place_button('<-', backspace, (entry,), row=5, column=0, ipadx=5, padx=5, pady=5)
    place_button('C', clear, (entry,), row=5, column=1, pady=5, ipadx=5)
    place_button('=', calc, (entry,), bg=cal_output_bg, row=5, column=2, ipadx=5, padx=5, pady=5,
                 columnspan=2, sticky=tkinter.E + tkinter.W + tkinter.N + tkinter.S)

    root.mainloop()

贪食蛇

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author:Wangdali time:2021年1月20日16:08:44
#python实现:贪吃蛇
'''
游戏玩法:回车开始游戏;空格暂停游戏/继续游戏;方向键/wsad控制小蛇走向
'''

'''
思路:用列表存储蛇的身体;用浅色表示身体,深色背景将身体凸显出来;
蛇的移动:仔细观察,是:身体除头和尾不动、尾部消失,头部增加,所以,新添加的元素放在列表头部、删除尾部元素;
游戏结束判定策略:超出边界;触碰到自己的身体:蛇前进的下一格子为身体的一部分(即在列表中)。
'''
#注:因为在列表中需要频繁添加和删除元素,所以用deque容器代替列表;是因为deque具有高效的插入和删除效率
#初始化蛇,长度为3,放置在屏幕左上角;
#导包
import random
import sys
import time
import pygame
from pygame.locals import *
from collections import deque
#基础设置
Screen_Height=480
Screen_Width=600
Size=20#小方格大小
Line_Width=1
#游戏区域的坐标范围
Area_x=(0,Screen_Width//Size-1) #0是左边界,1是右边界 #注:python中//为整数除法;/为浮点数除法
Area_y=(2,Screen_Height//Size-1)
#食物的初步设置
#食物的分值+颜色
Food_Style_List=[(10,(255,100,100)),(20,(100,255,100)),(30,(100,100,255))]
#整体颜色设置
Light=(100,100,100)
Dark=(200,200,200)
Black=(0,0,0)
Red=(200,30,30)
Back_Ground=(40,40,60)
#文本输出格式设置
def Print_Txt(screen,font,x,y,text,fcolor=(255,255,255)):
    #font.render参数意义:.render(内容,是否抗锯齿,字体颜色,字体背景颜色)
    Text=font.render(text,True,fcolor)
    screen.blit(Text,(x,y))
#初始化蛇
def init_snake():
    snake=deque()
    snake.append((2,Area_y[0]))
    snake.append((1,Area_y[0]))
    snake.append((0,Area_y[0]))
    return snake
#食物设置
#注意需要对食物出现在蛇身上的情况进行判断
def Creat_Food(snake):
    '''
    注:randint 产生的随机数区间是包含左右极限的,
    也就是说左右都是闭区间的[1, n],能取到1和n。
    而 randrange 产生的随机数区间只包含左极限,
    也就是左闭右开的[1, n),1能取到,而n取不到。randint
    产生的随机数是在指定的某个区间内的一个值,
    而 randrange 产生的随机数可以设定一个步长,也就是一个间隔。
    '''
    food_x=random.randint(Area_x[0],Area_x[1]) #此处有疑问
    food_y=random.randint(Area_y[0],Area_y[1])
    #如果食物出现在蛇上,重来;
    while(food_x,food_y)in snake:
        food_x = random.randint(Area_x[0], Area_x[1])
        food_y = random.randint(Area_y[[0], Area_y[1]])
    return food_x,food_y
#食物风格
def Food_Style():
    return Food_Style_List[random.randint(0,2)] #返回随机的分值和颜色
def main():
    pygame.init()
    screen=pygame.display.set_mode((Screen_Width,Screen_Height)) #初始化一个准备显示的窗口或屏幕
    pygame.display.set_caption('贪吃蛇') #Set the current window caption
    #得分字体设置
    font1=pygame.font.SysFont('SimHei',24)
    #GO字体设置
    font2 = pygame.font.SysFont(None, 72)
    fwidth, fheight = font2.size('GAME OVER') ###
    #程序bug修复:如果蛇在向右移动,快速点击分别施加向下、向左的命令,向下的命令会被覆盖,只有向左的命令被接受,直接GameOver
    # b变量为了防止这个情况发生
    b=True
    #蛇
    snake=init_snake()
    #食物
    food=Creat_Food(snake)
    food_style=Food_Style()
    #方向控制
    pos=(1,0) ###
    #启动游戏相关变量初始化
    game_over=True  #结束标志 # 是否开始,当start = True,game_over = True 时,才显示 GAME OVER
    game_start=False    #开始标志
    score=0 #得分
    orispeed=0.3  #蛇初始速度
    speed=orispeed  #蛇速度
    last_move_time=None
    pause=False #暂停
    while True:
        for event in pygame.event.get():
            if event.type==QUIT:
                sys.exit()
            elif event.type==KEYDOWN:
                if event.key==K_RETURN:
                    if game_over:
                        game_start=True
                        game_over=False
                        b=True
                        snake=init_snake()
                        food=Creat_Food(snake)
                        food_style=Food_Style()
                        pos=(1,0)
                        #得分
                        score=0
                        last_move_time=time.time()
                elif event.key==K_SPACE:
                    if not game_over:
                        pause=not pause
                #以下为防止蛇在向右移动时按向左键,导致GameOver
                elif event.key in (K_UP,K_w):
                    if b and not pos[1]: ###
                        pos=(0,-1)
                        b=False
                elif event.key in (K_DOWN,K_s):
                    if b and not pos[1]:
                        pos = (0, 1)
                        b = False
                elif event.key in (K_LEFT,K_a):
                    if b and not pos[0]:
                        pos = (-1, 0)
                        b = False
                elif event.key in (K_RIGHT,K_d):
                    if b and not pos[0]:
                        pos = (1, 0)
                        b = False
        #填充背景色
        screen.fill(Back_Ground)
        ###
        #画网格线、竖线
        for x in range(Size, Screen_Width, Size):
            pygame.draw.line(screen, Black, (x, Area_y[0] * Size), (x, Screen_Height), Line_Width)
        #画网格线、横线
        for y in range(Area_y[0] * Size, Screen_Height, Size):
            pygame.draw.line(screen, Black, (0, y), (Screen_Width, y), Line_Width)
        #蛇的爬行过程
        if not game_over:
            curTime=time.time()
            if curTime-last_move_time>speed: ###
                if not pause:
                    b=True
                    last_move_time=curTime
                    next_s = (snake[0][0] + pos[0], snake[0][1] + pos[1])
                    #如果吃到了食物
                    if next_s==food:
                        snake.appendleft(next_s)
                        score+=food_style[0]
                        speed = orispeed - 0.03 * (score // 100)
                        food = Creat_Food(snake)
                        food_style = Food_Style()
                    else:
                        #在区域内
                        if Area_x[0]<=next_s[0]<=Area_x[1] and Area_y[0]<=next_s[1]<=Area_y[1] and next_s not in snake:
                            snake.appendleft(next_s)
                            snake.pop()
                        else :
                            game_over=True
        #画食物
        if not game_over:
         '''
        rect(Surface,color,Rect,width=0)
第一个参数指定矩形绘制到哪个Surface对象上

第二个参数指定颜色

第三个参数指定矩形的范围(left,top,width,height)

第四个参数指定矩形边框的大小(0表示填充矩形)

例如绘制三个矩形:

    pygame.draw.rect(screen, BLACK, (50, 50, 150, 50), 0)
    pygame.draw.rect(screen, BLACK, (250, 50, 150, 50), 1)
    pygame.draw.rect(screen, BLACK, (450, 50, 150, 50), 10)
         '''
        # 避免 GAME OVER 的时候把 GAME OVER 的字给遮住了
        pygame.draw.rect(screen, food_style[1], (food[0] * Size, food[1] * Size, Size, Size), 0)
        #画蛇
        for s in snake:
            pygame.draw.rect(screen, Dark, (s[0] * Size + Line_Width, s[1] * Size + Line_Width,
                                            Size - Line_Width * 2, Size - Line_Width * 2), 0)
        Print_Txt(screen, font1, 30, 7, f'速度: {score // 100}')
        Print_Txt(screen, font1, 450, 7, f'得分: {score}')
        #画GameOver
        if game_over:

            if game_start:
                #print('GameOver')
                Print_Txt(screen, font2, (Screen_Width - fwidth) // 2, (Screen_Height - fheight) // 2, 'GAME OVER',Red)
        pygame.display.update()

if __name__=='__main__':
    main()

数字华容道

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import random
from collections import OrderedDict
import pygame

FPS = 60
SHAPE = 4         # 棋盘shape
CELL_SIZE = 100   # 方格大小
CELL_GAP_SIZE = 10  # 方格间距
MARGIN = 10  # 方格的margin
PADDING = 10  # 方格的padding
SCREEN_WIDTH = (CELL_SIZE + MARGIN) * SHAPE + MARGIN  # 屏幕宽度
SCREEN_HEIGHT = (CELL_SIZE + MARGIN) * SHAPE + MARGIN  # 屏幕高度

BACKGROUND_COLOR = "#92877d"  # 背景颜色
BACKGROUND_EMPTY_CELL_COLOR = "#9e948a"  # 空方格颜色
BACKGROUND_CELL_COLOR = "#edc22e"  # 方格颜色

# 定义两个元组相加
def tuple_add(t1, t2):
    return (t1[0] + t2[0], t1[1] + t2[1])

class Logic:
    def __init__(self, shape=4):
        self.shape = int(shape) if shape > 2 else 4  # 初始化形状
        self.tiles = OrderedDict()  # 初始化数据
        self.neighbors = [  # 定义方向矢量
            [1, 0],  # 下
            [-1, 0],  # 上
            [0, 1],  # 右
            [0, -1],  # 左
        ]
        self.click_dict = {'x': {}, 'y': {}}  # 定义鼠标点击坐标转换下标的数据
        self.init_load()  # 初始化加载

    def init_load(self):
        count = 1
        # 生成正确的序列
        for x in range(self.shape):
            for y in range(self.shape):
                mark = tuple([x, y])
                self.tiles[mark] = count
                count += 1
        self.tiles[mark] = 0

        for count in range(1000):  # 随机移动一千次
            neighbor = random.choice(self.neighbors)
            spot = tuple_add(mark, neighbor)

            if spot in self.tiles:
                number = self.tiles[spot]
                self.tiles[spot] = 0
                self.tiles[mark] = number
                mark = spot

        self.init_click_dict()

    def init_click_dict(self):
        # 初始化点击坐标转换下标的数据
        for r in range(self.shape):
            for c in range(self.shape):
                x = MARGIN * (c + 1) + c * CELL_SIZE
                x1 = x + CELL_SIZE
                click_x = tuple(range(x, x1))

                self.click_dict['x'][click_x] = c
                y = MARGIN * (r + 1) + r * CELL_SIZE
                y1 = y + CELL_SIZE
                click_y = tuple(range(y, y1))
                self.click_dict['y'][click_y] = r

    def move(self, mark):
        # 移动数据
        for neighbor in self.neighbors:
            spot = tuple_add(mark, neighbor)

            if spot in self.tiles and self.tiles[spot] is 0:
                self.tiles[spot], self.tiles[mark] = self.tiles[
                    mark], self.tiles[spot]
                break

    def click_to_move(self, x, y):
        # 点击移动
        x1 = None
        for k, v in self.click_dict['x'].items():
            if x in k:
                x1 = v

        if x1 is None:
            return
        y1 = None
        for k, v in self.click_dict['y'].items():
            if y in k:
                y1 = v

        if y1 is None:
            return
        self.move((y1, x1))

    def is_win(self):
        # 游戏结束判定
        if self.tiles[(self.shape - 1, self.shape - 1)] is not 0:
            return False
        values = list(self.tiles.values())
        for index in range(values.__len__() - 1):
            if index + 1 != values[index]:
                return False
        return True
    
def init_game():
    # 初始化游戏
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption('数字华容道 -- 0')
    return screen


def draw_num(logic, screen):
    for r in range(logic.shape):
        for c in range(logic.shape):
            num = logic.tiles[(r, c)]
            if num is not 0:
                color = pygame.Color(BACKGROUND_CELL_COLOR)
            else:
                color = pygame.Color(BACKGROUND_EMPTY_CELL_COLOR)

            x = MARGIN * (c + 1) + c * CELL_SIZE
            y = MARGIN * (r + 1) + r * CELL_SIZE
            pygame.draw.rect(screen, color, (x, y, CELL_SIZE, CELL_SIZE))
            if num is not 0:
                font_size = int((CELL_SIZE - PADDING) / 1.3)
                font = pygame.font.SysFont('arialBlod', font_size)
                font_width, font_height = font.size(str(num))
                screen.blit(font.render(str(num), True, (255, 255, 255)),
                            (x + (CELL_SIZE - font_width) / 2, y +
                             (CELL_SIZE - font_height) / 2 + 5))
                
def press(is_game_over, logic, COUNT, counts):
    for event in pygame.event.get():
        if event.type == COUNT and not is_game_over:  # 设置定时器,记录时间
            counts += 1
            pygame.display.set_caption('数字华容道 -- {}'.format(counts))
        if event.type == pygame.QUIT:  # 点击关闭按钮退出
            pygame.quit()
            sys.exit()
        elif event.type == pygame.MOUSEBUTTONUP:  # 鼠标点击
            if event.button == 1 and not is_game_over:
                x, y = event.pos
                logic.click_to_move(int(x), int(y))  # 点击移动
        elif event.type == pygame.KEYDOWN and event.key == 13:  # 游戏结束,回车重开
            return True
    if COUNT:
        return counts


def game_win(screen, logic, clock, text='You Win!'):
    font = pygame.font.SysFont('Blod', int(SCREEN_WIDTH / 4))
    font_width, font_height = font.size(str(text))
    while True:
        if press(True, logic, None, None):
            break
        screen.fill(pygame.Color(BACKGROUND_COLOR))
        draw_num(logic, screen)
        screen.blit(font.render(str(text), True, (0, 0, 0)),
                    ((SCREEN_WIDTH - font_width) / 2,
                     (SCREEN_HEIGHT - font_height) / 2))
        pygame.display.update()
        clock.tick(FPS)

def main():
    screen = init_game()
    clock = pygame.time.Clock()
    logic = Logic(SHAPE)
    COUNT = pygame.USEREVENT + 1
    pygame.time.set_timer(COUNT, 1000)
    seconds = 0  # 记录时间
    while True:
        if logic.is_win():  # 判断游戏是否胜利
            break
        seconds = press(False, logic, COUNT, seconds)  # 监控按键
        screen.fill(pygame.Color(BACKGROUND_COLOR))  # 填充背景
        draw_num(logic, screen)  # 画数字
        pygame.display.update()
        clock.tick(FPS)
    game_win(screen, logic, clock, text='Time:' + str(seconds))

if __name__ == "__main__":
    while True:
        main()

https://www.xamrdz.com/backend/32b1868806.html

相关文章: