程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python write a small game: quick calculation 24 points (Part 1)

編輯:Python

List of articles

  • Preface
  • Quick calculation 24 spot
    • 1. How to play
    • 2. The flow of the game
    • 3. Build the game interface
      • 1). Basic interface
      • 2). Shuffle 、 Licensing
        • Shuffle
        • Licensing
      • 3). timer
      • 4). The player enters a formula ( answer )
        • StringVar class
        • Key event binding
      • 5). Determine whether the player's input is correct
    • 4. Knowledge review


Preface

Hello everyone , I meet you again . After the June day holiday, the company gradually returned to work , Work starts to get busy , So the update frequency has to slow down . And ask brother recently developed small games are original , Though sparrows are small , Five zang organs , Artistic creativity 、 Window layout 、 Code implementation 、 Function debugging , There's nothing missing . So it took a lot of time .

24 Point is a little game that I have always wanted to play , I wanted to do this issue in the text interface , But it's not interesting to find the text interface , So we put . Now come to the graphical interface , Finally, I can realize the way I played as a child , Use playing cards as props . So you'll have to shuffle 、 Licensing 、 Calculate points and other small functions . And let the program judge whether the current four cards can be calculated 24 spot , Behind it is the automatic calculation 24 Point method .( Because brother Wen uses the exhaustive method , There must be a lot of double counting , I dare not pretend here “ Algorithm ” 了 .)

Because there's more content , It's the same as before , Divided into two parts :

Part 1 —— Game interface construction
The next part —— Function code implementation


Quick calculation 24 spot

1. How to play

I believe many people played it when they were young , The rules are also relatively simple : Find a deck of playing cards , Remove the big and small king ,52 card , Draw four cards at random each time , Use the four calculation methods of addition, subtraction, multiplication and division , See who can work out the fastest 24 spot . When I was a child, I didn't have a computer , Therefore, it is impossible to judge whether the four cards have solutions , So as long as everyone gives up the same , You can skip to the next group .

screenshots :

2. The flow of the game

I feel that this small program is more complicated than the previous one , The amount of code has reached 200 lines . The reason is , I want to realize too many functions . Shuffle 、 Licensing 、 Judge whether you can work out 24 spot 、 timing 、 Tips, etc , Brother Wen wanted to be a scoreboard , After the game , The pop-up window shows the correct rate . But in the end, due to lack of energy , Or simply display on the panel “ Tested ”、“ Passed ” Give up . But in fact, this part of the function is relatively simple , Interested friends can freely add in .

Quick calculation 24 The simple flow chart of point is as follows :

NoYesYesNoYesNo Replace the next group NoYes Game begins Whether the deck is 0 extract 4 card Calculate whether the combination has a solution Countdown starts The player enters the answer Judge whether the answer is correct Stop the countdown Whether to enter the next round Game over Shuffle There are three opportunities to use tips Time is running out , Automatically enter the next round

3. Build the game interface

The interface of this game is original , Certainly not in line with everyone's aesthetic . After you understand the logic of implementation , You can color it yourself 、 Change pictures 、 Adjust the layout , So as to achieve a satisfactory effect .

1). Basic interface

Game background 、 The realization of this function , In the last article, I introduced , There's no more verbosity here . Go straight to the code :

from tkinter import *
# Initialize the main window 
root = Tk()
root.geometry('800x500+400+200')
root.resizable(0,0)
root.title(' Quick calculation 24 spot ')
# The canvas is the same size as the main window 
cv = Canvas(root,width=800,height=500)
# Background image 
bg = PhotoImage(file=r"image\poker\bg.png")
cv_bg = cv.create_image(400,250,image = bg)
# Title picture 
title = PhotoImage(file=r"image\poker\title.png")
cv_title = cv.create_image(400,60,image = title)
# The canvas is mounted in the window 
cv.pack()
root.mainloop()

such , We get an empty window :

2). Shuffle 、 Licensing

Since it is calculated with poker 24 spot , That shuffle 、 Licensing operations are essential . Why did you create such a large window , It is also to leave enough space for licensing .

Shuffle

When the game starts , Or the deck is used up , It's about to start shuffling . So for the convenience of calling , We create a custom function .

import random
def shuffle_card():
global cardnum, back, cv_back
cardnum = list(range(52))
random.shuffle(cardnum)
# A pile of cards that have been shuffled , On the left side of the window 
back = PhotoImage(file=r"image\poker\back1.png")
cv_back = cv.create_image(100,200,image = back)

random Module is our old friend , To achieve random effects , We call when shuffling random.shuffle Method , take 52 A digital (0 To 51) The order of is random ,cardnum This list will become an irregularly arranged list . Just right shuffle It means to shuffle the cards , therefore , Use this method here , It's a perfect fit .cardnum Methods need to be called by the main program and other functions , So use global Keyword to declare it as a global variable .

After shuffling the cards , I want to display a picture of the back of a playing card on the left side of the window , There are cards in the stack . Due to limited energy , The thickness of the stack is not realized ( Of course, it is also possible to realize ). To keep the picture on the back of the playing card displayed , You also need to declare it as a global variable .

