· 6 years ago · Apr 11, 2019, 11:08 PM
1import pygame
2import os
3import sys
4import pygame.freetype
5import time
6import random
7from pygame.locals import *
8from tkinter import ttk
9from tkinter import *
10from tkinter import messagebox
11import sqlite3
12import tkinter
13
14import inputbox #This is needed to add an interface where the user can input the anwser to the math question
15import random #The function "random" is used in the get_single_question() to choose a random question from the database
16
17questions_already_solved=[0] #Array needed when the user resolve a question, so it doesn't appear anymore
18
19#QUEUE DATA STRUCTURE~~~~~~~~~~~~~~~~~~~~~~~~~
20class Queue:
21 def __init__(self):
22 #Initiates queue
23 self.items = []
24
25 def isEmpty(self):
26 #If queue returns an empty list, then the queue is empty
27 return self.items == []
28
29 def enqueue(self, item):
30 #Inserts a new element into the queue, regarding 0 as the rear position
31 self.items.insert(0,item)
32
33 def dequeue(self):
34 #Pop function is used to remove an element from the queue
35 return self.items.pop()
36
37 def size(self):
38 #checks size of queue
39 return len(self.items)
40
41#SQL DATABASES~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42def SQLQuestion():
43 with sqlite3.connect("games.db") as db:
44 cursor = db.cursor()
45
46 cursor.execute("""CREATE TABLE IF NOT EXISTS game (
47 questionID integer PRIMARY KEY AUTOINCREMENT,
48 question text,
49 answer text
50 )""")
51
52def SQLUser():
53 with sqlite3.connect("User.db") as db:
54 cursor = db.cursor()
55
56 cursor.execute("""CREATE TABLE IF NOT EXISTS user (
57 userID INTEGER PRIMARY KEY,
58 username VARCHAR(20) NOT NULL,
59 password VARCHAR(20) NOT NULL,
60 usertime INTEGER
61 )""")
62
63#USER LOG IN/CREATE/DELETE ACCOUNT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
64class user1():
65
66 def __init__(self, username, password, usertime):
67 self.username = username
68 self.password = password
69 self.usertime = usertime
70
71def GetUserTime(delta_time_s, usID):
72 print(type(usID))
73 with sqlite3.connect("User.db") as db:
74 c = db.cursor()
75 c.execute("UPDATE user SET usertime = ? WHERE userID = ?", (delta_time_s, usID[0]))
76 db.commit()
77 c.execute("SELECT usertime FROM user WHERE userID = ?", (usID))
78 GetTime = c.fetchone()[0]
79 user1(username=None, password=None,usertime=GetTime)
80
81def GetUserName(usID):
82 with sqlite3.connect("User.db") as db:
83 c = db.cursor()
84 c.execute("SELECT username FROM user WHERE userID = ?", (usID))
85 Getusername = c.fetchone()[0]
86 user1(username=GetUserName, password=None,usertime=None)
87 return(Getusername)
88
89def login(usernameLogin, passwordLogin,btn):
90 while True:
91 username = usernameLogin.get() #Fetches username
92 password = passwordLogin.get() #Fetches password
93 with sqlite3.connect("User.db") as db: #Creates a connection to database
94 c = db.cursor()
95 find_user = ("SELECT * FROM user WHERE username = ? AND password = ?")#Validates inputs for account
96 c.execute(find_user,[(username),(password)])
97 results = c.fetchall() #Fetches values from database for the validation process
98
99 if results: #Validates if the username/password is recognised by checking if it exists within the database
100 for i in results:
101 nameid = i[1]
102 c.execute("SELECT userID FROM user WHERE username = ?",(nameid,))
103 global usID #Global variable (ID) used to identify user account
104 usID = c.fetchone()
105 messagebox.showinfo("", "Welcome "+i[1]+"!")
106 btn.destroy()
107 QuestionMenu(usID)
108 break
109
110 else:
111 messagebox.showinfo("", "Password and username is not recognised")
112 break
113 window.destroy()
114
115def newUser(username1, password1):
116 found = 0
117 while found == 0:
118 username = username1.get()
119 with sqlite3.connect("User.db") as db:
120 c = db.cursor()
121 findUser = ("SELECT * FROM user WHERE username = ?")
122 c.execute(findUser, [(username)]) #Checks existence of username in database using tuple in execution
123
124 if c.fetchall(): #If statement validates username to see if it exists in the database
125 messagebox.showinfo("Username", "Username taken please try again.")
126 break
127 else:
128 messagebox.showinfo("", "Account has been created!")
129 found = 1
130
131 password = password1.get()
132 insertData = '''INSERT INTO user(username, password)
133 VALUES(?,?)'''#Inserts new account into database with the new values
134 c.execute(insertData, [(username),(password)])
135 db.commit()
136
137def newUserTkinter():
138 window = tkinter.Tk()
139 window.title("Create new account")
140
141 labelOne = ttk.Label(window, text = "Enter a username:")
142 labelOne.grid(row = 0, column = 0)
143 username1 = tkinter.StringVar(window)#value type is classified as a string
144 usernameEntry = ttk.Entry(window, width = 30, textvariable = username1)
145 usernameEntry.grid(row = 1, column = 0)
146
147 labelTwo = ttk.Label(window, text = "Enter a password:")
148 labelTwo.grid(row = 2, column = 0)
149 password1 = tkinter.StringVar(window)#value type is classified as a string
150 passwordEntry = ttk.Entry(window, width = 30, textvariable = password1)
151 passwordEntry.grid(row = 3, column = 0)
152
153 btn = ttk.Button(window, text="Submit", command=lambda: newUser(username1, password1))
154 btn.grid(row = 3, column = 1)
155
156def removeUser(usernameD, passwordD):
157 exists = 0
158 while exists == 0:#Validates exsistence of account username
159 username = usernameD.get()
160 password = passwordD.get()
161 with sqlite3.connect("User.db") as db:
162 c = db.cursor()
163 findUser = ("SELECT * FROM user WHERE username = ?")
164 c.execute(findUser, [(username)])
165
166 if c.fetchall():
167 messagebox.showinfo("Delete account", "Account deleted!")
168 exists = 1
169 else:
170 messagebox.showinfo("", "Account does not exist")
171 break
172
173 remove_user = ("DELETE from user WHERE username = ? AND password = ?")
174 c.execute(remove_user,[(username),(password)])
175 db.commit()
176
177def removeUserTkinter():
178 window = tkinter.Tk()
179 window.title("Delete account")
180
181 labelOne = ttk.Label(window, text = "Enter account username:")
182 labelOne.grid(row = 0, column = 0)
183 usernameD = tkinter.StringVar(window)#value type is classified as a string
184 usernameEntry = ttk.Entry(window, width = 30, textvariable = usernameD)
185 usernameEntry.grid(row = 1, column = 0)
186
187 labelTwo = ttk.Label(window, text = "Enter account password:")
188 labelTwo.grid(row = 2, column = 0)
189 passwordD = tkinter.StringVar(window)#value type is classified as a string
190 passwordEntry = ttk.Entry(window, width = 30, textvariable = passwordD)
191 passwordEntry.grid(row = 3, column = 0)
192
193 btn = ttk.Button(window, text="Submit", command=lambda: removeUser(usernameD, passwordD))
194 btn.grid(row = 3, column = 1)
195
196def menu():
197 with sqlite3.connect("User.db") as db:
198 c = db.cursor()
199 c.execute("SELECT * FROM user")
200 print(c.fetchall())
201
202 window = tkinter.Tk()
203 window.title("Treasure Hunt Game!")
204
205 labelOne = ttk.Label(window, text = """ ~~~~~~~~~~~~~ USER MENU ~~~~~~~~~~~~~
206 """)#label displays instruction
207 labelOne.grid(row = 0, column = 0)#places label in a grid
208
209 btn = ttk.Button(window, text = "Create account", command = newUserTkinter)
210 btn.grid(row = 1, column = 0)#places button in a grid
211
212 btn = ttk.Button(window, text = "Delete account", command = removeUserTkinter)
213 btn.grid(row = 2, column = 0)#places button in a grid
214
215 photo = tkinter.PhotoImage(file = "logo.gif")
216 imglabel = ttk.Label(window, image = photo)
217 imglabel.image = photo
218 imglabel.grid(row = 3, column = 0)
219
220 labelTwo = ttk.Label(window, text = "Login to your account:")
221 labelTwo.grid(row = 4, column = 0)
222
223 usernameLogin = tkinter.StringVar(window)#value type is classified as a string
224 usernameEntry = ttk.Entry(window, width = 30, textvariable = usernameLogin)
225 usernameEntry.grid(row = 6, column = 0)
226
227 labelTwo = ttk.Label(window, text = "Username")
228 labelTwo.grid(row = 5, column = 0)
229
230 passwordLogin = tkinter.StringVar(window)#value type is classified as a string
231 passwordEntry = ttk.Entry(window, width = 30, textvariable = passwordLogin)
232 passwordEntry.grid(row = 8, column = 0)
233 passwordEntry.config(show="*") #Used to hide password on screen
234
235 labelTwo = ttk.Label(window, text = "Password")
236 labelTwo.grid(row = 7, column = 0)
237
238 btn = ttk.Button(window, text="Log in", command=lambda: login(usernameLogin, passwordLogin, window))
239 btn.grid(row = 8, column = 1)
240
241#SQL QUESTION ADD/REMOVE/GET~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
242def insert_question(emp):
243 conn = sqlite3.connect('games.db')
244 c = conn.cursor()
245 c.execute("INSERT INTO game VALUES (?, ?, ?)", (emp))
246 conn.commit()
247
248def get_question():
249 conn = sqlite3.connect('games.db')
250 c = conn.cursor()
251 c.execute("SELECT * FROM game")
252 return c.fetchall()
253
254def get_number_total_question(): #Gets the total number of questions within the database
255 conn = sqlite3.connect('games.db')
256 c = conn.cursor()
257 c.execute("SELECT COUNT(*) FROM game")
258 return c.fetchone()[0]
259
260def get_single_question(question_number): #Gets the question from the database
261 conn = sqlite3.connect('games.db')
262 c = conn.cursor()
263 c.execute("SELECT question FROM game WHERE questionID="+str(question_number))
264 return c.fetchone()[0]
265
266def get_answer(question_number): #Gets the answer from the database
267 conn = sqlite3.connect('games.db')
268 c = conn.cursor()
269 c.execute("SELECT answer FROM game WHERE questionID="+str(question_number))
270 return c.fetchone()[0]
271
272def remove_question(emp):
273 conn = sqlite3.connect('games.db')
274 c = conn.cursor()
275 c.execute("DELETE from game WHERE question = ?", [emp])
276 conn.commit()
277
278#Game Menu Tkinter~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
279def showInstructions():
280 messagebox.showinfo("Instructions", """You are a treasure hunter, your goal is to collect atleast 100
281gold by the end of the game from treasure chests randomly scattered across the grid.There are 10 chests within a grid and
282each treasure chest is worth 10 gold but can only be reclaimed 3 times before it is replaced by a bandit.
283Landing on a bandit will cause you to lose all of your
284gold and if all the chests have been replaced by bandits and you have less then 100 gold this means you lose!
285
286Press enter to continue...""")#messagebox used for more simple functions (showing messages)
287
288def Add2leaderboard(delta_time_s):
289 with open("high_scores.txt","a") as f:
290 f.write(GetUserName(usID) + ' | ' + str(delta_time_s) + " seconds" + os.linesep)
291 f.close()
292
293def showLeaderboard():
294 with open("high_scores.txt") as f:
295 messagebox.showinfo("Leaderboard",f.read())
296
297def con():
298 messagebox.showinfo("Game", "Time to play!")
299 pass
300 game()
301
302def showQuestions():
303 emps = get_question()
304 messagebox.showinfo("List of questions/answers", emps)
305
306def AddQuestion(mathquestion, mathanswer):
307 mathquestion1 = mathquestion.get()
308 mathanswer1 = mathanswer.get()
309 emp_1 = (None, mathquestion1, mathanswer1)
310 insert_question(emp_1)
311 messagebox.showinfo("Question inputed!")
312
313 emps = get_question()
314 print(emps)
315
316def removeQuestion(DeleteQuestion):
317 exists = 0
318 while exists == 0:#Validates exsistence of question
319 DeleteQuestion1 = DeleteQuestion.get()
320 conn = sqlite3.connect('games.db')
321 c = conn.cursor()
322 findQuestion = ("SELECT * FROM game WHERE question = ?")
323 c.execute(findQuestion, [(DeleteQuestion1)])
324
325 if c.fetchall():
326 messagebox.showinfo("Delete qustion","Question deleted!")
327 exists = 1
328 else:
329 messagebox.showinfo("","Question does not exist")
330 break
331
332 remove_question(DeleteQuestion1)
333
334def removeQuestionTk():
335 window = tkinter.Tk()
336 window.title("Remove a question.")
337
338 labelOne = ttk.Label(window, text = "Enter question to remove:")
339 labelOne.grid(row = 0, column = 0)
340 DeleteQuestion = tkinter.StringVar(window)#value type is classified as a string
341 questionEntry = ttk.Entry(window, width = 30, textvariable = DeleteQuestion)
342 questionEntry.grid(row = 1, column = 0)
343
344 btn = ttk.Button(window, text="Submit", command=lambda: removeQuestion(DeleteQuestion))
345 btn.grid(row = 1, column = 1)
346
347def QuestionMenu(getID):
348 with sqlite3.connect("games.db") as db:
349 c = db.cursor()
350
351 with sqlite3.connect("user.db") as us:
352 u = us.cursor()
353
354 u.execute("SELECT username FROM user WHERE userID = ?",(getID))
355 username = u.fetchone()[0]
356 MenuName = ("Welcome",username,"!")
357
358 window = tkinter.Tk()
359 window.title("Treasure Hunt Game!")
360
361 labelOne = ttk.Label(window, text = """ ~~~~~~~~~~~~~ GAME MENU ~~~~~~~~~~~~~
362 """)#label displays instruction
363 labelOne.grid(row = 0, column = 0)#places label in a grid
364
365 labelname = ttk.Label(window, text = MenuName)
366 labelname.grid(row = 1, column = 0)
367
368 btn = ttk.Button(window, text = "View instructions", command = showInstructions)#label displays instruction
369 btn.grid(row = 2, column = 0)#places button in a grid
370
371 btn = ttk.Button(window, text = "View leaderboard", command = showLeaderboard)
372 btn.grid(row = 3, column = 0)
373
374 btn = ttk.Button(window, text = "View all questions", command = showQuestions)
375 btn.grid(row = 4, column = 0)
376
377 btn = ttk.Button(window, text = "Continue", command = con)
378 btn.grid(row = 5, column = 0)
379
380 labelTwo = ttk.Label(window, text = "Enter a math question:")
381 labelTwo.grid(row = 6, column = 0)
382 mathquestion = tkinter.StringVar()#value type is classified as a string
383 userEntryQ = ttk.Entry(window, width = 30, textvariable = mathquestion)
384 userEntryQ.grid(row = 7, column = 0)
385
386 labelTwo = ttk.Label(window, text = "Enter the answer to this question:")
387 labelTwo.grid(row = 8, column = 0)
388 mathanswer = tkinter.StringVar()
389 userEntryQ = ttk.Entry(window, width = 30, textvariable = mathanswer)
390 userEntryQ.grid(row = 9, column = 0)
391
392 btn = ttk.Button(window, text = "Submit", command=lambda: AddQuestion(mathquestion, mathanswer))
393 btn.grid(row = 9, column = 1)
394
395 btn = ttk.Button(window, text = "Remove a question", command = removeQuestionTk)
396 btn.grid(row = 10, column = 0)#places button in a grid
397
398SQLUser()
399SQLQuestion()
400menu()
401
402#MAIN GAME~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
403
404#colours
405black = (0, 0, 0)
406white = (255, 255, 255)
407brown = (153, 76, 0)
408blue = (0, 0, 255)
409grey = (192,192,192)
410
411#game dimensions (20,30,20) BASE VALUES
412tilesize = 20
413mapwidth = 30
414mapheight = 20
415
416#Identifiers for different variables
417coins = 0
418ship = 1
419water = 2
420rock = 3
421movesMade = 4
422stopwatch = 5
423
424#Dictionary used for the value of the widgets that will be shown in game
425inventory = {
426 coins: 0,
427 movesMade: 0,
428 stopwatch: ""
429 }
430
431#position of the player
432playerPos = [0,0]
433
434#List of variables that will change in game
435resources = [coins, movesMade, stopwatch]
436
437#
438def playsound():
439 pygame.mixer.music.load("explosion.mp3")
440 pygame.mixer.music.play()
441
442def game():
443 pygame.mixer.init()
444 print(usID)
445 pygame.init() #Initiates Pygame
446 pygame.display.set_mode((200,200)) #Sets window display of Pygame (x,y)
447
448 #Dictionary for texture of the map
449 textures = { #The transform function scales the photo to the tile size
450 ship : pygame.transform.smoothscale(pygame.image.load('ship3.png').convert_alpha(), (tilesize, tilesize)),
451 water: pygame.transform.smoothscale(pygame.image.load('water.png'), (tilesize, tilesize)),
452 rock: pygame.transform.smoothscale(pygame.image.load('rock1.png').convert_alpha(), (tilesize, tilesize)),
453 coins: pygame.transform.smoothscale(pygame.image.load('chest.png'), (tilesize, tilesize)),
454 movesMade: pygame.transform.smoothscale(pygame.image.load('player.png'), (tilesize, tilesize)),
455 stopwatch: pygame.transform.smoothscale(pygame.image.load('stopwatch.png'), (tilesize, tilesize))
456 }
457
458 #image that will represent player
459 PLAYER = pygame.transform.smoothscale(pygame.image.load('player.png'), (tilesize, tilesize))
460
461 #utilise list comprehension to create grid
462 tilemap = [[water for w in range(mapwidth)] for h in range(mapheight)]
463
464 #Window display is set up by multplying width by height and adding extra space at the bottom of the window
465 displaysurf = pygame.display.set_mode((mapwidth*tilesize,mapheight*tilesize + 60))
466
467 #Fonts used to display text
468 font = pygame.freetype.SysFont('Times New Roman', 20)
469 invfont = pygame.font.Font('FreeSansBold.ttf', 18)
470
471 #loops through each row - Creates the game map
472 coinstot=0 #TEST
473 coins_per_row=0 #TEST
474 for rw in range(mapheight):
475 for cl in range(mapwidth):
476 randomnumber = random.randint(0,15)
477 if randomnumber == 0 or randomnumber == 1:
478 tile = rock
479 elif randomnumber == 2 or randomnumber == 3 :
480 tile = ship
481 #elif randomnumber == 4 and coins_per_row<1 and coinstot<=10 : #TEST
482 # tile = coins #TEST
483 # coins_per_row+=1 #TEST
484 else:
485 tile = water
486 #sets position in the grid
487 tilemap[rw][cl] = tile
488 coinstot+=coins_per_row #TEST
489 coins_per_row=0 #TEST
490
491 #List holds location values of past visited tiles
492 visit = {}
493 start_time = pygame.time.get_ticks() #Sets start time for game
494 while True:
495 displaysurf.fill(black) #Background color
496
497 #user events
498 for event in pygame.event.get():
499 if event.type == QUIT:
500 pygame.quit()
501 sys.exit()
502 elif event.type == KEYDOWN: #If statement checks within the event, what keys have been clicked
503 if event.key == K_RIGHT and playerPos[0] < mapwidth - 1:
504 NextTileX1 = tilemap[playerPos[1]][playerPos[0]+1] #Variable holds position of the next tile in instance that user goes right
505 if NextTileX1 == rock: #Checks if value of the next tile is equal to rock
506 playsound()
507 pass
508 else:
509 playerPos[0] += 1
510 if event.key == K_LEFT and playerPos[0] > 0:
511 NextTileX2 = tilemap[playerPos[1]][playerPos[0]-1] #Variable holds position of the next tile in instance that user goes left
512 if NextTileX2 == rock:
513 playsound()
514 pass
515 else:
516 playerPos[0] -= 1
517
518 if event.key == K_UP and playerPos[1] > 0:
519 NextTileY1 = tilemap[playerPos[1]-1][playerPos[0]] #Variable holds position of the next tile in instance that user goes up
520 if NextTileY1 == rock:
521 playsound()
522 pass
523 else:
524 playerPos[1] -= 1
525
526 if event.key == K_DOWN and playerPos[1] < mapheight -1: #Variable holds position of the next tile in instance that user goes down
527 NextTileY2 = tilemap[playerPos[1]+1][playerPos[0]]
528 if NextTileY2 == rock:
529 playsound()
530 pass
531 else:
532 playerPos[1] += 1
533 if event.key == K_SPACE:
534 pos = (playerPos[1], playerPos[0])
535 if not pos in visit: # checks whether a tile has been used
536 visit[pos] = True
537 currentTile = tilemap[playerPos[1]][playerPos[0]]
538 if currentTile == rock:
539 inventory[movesMade] += 1
540 percent = 30 # coins are kept with a probability of 30 percent and will be lost by 70 percent
541 ran1 = random.randint(0,100) # random value in [0, 99]
542 if ran1 >= percent and inventory[coins] > 30:
543 inventory[coins] -= 30
544 else:
545 inventory[coins] += 20
546
547 elif currentTile == ship:
548 n_question=0 #The question "0" does not exist, so I can use that number to inizialize the variable
549
550 if (len(questions_already_solved)-1)!=get_number_total_question(): #Checks for the limit, limit being total number of questions while n_question in questions_already_solved: #COMMENT THIS LINE TO MAKE THE QUESTIONS REPEATABLE
551 while n_question in questions_already_solved: #COMMENT THIS LINE TO MAKE THE QUESTIONS REPEATABLE
552 n_question=random.randint(1,get_number_total_question()) #INDENT THIS LINE CORRECTLY TO MAKE THE QUESTIONS REPEATABLE
553
554 question = get_single_question(n_question) #Fetches question from the Database
555 system_answer = get_answer(n_question) #Fetches answer of the question from the database
556
557 screen = pygame.display.set_mode((600, 460))
558
559 user_answer = inputbox.ask(screen, question)
560 if user_answer == system_answer: #If statement validates answer
561 messagebox.showinfo("","Correct answer!")
562 inventory[coins] += 100 #10 coins are added to the inventory
563 questions_already_solved.append(n_question) #COMMENT THIS LINE TO MAKE THE QUESTIONS REPEATABLE
564
565 else: #TEST
566 messagebox.showinfo("","Wrong answer!")
567
568 else:
569 screen = pygame.display.set_mode((600, 460))
570 user_answer = inputbox.ask(screen, "No more questions! Press ENTER to continue...")#COMMENT THIS LINE TO MAKE THE QUESTIONS REPEATABLE
571
572
573 #loops through each row
574 for row in range(mapheight):
575 #loops through each column in row
576 for column in range(mapwidth):
577 displaysurf.blit(textures[tilemap[row][column]], (column*tilesize,row*tilesize))
578
579 displaysurf.blit(PLAYER,(playerPos[0]*tilesize,playerPos[1]*tilesize))
580
581 placePosition = 10
582 for item in resources:
583 displaysurf.blit(textures[item],(placePosition, mapheight*tilesize + 20))
584 placePosition += 30
585 #text displays amount of coin
586 textObj = invfont.render(str(inventory[item]), True, white, black)
587 displaysurf.blit(textObj,(placePosition, mapheight*tilesize + 20))
588 placePosition += 50
589
590 if inventory[coins] < 100:
591 current_time = pygame.time.get_ticks() #Displays real time in milliseconds
592 global delta_time_s
593 delta_time_s = (current_time - start_time) // 1000 #Convert from milliseconds to seconds
594
595 text_surf, text_rect = font.render(str(delta_time_s), (255, 255, 255), size=30) #Renders time text to a surface object
596 marginwidth = -30# margins to the window
597 marginheight = -240
598 size = (200, 200) # window size
599 text_pos = (size[0] - text_rect.width - marginwidth, size[1] - text_rect.height - marginheight)
600
601 displaysurf.blit(text_surf, text_pos)
602
603 if inventory[coins] >= 100:
604 print(delta_time_s)
605 GetUserTime(delta_time_s, usID)
606 Add2leaderboard(delta_time_s)
607 break
608
609 pygame.display.update() #Renders the Pygame window