Reputation: 157
I'm making the Towers of Hanoi.
It should work like this: you click on the first tower, from where you want a disk to move, and then on the second where you want the disk to move to. The disk should move from the first tower (a list) to the second tower (another list).
My problem is that when you first click, the code generates the position, and soon after that you should click again to decide where the disk should go, but the code automatically takes the position of the first click.
Here's a sample of my code:
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((500, 400))
pygame.display.set_caption("Tower of Hanoi")
block_red = pygame.image.load('red.png')
block_blue = pygame.image.load('blue.png')
block_green = pygame.image.load('green.png')
rod1 = [block_red, block_blue, block_green]
rod2 = []
rod3 = []
WHITE = (255, 255, 255)
while True:
DISPLAYSURF.fill(WHITE)
# get the position of the mouse click
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
mousex, mousey = pygame.mouse.get_pos()
click1 = mousex, mousey
# first in the left part of the screen
if (mousex > 0) and (mousex < 166) and (mousey > 0) and (mousey < 400):
if len(rod1) == 0:
print "not valid"
elif len(rod1) == 1 or 2 or 3:
disk1 = rod1[-1]
rod1.remove(disk1)
# click again in a other part of the screen
if event.type == MOUSEBUTTONDOWN:
mousex, mousey = pygame.mouse.get_pos()
click2 = mousex, mousey
if (mousex > 166) and (mousex < 333) and (mousey > 0) and (mousey < 400):
rod2.append(disk1)
elif (mousex > 333) and (mousex < 500) and (mousey > 0) and (mousey < 400):
rod3.append(disk1)
else:
rod1.append(disk1)
# if statement fot the middle part
# if statement for the right part
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Upvotes: 2
Views: 1278
Reputation: 3080
I think this line will not do what you expect it to:
elif len(rod1) == 1 or 2 or 3:
Test in the interpreter that it does not evaluate to True but rather always to the value of 2.
You probably meant to do something like:
elif len(rod1) in (1, 2, 3):
Or even:
elif len(rod1) > 0:
Additionally, you could still go for a series of "or" statements to cover your needs:
[not recommended]
elif len(rod1) == 1 or len(rod1) == 2 or len(rod1) == 3:
If any one of the statements evaluates to True, the conditional statement will also be True.
Upvotes: 1
Reputation: 101162
Keep in mind that your code runs in a loop, so you have to do keep track of the state of your game.
Clicking on the first tower changes the state of your game: Now one tower is selected, and clicking on a tower now does something different (it moves a block from the first to the second tower).
In your example, you just need to keep track of the fact if a tower is currently selected or not (and the blocks each tower has, of course). Don't be afraid of the word state, a simple variable is enough.
Take a look at the following code (note the comments). It just keeps track of the selected rod in the variable selected
, then later checks if it is set to decide if a block needs to be moved.
import pygame
from collections import namedtuple
pygame.init()
screen = pygame.display.set_mode((500, 400))
# create a named tuple to keep track of the size/location of the rods and their blocks
Rod = namedtuple('Rod', ['rect', 'items'])
# first rod has 4 items. The just use a number to keep track of the size of the blocks
rods = (Rod(pygame.rect.Rect((100, 150, 25, 250)), [6, 5, 4, 3, 2, 1]),
Rod(pygame.rect.Rect((225, 150, 25, 250)), []),
Rod(pygame.rect.Rect((350, 150, 25, 250)), []))
# keep track of the currently selected rod
selected = None
while True:
if pygame.event.get(pygame.QUIT): break
screen.fill(pygame.color.Color('white'))
# draw the rods. It's easy since every rod has a rect which we can use with pygame.draw.rect
for rod in rods:
# if a rod is selected, we draw it yellow instead of black
pygame.draw.rect(screen, pygame.color.Color('yellow' if selected == rod else 'black'), rod.rect)
# draw each block of each rod
for i, item in enumerate(rod.items):
r = pygame.rect.Rect(rod.rect.x - item * 8, 375 - 25 * i, 25 + item * 16, 25)
pygame.draw.rect(screen, pygame.color.Color('green' if selected == rod else 'darkgreen'), r)
for e in pygame.event.get():
if e.type == pygame.MOUSEBUTTONDOWN:
# check if we clicked a rod. It's easy since every rod has a rect
rod = next((r for r in rods if r.rect.collidepoint(pygame.mouse.get_pos())), None)
if rod:
if selected:
# if there's already a rod selected, move block from one the selected
# rod to the clicked rod
rod.items.append(selected.items.pop())
selected = None
elif rod.items:
# if no rod is selected, selected the currently clicked one (if it has blocks)
selected = rod
else:
selected = None
pygame.display.flip()
Result:
Upvotes: 1
Reputation: 188
What I would personally do is put a loop around your code...
clicklocations = []
for clicknumber in range(0,1):
# get the position of the mouse click
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
mousex, mousey = pygame.mouse.get_pos()
clicklocations.append([mousex, mousey])
# code for left part of the screen
if clicklocations[0] in left part of screen, do stuff etc. etc.
# code for middle part of the screen
# code for right part of the screen
Something like this.
Then, you'll have both click locations stored and won't have to rewrite your clicking code twice.
Upvotes: 0