The effect of the code running is as follows :

Licensing

We can simulate the action of dealing cards in reality , There are two steps to licensing :1) Show cards at the top of the stack ,2) Move the card to the specified position .

When the front shuffles , We have created a 0 To 51 A disordered list of numbers cardnum, Now we just need to put this 52 Numbers correspond to pictures , You can catch the cards , Automatically display the picture of playing cards .

First , Create a list of poker pictures .

card = [PhotoImage(file=f'image/poker/{
i:0>2}.png') for i in range(1,53)]

Ask brother to prepare the poker picture from 01 Start naming , So you need to use the formatting method , take 01 To 52 The digitally named pictures are read into the list card in .

next , We customize a draw 、 Licensing functions :

import tkinter.messagebox as tm
def draw_card():
draw=[]
if len(cardnum)==0:
tm.showinfo(message=' The deck has been used up , Reshuffle your cards ')
shuffle_card()
for i in range(4):
# Simulate a draw : Deck cardnum A card pops up at the end , Put it in the list of cards to show draw in 
draw.append(cardnum.pop())
# Show cards at the top of the stack 
cv_card.append(cv.create_image(100,200,image=card[draw[i]]))
# If you finish the last four cards , Delete the picture on the back of the card ( Detail control )
if len(cardnum)==0:cv.delete(cv_back)
# call canvas Of move Method , Move the card to the specified position , Achieve licensing effect 
for _ in range(150*(i+1)):
cv.move(cv_card[i],1,0)
cv.update()

There are several details :

  1. When the last four cards in the deck are captured , The picture on the back of the card should be deleted . Then the next time you deal , Call shuffled shuffle_card() function
  2. Canvas Of move The method is actually very simple , Because we are “ Hold the cards ” after , The pictures of the four cards have been named ( In the list cv_card in ), therefore move The function only needs to pass three parameters move(cv_card[i],1,0), The first parameter indicates which image to move , The second parameter 1 Indicates abscissa movement 1 Pixels , The third parameter 0 Indicates that the vertical coordinate is unchanged .
  3. Every time I move to the right 1 Pixels , loop 150 All over ( second 、 3、 ... and 、 Four cards have more cycles ), And in each cycle , Must call Canvas Of update() Method , Display the picture of each pixel .
  4. In the previous article , Because it is a static interface , Ask brother to suggest canvas Of pack Method at the end . But because this time we want to dynamically achieve some animation effects , So we need to canvas“ Mounting ” Up , To play animation on it .

The effect of the final deal is as follows :

3). timer

When drawn out 4 After playing cards and showing them , We first have to let the program calculate , These four cards are combined in various permutations , Can you come to 24 spot . The calculation method of this part will be introduced in the next chapter . If there is a definite solution , It can be concluded that 24 spot , We're about to start timing .

Brother Wen introduced the making of timers in his previous article , Here you can take it directly . Of course , Or default 90 Second countdown .

Python Animation production :90 Second countdown round progress bar effect

The specific code has been explained in this article , So I won't be too verbose here . But the code here also solves the last question in that little article : If you achieve a smooth progress bar .

The code is as follows :

def initialize():
global angle,count,cv_arc,cv_inner,cv_text
count=90
angle=360
cv_arc=cv.create_oval(100,330,200,430,fill='red',outline='yellow')
cv_inner=cv.create_oval(120,350,180,410,fill='yellow',outline='yellow')
cv_text=cv.create_text(150,380,text=count,font =(' Microsoft YaHei ',20,'bold'),fill='red')
draw_card()
def countdown():
global angle,count,cv_arc,cv_inner,cv_text,cd
if angle == 360:
angle -= 1
else:
cv.delete(cv_arc)
cv.delete(cv_inner)
cv.delete(cv_text)
cv_arc=cv.create_arc(100,330,200,430,start=90,extent=angle,fill="red",outline='yellow')
angle -= 1
if angle%4 == 0: count-=1
cv_inner=cv.create_oval(120,350,180,410,fill='yellow',outline='yellow')
cv_text=cv.create_text(150,380,text=count,font =(' Microsoft YaHei ',20,'bold'),fill='red')
if count==0:
tm.showinfo(message=' The countdown is over ! Automatically enter the next round ')
cv.delete(cv_arc)
cv.delete(cv_inner)
cv.delete(cv_text)
initialize()
else:
cd = root.after(250,countdown)

in addition , Brother Wen has defined another name here initialize() Function of , The translation is initialization , The purpose is to put some repetitive work into it , For example, the circle that blocks the progress bar . therefore , We can put the card grabbing function draw_card() Put it inside , In the main program, you only need to call initialize() that will do .

The effect is as follows :

4). The player enters a formula ( answer )

There are many ways to make it possible for players to enter answers from the keyboard , I would like to take this opportunity to introduce a “ Event binding " Methods .

First , Create a Label Tag components , Same as Button Button components 、Canvas Canvas components , The label component is also tkinter The next component , It is easy to understand why Canvas The same level . To be in Canvas Display components of the same level on the , We need to use the create_window Method .

