![]() |
How to test the high-score in my Python-game - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: How to test the high-score in my Python-game (/thread-40829.html) |
How to test the high-score in my Python-game - Pluviometer - Oct-02-2023 We have even taken turns introducing each other to new genres and types of porn we may not have explored before. https://gayporn.name/categories/ghetto/ https://freegayporn.club/categories/japanese/ https://gaypornwebsite.com/tags/chubby-crossdresser/ RE: How to test the high-score in my Python-game - Gribouillis - Oct-02-2023 (Oct-02-2023, 09:23 AM)Pluviometer Wrote: How do I come around this problem?Suppose you programmed a chess game and you want to test the checkmate feature. You could inject a chess position where there is a checkmate at the next move, then continue from here. You could do the same with your game. Design it so that you can inject a predefined state of the whole game just before the high-score is reached. This is interesting because it forces you to define a structure that can store the whole state of the game. Another thing you could consider is to add the capability to play a whole game without human interaction, with the computer playing predefined moves for example. RE: How to test the high-score in my Python-game - deanhystad - Oct-02-2023 For a program as complex as a game, you must have organized your code into functions and/or classes. To test these functions/classes you should write a test program. This is a minesweeper game that I have laying around. """Minesweeper game. Find all safe squares while avoiding bombs.""" import random import time import datetime import tkinter as tk from tkinter import messagebox from collections import defaultdict class Cell(tk.Button): """A button for the Minsweeper game. Press me to reveal a bomb or information about surrounding bombs. """ def __init__(self, parent, row, column, count): super().__init__( parent, text=" ", width=2, relief=tk.RAISED, command=self.press ) self.parent = parent self.row = row self.column = column self.count = count self.pressed = False self.flagged = False self.bind("<Button-3>", self.flag) def press(self): """Button pressed. Show bomb info""" if not self.pressed: self.configure(relief=tk.SUNKEN) self.pressed = True self["text"] = "X" if self.count < 0 else str(self.count) self.parent.clear_cell(self) def flag(self, _): """Right mouse button pressed. Toggle flag marker""" if not self.pressed: self.flagged = not self.flagged self["text"] = "F" if self.flagged else " " class Board(tk.Tk): """Minesweeper playing surface. I make a grid of buttons that are pressed to reveal bombs or information about surrounding bombs. """ neighbors = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)) def __init__(self, rows, columns, bomb_count): super().__init__() self.title("Minesweeper") self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.rows = rows self.columns = columns self.safe_count = rows * columns - bomb_count # Make all the bombs bombs = defaultdict(lambda: 0) for index in random.sample(range(rows * columns), k=bomb_count): bombs[(index // columns, index % columns)] = 1 # Make the map self.cells = [] for row in range(rows): for column in range(columns): # Count bombs in surrounding cells. Use -1 to indicate # cell contains a bomb. if bombs[(row, column)]: count = -1 else: count = sum(bombs[(row + r, column + c)] for c, r in self.neighbors) cell = Cell(self, row, column, count) cell.grid(row=row, column=column) self.cells.append(cell) # Add status display to bottom of window self.done = False self.status = tk.Label(self, text="") self.status.grid(row=rows, column=0, columnspan=columns) self.start_time = time.time() self.update_status() def cell(self, row, column): """Return cell at (row, column)""" if 0 <= row < self.rows and 0 <= column < self.columns: return self.cells[row * self.columns + column] raise IndexError def clear_cell(self, cell): """Cell was selected""" if cell.count < 0: self.done = True messagebox.showinfo("Today marks the passing of you.") else: self.safe_count -= 1 if self.safe_count <= 0: self.done = True messagebox.showinfo("Winner, winner, chicken dinner!") elif cell.count == 0: # All surrounding cells are save. Open them for c, r in self.neighbors: try: self.cell(cell.row + r, cell.column + c).press() except IndexError: pass def update_status(self): """Update status display""" delta = str(datetime.timedelta(seconds=int(time.time() - self.start_time))) self.status["text"] = f"{delta} Remaining {self.safe_count}" if not self.done: self.after(1000, self.update_status) Board(10, 10, 10).mainloop()The first step to writing a test is take the code on the bottom of the file and reorganize so it is not run when the file is imported in a test program. if __name__ == "__main__": Board(10, 10, 10).mainloop()If this was more than a single line I would write a main() function. def main(): board = Board(10, 10, 10) board.mainloop() if __name__ == "__main__": main()Now I can import my game module into my test program. Lets say I was having a problem with the Cell class not showing the correct count. I can write a program that creates a cell and tests the functions. test.py import tkinter as tk from minesweeper import Cell # Need to make a tkinter root window to test Cell root = tk.Tk() # Make a cell that has a bomb. Press the cell and verify # the button shows "X" cell = Cell(root, 1, 1, -1) cell.press() print(cell["text"])When I run the program I get an error. My Cell clas calls parent.clear_cell(). My test program needs to make a "test fixture" that provides this functionality.import tkinter as tk from minesweeper import Cell # Need to make a tkinter root window to test Cell class TestWindow(tk.Tk): def __init__(self): super().__init__() self.cell = Cell(self, 1, 1, 0) def clear_cell(self, cell): """Dummy method to make Cell happy.""" def test(self, count): """Veify that Cell displays the correct text when pressed.""" self.cell.count = count self.cell.pressed = False self.cell.press() expected_text = "X" if count < 0 else str(count) return self.cell["text"] == expected_text testWindow = TestWindow() for i in range(-1, 9): print("Test", i, testWindow.test(i)) All my tests passed. If I am having problems with the button labels, it must be something outside Cell.While testing I decide to write a test to verify Cell.flag() works. # Need to make a tkinter root window to test Cell class TestWindow(tk.Tk): def __init__(self): super().__init__() self.cell = Cell(self, 1, 1, 0) def testFlag(self, flag): """Veify that toggling the flag works.""" self.cell.pressed = False self.cell.flagged = flag == "F" self.cell["text"] = flag self.cell.flag(None) expected_text = " " if flag == "" else "F" return self.cell["text"] == expected_text testWindow = TestWindow() print('testFlag("F")', testWindow.testFlag("F")) print('testFlag(" ")', testWindow.testFlag(" ")) I like this way of testing. I do some research and see there are python packages to simplify writing tests. I find something called unittest that is included with my python distribution.https://docs.python.org/3/library/unittest.html I restructure my test code to be compatible with unittest. import tkinter as tk from minesweeper import Cell import unittest # Need to make a tkinter root window to test Cell class TestWindow(tk.Tk): def __init__(self): super().__init__() self.withdraw() self.cell = Cell(self, 1, 1, 0) def clear_cell(self, cell): """Dummy method to make Cell happy.""" def set_count(self, count): self.cell.count = count self.cell.pressed = False self.cell.press() return self.cell["text"] def toggle_flag(self, flag): self.cell.pressed = False self.cell.flagged = flag == "F" self.cell["text"] = flag self.cell.flag(None) return self.cell["text"] class CellTestCase(unittest.TestCase): def setUp(self): self.window = TestWindow() def tearDown(self): self.window.destroy() def test_cell_press(self): self.assertEqual(self.window.set_count(-1), "X") for i in range(8): self.assertEqual(self.window.set_count(i), str(i)) def test_toggle_flag(self): self.assertEqual(self.window.toggle_flag("F"), " ") self.assertEqual(self.window.toggle_flag(" "), " ")I run the unittest from the commandline. The test find the error I intentionally left in the test code. I correct the test and run again. Another popular testing framework is pytest.https://docs.pytest.org/en/7.4.x/ I change my test program to be compatible with pytest. import tkinter as tk from minesweeper import Cell import pytest # Need to make a tkinter root window to test Cell class Window(tk.Tk): def __init__(self): super().__init__() self.withdraw() self.cell = Cell(self, 1, 1, 0) def clear_cell(self, cell): """Dummy method to make Cell happy.""" def set_count(self, count): self.cell.count = count self.cell.pressed = False self.cell.press() return self.cell["text"] def toggle_flag(self, flag): self.cell.pressed = False self.cell.flagged = flag == "F" self.cell["text"] = flag self.cell.flag(None) return self.cell["text"] @pytest.fixture def window(): return Window() def test_cell_press(window): assert window.set_count(-1) == "X" for i in range(8): assert window.set_count(i) == str(i) def test_toggle_flag(window): assert window.toggle_flag("F") == " " assert window.toggle_flag(" ") == " "Notice I put the error back in the test_togle_flag test. I run the test.
|