├── README.md └── __main__.py /README.md: -------------------------------------------------------------------------------- 1 | # Towers of Hanoi - Pygame 2 | 3 | Towers of Hanoi puzzle as a game using python3 and pygame 4 | 5 | ## How to play 6 | 7 | You need pygame installed with python 3. On Windows, simply double-click the file. On Linux-based systems, use the command line. 8 | 9 | On the title screen, use arrow keys to select the number of disks, then press ENTER to start. In game, use the LEFT and RIGHT arrow keys to move the pointer, and UP and DOWN arrows to lift and place disks. 10 | 11 | Press ESCAPE to return to the menu screen and Q to quit the game. -------------------------------------------------------------------------------- /__main__.py: -------------------------------------------------------------------------------- 1 | import pygame, sys, time 2 | 3 | pygame.init() 4 | pygame.display.set_caption("Towers of Hanoi") 5 | screen = pygame.display.set_mode((640, 480)) 6 | clock = pygame.time.Clock() 7 | 8 | game_done = False 9 | framerate = 60 10 | 11 | # game vars: 12 | steps = 0 13 | n_disks = 3 14 | disks = [] 15 | towers_midx = [120, 320, 520] 16 | pointing_at = 0 17 | floating = False 18 | floater = 0 19 | 20 | # colors: 21 | white = (255, 255, 255) 22 | black = (0, 0, 0) 23 | red = (255, 0, 0) 24 | gold = (239, 229, 51) 25 | blue = (78,162,196) 26 | grey = (170, 170, 170) 27 | green = (77, 206, 145) 28 | 29 | def blit_text(screen, text, midtop, aa=True, font=None, font_name = None, size = None, color=(255,0,0)): 30 | if font is None: # font option is provided to save memory if font is 31 | font = pygame.font.SysFont(font_name, size) # already loaded and needs to be reused many times 32 | font_surface = font.render(text, aa, color) 33 | font_rect = font_surface.get_rect() 34 | font_rect.midtop = midtop 35 | screen.blit(font_surface, font_rect) 36 | 37 | def menu_screen(): # to be called before starting actual game loop 38 | global screen, n_disks, game_done 39 | menu_done = False 40 | while not menu_done: # every screen/scene/level has its own loop 41 | screen.fill(white) 42 | blit_text(screen, 'Towers of Hanoi', (323,122), font_name='sans serif', size=90, color=grey) 43 | blit_text(screen, 'Towers of Hanoi', (320,120), font_name='sans serif', size=90, color=gold) 44 | blit_text(screen, 'Use arrow keys to select difficulty:', (320, 220), font_name='sans serif', size=30, color=black) 45 | blit_text(screen, str(n_disks), (320, 260), font_name='sans serif', size=40, color=blue) 46 | blit_text(screen, 'Press ENTER to continue', (320, 320), font_name='sans_serif', size=30, color=black) 47 | for event in pygame.event.get(): 48 | if event.type==pygame.KEYDOWN: 49 | if event.key == pygame.K_q: 50 | menu_done = True 51 | game_done = True 52 | if event.key == pygame.K_RETURN: 53 | menu_done = True 54 | if event.key in [pygame.K_RIGHT, pygame.K_UP]: 55 | n_disks += 1 56 | if n_disks > 6: 57 | n_disks = 6 58 | if event.key in [pygame.K_LEFT, pygame.K_DOWN]: 59 | n_disks -= 1 60 | if n_disks < 1: 61 | n_disks = 1 62 | if event.type == pygame.QUIT: 63 | menu_done = True 64 | game_done = True 65 | pygame.display.flip() 66 | clock.tick(60) 67 | 68 | def game_over(): # game over screen 69 | global screen, steps 70 | screen.fill(white) 71 | min_steps = 2**n_disks-1 72 | blit_text(screen, 'You Won!', (320, 200), font_name='sans serif', size=72, color=gold) 73 | blit_text(screen, 'You Won!', (322, 202), font_name='sans serif', size=72, color=gold) 74 | blit_text(screen, 'Your Steps: '+str(steps), (320, 360), font_name='mono', size=30, color=black) 75 | blit_text(screen, 'Minimum Steps: '+str(min_steps), (320, 390), font_name='mono', size=30, color=red) 76 | if min_steps==steps: 77 | blit_text(screen, 'You finished in minumum steps!', (320, 300), font_name='mono', size=26, color=green) 78 | pygame.display.flip() 79 | time.sleep(2) # wait for 2 secs 80 | pygame.quit() #pygame exit 81 | sys.exit() #console exit 82 | 83 | def draw_towers(): 84 | global screen 85 | for xpos in range(40, 460+1, 200): 86 | pygame.draw.rect(screen, green, pygame.Rect(xpos, 400, 160 , 20)) 87 | pygame.draw.rect(screen, grey, pygame.Rect(xpos+75, 200, 10, 200)) 88 | blit_text(screen, 'Start', (towers_midx[0], 403), font_name='mono', size=14, color=black) 89 | blit_text(screen, 'Finish', (towers_midx[2], 403), font_name='mono', size=14, color=black) 90 | 91 | 92 | 93 | 94 | def make_disks(): 95 | global n_disks, disks 96 | disks = [] 97 | height = 20 98 | ypos = 397 - height 99 | width = n_disks * 23 100 | for i in range(n_disks): 101 | disk = {} 102 | disk['rect'] = pygame.Rect(0, 0, width, height) 103 | disk['rect'].midtop = (120, ypos) 104 | disk['val'] = n_disks-i 105 | disk['tower'] = 0 106 | disks.append(disk) 107 | ypos -= height+3 108 | width -= 23 109 | 110 | 111 | def draw_disks(): 112 | global screen, disks 113 | for disk in disks: 114 | pygame.draw.rect(screen, blue, disk['rect']) 115 | return 116 | 117 | def draw_ptr(): 118 | ptr_points = [(towers_midx[pointing_at]-7 ,440), (towers_midx[pointing_at]+7, 440), (towers_midx[pointing_at], 433)] 119 | pygame.draw.polygon(screen, red, ptr_points) 120 | return 121 | 122 | def check_won(): 123 | global disks 124 | over = True 125 | for disk in disks: 126 | if disk['tower'] != 2: 127 | over = False 128 | if over: 129 | time.sleep(0.2) 130 | game_over() 131 | 132 | def reset(): 133 | global steps,pointing_at,floating,floater 134 | steps = 0 135 | pointing_at = 0 136 | floating = False 137 | floater = 0 138 | menu_screen() 139 | make_disks() 140 | 141 | 142 | menu_screen() 143 | make_disks() 144 | # main game loop: 145 | while not game_done: 146 | for event in pygame.event.get(): 147 | if event.type == pygame.QUIT: 148 | game_done = True 149 | if event.type == pygame.KEYDOWN: 150 | if event.key == pygame.K_ESCAPE: 151 | reset() 152 | if event.key == pygame.K_q: 153 | game_done = True 154 | if event.key == pygame.K_RIGHT: 155 | pointing_at = (pointing_at+1)%3 156 | if floating: 157 | disks[floater]['rect'].midtop = (towers_midx[pointing_at], 100) 158 | disks[floater]['tower'] = pointing_at 159 | if event.key == pygame.K_LEFT: 160 | pointing_at = (pointing_at-1)%3 161 | if floating: 162 | disks[floater]['rect'].midtop = (towers_midx[pointing_at], 100) 163 | disks[floater]['tower'] = pointing_at 164 | if event.key == pygame.K_UP and not floating: 165 | for disk in disks[::-1]: 166 | if disk['tower'] == pointing_at: 167 | floating = True 168 | floater = disks.index(disk) 169 | disk['rect'].midtop = (towers_midx[pointing_at], 100) 170 | break 171 | if event.key == pygame.K_DOWN and floating: 172 | for disk in disks[::-1]: 173 | if disk['tower'] == pointing_at and disks.index(disk)!=floater: 174 | if disk['val']>disks[floater]['val']: 175 | floating = False 176 | disks[floater]['rect'].midtop = (towers_midx[pointing_at], disk['rect'].top-23) 177 | steps += 1 178 | break 179 | else: 180 | floating = False 181 | disks[floater]['rect'].midtop = (towers_midx[pointing_at], 400-23) 182 | steps += 1 183 | screen.fill(white) 184 | draw_towers() 185 | draw_disks() 186 | draw_ptr() 187 | blit_text(screen, 'Steps: '+str(steps), (320, 20), font_name='mono', size=30, color=black) 188 | pygame.display.flip() 189 | if not floating:check_won() 190 | clock.tick(framerate) --------------------------------------------------------------------------------