answer=StringVar()
cv.create_text(400,350,text=' Please enter your answer ',font =(' Square regular script, simplified Chinese ',18,'bold'))
lb = Label(root,text='',font=(' Microsoft YaHei ',15),textvariable=answer,bg='lightyellow')
cv_lb = cv.create_window(400,400,window=lb)
# Binding gets input from the keyboard <Key>, And pass it to the user-defined function myanswer
lb.bind('<Key>',myanswer)
# Get the tag component into focus , Otherwise, you cannot input from the keyboard 
lb.focus_set()

StringVar class

First of all, here is a definition of tkinter Under the StringVar Class , In fact, it represents a string , But more than ordinary string variables “ intelligence ”. such , When we're in Label Use... In components textvariable Parameters , After specifying this instance , It can be dynamically bound together . in other words StringVar Into what content ,Label The component will be displayed automatically , It is much simpler and more convenient than the assignment operation .

Key event binding

Create good Label After label assembly , You can use bind() Method to bind a Key event , Represents the input content of the keyboard , Then the input is implicitly passed to myanswer This custom callback function , This function is used to assign the keyboard input to StringVar, And then in Label It shows that .

The function is defined as follows :

trans={
'plus':'+','minus':'-','asterisk':'*','slash':'/','parenleft':'(','parenright':')'}
def myanswer(event):
s=event.keysym
txt=answer.get()
if s=='BackSpace':
txt=txt[:-1]
elif s=='Return':
if is_right(txt):
root.after_cancel(cd)
c = tm.askyesno(message=' Go on to the next game ?')
if c:
cv.delete(cv_arc)
cv.delete(cv_inner)
cv.delete(cv_text)
initialize()
else:root.destroy()
else:
txt=''
elif s.isnumeric():
txt+=s
elif s in trans:
txt+=trans[s]
answer.set(txt)

event Is a variable implicitly passed in by the event binding function , and event.keysym It represents the current ( Trigger ) The characters obtained by this function , That is, which key was pressed from the keyboard . Be careful , Just press one key here , It will trigger myanswer Callback function , therefore event.keysym The value of represents only one character at a time .

But the display form of this character is different from what we usually think . In addition to single character keys such as numbers and letters , Direction key 、 Symbols and so on are all expressed in one word , and event.keysym It's the same word , Not the arrow keys 、 Symbols and other special characters . therefore , Let's create a dictionary here trans, Come and take event.keysym The resulting symbol , Like addition, subtraction, multiplication and division 、 Parentheses, etc , Convert to correct characters + - * / ( ) Show it .

We also need to limit the characters that players can enter , Except for numbers and arithmetic symbols + 0 * / ( ), There are also carriage return and backspace ( Delete ), Players should not react when they press any other key .

Each time the player enters a character , All use answer.get() Method to get the current Label Characters on , Then carry out corresponding operations ( Delete 、 Add characters ), Finally through answer.set() Method to display the new string in the Label On .

besides , This function also contains a function ,is_right(), When the player presses enter (Return) When , This function is used to judge the current Label Whether the characters on the can calculate 24, To judge the outcome . If you can , Then cancel the timer (cd), Then start the next round , If not , be “ wipe ” Drop the current answer , Ask the player to re-enter .

5). Determine whether the player's input is correct

is_right() Functions are part of the code implementation , But brother Wen thinks this function is related to the callback function above , I decided to introduce it in the last chapter .

In addition to determining whether it can calculate 24 outside , Also make sure that players only use , And used up the given 4 A digital . Then the arithmetic symbols in the resulting equation are removed , Then divide it into numbers , Just match the current deck number nums contrast , If different , It means that the player did not use the correct number .

To prevent players from entering the denominator 0 And so on , Use here try…except Method to judge .eval() Function is used to convert the string of an arithmetic expression into a real expression for calculation , And if the denominator is 0, More or less parentheses , Wait, the expression is wrong , An error prompt will be thrown directly .

import math
def is_right(txt):
try:
result = eval(txt)
except:
tm.showinfo(message=' The formula is incorrect , Please re-enter !')
return False
for i in '+-*/()':
txt=txt.replace(i,' ')
txt=[int(i) for i in txt.split()]
if sorted(txt)!=sorted(nums):
tm.showinfo(message=' Please use the given number !')
return False
if math.isclose(result,24):
tm.showinfo(message=' Congratulations ! Correct answer !')
return True

Last but not least , Because we're calculating 24 In the process of dot , It is quite possible to use division , And once you use division , The result must be a floating point number . Because computers use binary to represent floating point numbers , So once some decimals can not be completely expressed in binary , There will be an infinite circular decimal , Produce errors . So here, if you directly use if result==24 To judge , In some cases, you will not get the correct results , such as 23.999999 and 24 Is not equal , but 23.999999 It may be caused by division in the calculation process .

So we use math Modular isclose Method .math.isclose(result, 24) It means that the difference between two numbers is in a very small range , The two numbers are the same .

The final effect is as follows :

4. Knowledge review

  1. Canvas Of move Method
  2. Component's event binding
  3. StringVar type


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved