Global variable set and then reset in Python Canvas - python

Good afternoon,
I'm building out (suppose to be) a relatively simple q & a experiment for a psychology experiment. I'm using Pythons canvas for drawing and painting but have hit a bit of brick wall and a classic update scenario, I think. Here's the code:
# Replace with 60000 for 1 minute a question
screen_timeout = 10000
start_time = clock.time()
# Create a canvas, mouse & keyboard object
canvas = canvas()
mouse = mouse()
kb = keyboard(timeout=0)
question = '1) Which two chemicals are discussed?'
answer = ''
show_circle = False
global circle_clicked
circle_clicked = False
def draw_question_and_answer(c, a):
c.text('%s<br />(Just start typing; press enter to submit)<br /><br />%s' % (question, a))
def draw_mouse(c, (x, y)):
c.fixdot(x, y)
def draw_circle(c):
c['circle'] = Circle(0, 0, 50, fill=True, color='red')
def paint(c, a, s, (x, y)):
c.clear()
# show_circle_every(s, 2500)
# NOTE Drawing order matters here
if s:
draw_question_and_answer(c, a)
draw_circle(c)
draw_mouse(c, (x, y))
if (x, y) in c['circle']:
circle_clicked = True
else:
draw_question_and_answer(c, a)
c.show()
def game_loop(c, m, a, s):
while True:
if clock.time() - start_time >= screen_timeout:
break
# if clock.time() - start_time >= 2500 and s == False:
# s = True
response, timestamp_kb = kb.get_key()
(x, y), timestamp_m = m.get_pos()
# TODO Extrapolate to function
if s == False:
if response == 'return':
var.gq1 = a
log.write_vars()
break
if response != None and response != 'right shift' and response != 'left shift':
if response == 'space':
a += ' '
elif response == 'backspace':
a = a[:-1]
else:
a += response
paint(c, a, s, (x, y))
# If the user enters the circle it should disappear
print circle_clicked
if clock.time() - start_time >= 2500 and circle_clicked == False:
s = True
game_loop(canvas, mouse, answer, show_circle)
What I'm trying to do here is show a red circle every 2.5 seconds and keep the circle there until the users mouse enters the boundary of the circle. In these lines here:
if clock.time() - start_time >= 2500 and circle_clicked == False:
s = True
I'm setting the s variable (show) to True to show the circle which works. And in this line:
if (x, y) in c['circle']:
circle_clicked = True
if the user enters the circle I'm setting clicked to true. But if I print the values I can see circle_clicked changing from True to back False - How come? Does the loop get it's own version of circle_clicked? If so how?
What am I doing wrong here as I think it's quite a simple problem? Coming from a purely Javascript background also complicates things as I'm trying to learn Python to do it.
Thanks

Change your paint function to this
def paint(c, a, s, (x, y)):
global circle_clicked
c.clear()
# show_circle_every(s, 2500)
# NOTE Drawing order matters here
if s:
draw_question_and_answer(c, a)
draw_circle(c)
draw_mouse(c, (x, y))
if (x, y) in c['circle']:
circle_clicked = True
else:
draw_question_and_answer(c, a)
c.show()

Related

I'm having a problem with determining the intersection of two lines in this python code

I tried a math formula from analytic geometry but I didn't get the desired results.
As you can see in the code, the user draw two lines and a green circle(point of intersection) appear.
I have tried to fix the problem for hours but I failed. Sometimes the point doesn't appear or appear but in the wrong position.
Source of the formula I used in the code
Docs of pygame the library I used
#!/usr/bin/env python
from pygame import *
from time import sleep
init();
win = display.set_mode((500,500));
lines = []
cords = []
preview = False
xi = -100
yi = -100
def drawlines(flines):
for fcords in flines:
draw.line(win,(0,0,0),fcords[0],fcords[1],4)
while True:
win.fill((255,255,255))
for ev in event.get():
if ev.type == QUIT:
quit();
exit();
elif ev.type == MOUSEBUTTONDOWN:
if ev.button == 1:
preview = True
a = mouse.get_pos()
cords.append(mouse.get_pos())
elif ev.type == MOUSEBUTTONUP:
if ev.button == 1:
cords.append(mouse.get_pos())
lines.append((cords))
cords = []
preview = False
######################################## THIS BROKEN PART #################################
if len(lines) == 2:
#line 1
points_line1 = lines[0]
point1_line1 = points_line1[0]
point2_line1 = points_line1[1]
line1_vector = (point2_line1[0]-point1_line1[0],point2_line1[1]-point1_line1[1])
a_line1 = line1_vector[1]
b_line1 = -line1_vector[0]
c_line1 = -((a_line1*point1_line1[0]) + (b_line1*point1_line1[1]))
#line2
points_line2 = lines[1]
point1_line2 = points_line2[0]
point2_line2 = points_line2[1]
line2_vector = (point2_line2[0]-point1_line2[0],point2_line2[1]-point1_line2[1])
a_line2 = line2_vector[1]
b_line2 = -line2_vector[0]
c_line2 = -((a_line2*point1_line2[0]) + (b_line2*point1_line2[1]))
if (a_line2 != 0 and b_line2 != 0):
if (a_line1 / a_line2) != ( b_line1/b_line2):
#intersection between line1 and line2
yi = ((((a_line1*c_line2) / a_line2) + c_line1) / -b_line1)
xi = (((-b_line1*yi)-c_line1) / a_line1)
###########################################################################################
elif preview:
draw.line(win,(0,0,0),a,mouse.get_pos(),4)
drawlines(lines)
draw.circle(win,(0,200,0),(int(xi),int(yi)),10)
display.flip()
It's hard to dig through your code. Especially c_line1 = -((a_line1*point1_line1[0]) + (b_line1*point1_line1[1])) seems to be odd, because it calculates the Dot product of vector and a point.
Therefore I don't know exactly what's wrong with your code, but I know how to intersect lines. See Problem with calculating line intersections and Collision and Intersection - Line and line.
Write functions that can add, subtract, scale vectors and rotate vectors by 90°. Write a function which calculates the Dot product:
def add(a, b):
return a[0]+b[0], a[1]+b[1]
def sub(a, b):
return a[0]-b[0], a[1]-b[1]
def rot90(v):
return -v[1], v[0]
def mul(v, s):
return v[0]*s, v[1]*s
def dot(a, b):
return a[0]*b[0] + a[1]*b[1]
Calculate the vector from the beginning of the lines to the end of the lines and the normal vectors to the lines. The normal vector is obtained by rotating the line vector by 90°:
#line 1
point1_line1, point2_line1 = lines[0]
line1_vector = sub(point2_line1, point1_line1)
line1_norml = rot90(line1_vector)
#line2
point1_line2, point2_line2 = lines[1]
line2_vector = sub(point2_line2, point1_line2)
line2_norml = rot90(line2_vector)
Calculate the intersection of the line segments. Make sure the lines are not parallel and that the intersection point is on the line segments:
# vector from start point of line 2 to start point of line 1
l2p1_l1p1 = sub(point1_line1, point1_line2)
# intersection
d = dot(line2_vector, line1_norml)
if d != 0: # prallel lines
t = dot(l2p1_l1p1, line1_norml) / d
u = dot(l2p1_l1p1, line2_norml) / d
if 0 <= t <= 1 and 0 <= u <= 1: # intersection on line segments
xi, yi = add(point1_line2, mul(line2_vector, t))
Minimal example:
from pygame import *
init()
win = display.set_mode((500,500))
lines = []
cords = []
preview = False
xi, yi = -100, -100
def drawlines(flines):
for fcords in flines:
draw.line(win,(0,0,0),fcords[0],fcords[1],4)
def add(a, b):
return a[0]+b[0], a[1]+b[1]
def sub(a, b):
return a[0]-b[0], a[1]-b[1]
def rot90(v):
return -v[1], v[0]
def mul(v, s):
return v[0]*s, v[1]*s
def dot(a, b):
return a[0]*b[0] + a[1]*b[1]
run = True
while run:
for ev in event.get():
if ev.type == QUIT:
run = False
elif ev.type == MOUSEBUTTONDOWN:
if ev.button == 1:
preview = True
a = ev.pos
cords.append(a)
elif ev.type == MOUSEBUTTONUP:
if ev.button == 1:
cords.append(ev.pos)
lines.append((cords))
cords = []
preview = False
intersections = []
for i, line1 in enumerate(lines):
for line2 in lines[i+1:]:
#line 1
point1_line1, point2_line1 = line1
line1_vector = sub(point2_line1, point1_line1)
line1_norml = rot90(line1_vector)
#line2
point1_line2, point2_line2 = line2
line2_vector = sub(point2_line2, point1_line2)
line2_norml = rot90(line2_vector)
# vector from start point of line 2 to start point of line 1
l2p1_l1p1 = sub(point1_line1, point1_line2)
# intersection
d = dot(line2_vector, line1_norml)
if d != 0: # prallel lines
t = dot(l2p1_l1p1, line1_norml) / d
u = dot(l2p1_l1p1, line2_norml) / d
if 0 <= t <= 1 and 0 <= u <= 1: # intersection on line segments
xi, yi = add(point1_line2, mul(line2_vector, t))
intersections.append((xi, yi))
win.fill((255,255,255))
if len(cords) % 2 == 1:
draw.line(win,(0,0,0), a, mouse.get_pos(), 4)
drawlines(lines)
for p in intersections:
draw.circle(win, (0,200,0), (round(p[0]), round(p[1])), 10)
display.flip()
quit()
exit()

Python Canvas bbox returns None

so i am making a game (Minecraft 2D (scuffed edition)) and if you are underground in a cave, i want the background to be dark, not that you can see the sun if you are in a cave, so what i do is i want to check for the lowest grass block on screen (witch is ground level)
and then place the cave background atthat location, but when i trie to get the bbox or the coords of a block object on the canvas, it just gives me None.
So i have this now:
(the camera function gets run every time the player moves)
def camera(self):
for i in self.block_sprites:
self.canvas.delete(i.get_image())
for i in self.sprites:
self.canvas.delete(i)
self.draw_current_pos()
self.draw_background()
def add_block_sprite(self, x, y, block_type):
self.current_sprite = Block(x, y, self, block_type)
self.block_sprites.append(self.current_sprite)
def draw_current_pos(self):
self.sprites = []
self.block_sprites = []
for x in range(0, 20):
for y in range(0, 21):
if self.world.world[self.posx+x][self.posy+y] == 0 :
continue
else:
self.add_block_sprite(x, y, self.world.world[self.posx + x][self.posy + y])
def draw_background(self):
grass_y = 1000
test_for_grass = False
for block in self.block_sprites:
if block.get_type() == 1:
print(self.canvas.bbox(block)) #prints "None"
if self.canvas.bbox(block)[1] > grass_y: ####error here####
grass_y = self.canvas.coords(block)[1]
test_for_grass = True
if not test_for_grass and self.posy < 30:
grass_y = 1000 - grass_y
cave = self.canvas.create_image(0, grass_y, image=self.cavebg, anchor="nw")
self.sprites.append(cave)
Do you know what the problem is?
I hope you can help!
(if this it to little code for the problem tell me)

Python Recursive maze solver never backtracks all the way back

I have a recursive maze solver with one image (PNG, 200x200) I have tried using try/except to print an exception but nothing prints.
Recursive function
def solveRecursiveMaze(arr,x,y):
successful = False
if (x,y) == getExitPoint():
successful = True
elif isValid(arr,x,y):
arr[x][y] = "V" #set to V to show it's a visited path
successful = solveRecursiveMaze(arr, x-1, y)
if not successful:
successful = solveRecursiveMaze(arr, x, y+1)
if not successful:
successful = solveRecursiveMaze(arr, x+1, y)
if not successful:
successful = solveRecursiveMaze(arr, x, y-1)
if successful:
arr[x][y] = "P" #Mark as P to show it's a valid pa
return successful
isValid checks to see if the 2D array has a "W" (for White pixel) at the position passed in, and it is within bounds of the array
def isValid(arr,x,y):
if x < len(arr) and y < len(arr) and x >= 0 and y >= 0:
if arr[x][y] == "W":
return True
return False
getExitPoint returns an x,y (pixel) of the point that is found for the exit of the maze
def getExitPoint():
x = crop.size[0] - 1
for y in range(0, crop.size[1]):
if(crop.getpixel((x,y)) == (255,255,255)):
return x,y
if(crop.getpixel((y,x)) == (255,255,255)):
return y,x
this is how I convert my image to a 2D array
maze = []
width,height = crop.size
for x in range(0, width):
mazeX = []
for y in range(0, height):
if(crop.getpixel((x,y)) == (0,0,0)):
mazeX.append("B")
elif(crop.getpixel((x,y)) == (255,255,255)):
mazeX.append("W")
maze.append(mazeX)
What it is supposed to do, is convert the image into a 2D array, which gets traversed recursively (using backtracking) looking for a successful path, then draws a red line over the path.
The script does not work on this image, it stops at pixel X=76, y=153 every time, and i am not sure what to do/what I'm doing wrong
The borders are 1px and the path is 1px. There are not any errors, stack-traces, exceptions, or anything thrown. The recursion just stops and the program quits. Any Ideas?
There are some various problems with your code, but I think what is happening is that you are running over the recursion limit. Your maze is fairly large and complex. I needed to use 4000 (For me, 1000 is the default, and 3000 wasn't large enough).
Not sure what image library you're using; I used PIL.Image
Your input image is actually 203x203, and there is a challenge to locate the entrance and exit. I assumed the entrance is at the top or on the left side, and the exit is on the right side or along the bottom.
import sys
import argparse
import PIL.Image
import os
colors = {
'white' : (255, 255, 255),
'black' : (0, 0, 0),
'red' : (128, 0, 0),
'green' : (0, 255, 0) }
def isValid(image, x, y):
if x < image.size[0] and y < image.size[1] and x >= 0 and y >= 0:
if image.getpixel((x, y)) == colors['white']:
return True
return False
def getEntryPoint(image):
# Search along top.
for x in range(1, image.size[0] - 1):
if image.getpixel((x, 1)) == colors['white']:
return x, 1
# Search along left side.
for y in range(1, image.size[1] - 1):
if image.getpixel((1, y)) == colors['white']:
return 1, y
# Maze is invalid if there is no entry point.
raise Exception('No entry point found!')
def getExitPoint(image):
# Search along bottom.
for x in range(1, image.size[0] - 1):
if image.getpixel((x, image.size[1] - 2)) == colors['white']:
return x, image.size[1] - 2
# Search along right side.
for y in range(1, image.size[1] - 1):
if image.getpixel((image.size[0] - 2, y)) == colors['white']:
return image.size[0] - 2, y
# Maze is invalid if there is no exit point.
raise Exception('No exit point found!')
def solveRecursiveMaze(image, x, y):
successful = False
if (x, y) == getExitPoint(image):
successful = True
elif isValid(image, x, y):
# set to show it's a visited path
image.putpixel((x, y), colors['red'])
successful = solveRecursiveMaze(image, x-1, y)
if not successful:
successful = solveRecursiveMaze(image, x, y+1)
if not successful:
successful = solveRecursiveMaze(image, x+1, y)
if not successful:
successful = solveRecursiveMaze(image, x, y-1)
if successful:
# Mark to show it's a valid path.
image.putpixel((x, y), colors['green'])
return successful
def main(options):
solved = False
if options.depth:
sys.setrecursionlimit(options.depth)
try:
image = PIL.Image.open(options.filename)
except:
print('ERROR: Could not open %s' % (options.filename))
else:
image = image.convert('RGB')
x, y = getEntryPoint(image)
print('Entering maze at x = %d, y = %d' % (x, y))
solved = solveRecursiveMaze(image, x, y)
if not solved:
print('No solution exists.')
else:
print('Solved maze.')
basename = os.path.splitext(options.filename)[0]
image.save(basename + '_solution' + '.png', 'PNG')
return 0 if solved else 1
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--d',
'-depth',
dest='depth',
type=int,
help='Set Python recursion limit with sys.setrecursionlimit()')
parser.add_argument(
'filename',
help='Image containing the maze.')
options = parser.parse_args()
sys.exit(main(options))

How can I change this to use a q table for reinforcement learning

I am working on learning q-tables and ran through a simple version which only used a 1-dimensional array to move forward and backward. now I am trying 4 direction movement and got stuck on controlling the person.
I got the random movement down now and it will eventually find the goal. but I want it to learn how to get to the goal instead of randomly stumbling on it. So I would appreciate any advice on adding a qlearning into this code. Thank you.
Here is my full code as it stupid simple right now.
import numpy as np
import random
import math
world = np.zeros((5,5))
print(world)
# Make sure that it can never be 0 i.e the start point
goal_x = random.randint(1,4)
goal_y = random.randint(1,4)
goal = (goal_x, goal_y)
print(goal)
world[goal] = 1
print(world)
LEFT = 0
RIGHT = 1
UP = 2
DOWN = 3
map_range_min = 0
map_range_max = 5
class Agent:
def __init__(self, current_position, my_goal, world):
self.current_position = current_position
self.last_postion = current_position
self.visited_positions = []
self.goal = my_goal
self.last_reward = 0
self.totalReward = 0
self.q_table = world
# Update the totoal reward by the reward
def updateReward(self, extra_reward):
# This will either increase or decrese the total reward for the episode
x = (self.goal[0] - self.current_position[0]) **2
y = (self.goal[1] - self.current_position[1]) **2
dist = math.sqrt(x + y)
complet_reward = dist + extra_reward
self.totalReward += complet_reward
def validate_move(self):
valid_move_set = []
# Check for x ranges
if map_range_min < self.current_position[0] < map_range_max:
valid_move_set.append(LEFT)
valid_move_set.append(RIGHT)
elif map_range_min == self.current_position[0]:
valid_move_set.append(RIGHT)
else:
valid_move_set.append(LEFT)
# Check for Y ranges
if map_range_min < self.current_position[1] < map_range_max:
valid_move_set.append(UP)
valid_move_set.append(DOWN)
elif map_range_min == self.current_position[1]:
valid_move_set.append(DOWN)
else:
valid_move_set.append(UP)
return valid_move_set
# Make the agent move
def move_right(self):
self.last_postion = self.current_position
x = self.current_position[0]
x += 1
y = self.current_position[1]
return (x, y)
def move_left(self):
self.last_postion = self.current_position
x = self.current_position[0]
x -= 1
y = self.current_position[1]
return (x, y)
def move_down(self):
self.last_postion = self.current_position
x = self.current_position[0]
y = self.current_position[1]
y += 1
return (x, y)
def move_up(self):
self.last_postion = self.current_position
x = self.current_position[0]
y = self.current_position[1]
y -= 1
return (x, y)
def move_agent(self):
move_set = self.validate_move()
randChoice = random.randint(0, len(move_set)-1)
move = move_set[randChoice]
if move == UP:
return self.move_up()
elif move == DOWN:
return self.move_down()
elif move == RIGHT:
return self.move_right()
else:
return self.move_left()
# Update the rewards
# Return True to kill the episode
def checkPosition(self):
if self.current_position == self.goal:
print("Found Goal")
self.updateReward(10)
return False
else:
#Chose new direction
self.current_position = self.move_agent()
self.visited_positions.append(self.current_position)
# Currently get nothing for not reaching the goal
self.updateReward(0)
return True
gus = Agent((0, 0) , goal)
play = gus.checkPosition()
while play:
play = gus.checkPosition()
print(gus.totalReward)
I have a few suggestions based on your code example:
separate the environment from the agent. The environment needs to have a method of the form new_state, reward = env.step(old_state, action). This method is saying how an action transforms your old state into a new state. It's a good idea to encode your states and actions as simple integers. I strongly recommend setting up unit tests for this method.
the agent then needs to have an equivalent method action = agent.policy(state, reward). As a first pass, you should manually code an agent that does what you think is right. e.g., it might just try to head towards the goal location.
consider the issue of whether the state representation is Markovian. If you could do better at the problem if you had a memory of all the past states you visited, then the state doesn't have the Markov property. Preferably, the state representation should be compact (the smallest set that is still Markovian).
once this structure is set-up, you can then think about actually learning a Q table. One possible method (that is easy to understand but not necessarily that efficient) is Monte Carlo with either exploring starts or epsilon-soft greedy. A good RL book should give pseudocode for either variant.
When you are feeling confident, head to openai gym https://www.gymlibrary.dev/ for some more detailed class structures. There are some hints about creating your own environments here: https://www.gymlibrary.dev/content/environment_creation/

Calling Methods From Class Not Working

I have made a sonar finding game and some functions for it. I have put these functions into a class and now I want to call them so I can play the game, however when I define the class call it now returns things to me like game.getNewBoard() takes 0 positional arguments and tells me I have given it one when I have not and so on. Any help would be appreciated.
# Sonar
import random
import sys
class OceanTreasure:
def drawBoard(board):
# Draw the board data structure.
hline = ' ' # initial space for the numbers down the left side of the board
for i in range(1, 6):
hline += (' ' * 9) + str(i)
# print the numbers across the top
print(hline)
print(' ' + ('0123456789' * 6))
print()
# print each of the 15 rows
for i in range(15):
# single-digit numbers need to be padded with an extra space
if i < 10:
extraSpace = ' '
else:
extraSpace = ''
print('%s%s %s %s' % (extraSpace, i, getRow(board, i), i))
# print the numbers across the bottom
print()
print(' ' + ('0123456789' * 6))
print(hline)
def getRow(board, row):
# Return a string from the board data structure at a certain row.
boardRow = ''
for i in range(60):
boardRow += board[i][row]
return boardRow
def getNewBoard():
# Create a new 60x15 board data structure.
board = []
for x in range(60): # the main list is a list of 60 lists
board.append([])
for y in range(15): # each list in the main list has 15 single-character strings
# I thought about using different char to make it more readble?? Admit it, it looks dull with just these ~
if random.randint(0, 1) == 0:
board[x].append('~')
else:
board[x].append('~')
return board
def getRandomChests(numChests):
# Create a list of chest data structures (two-item lists of x, y int coordinates)
chests = []
for i in range(numChests):
chests.append([random.randint(0, 59), random.randint(0, 14)])
return chests
def isValidMove(x, y):
# Return True if the coordinates are on the board, otherwise False.
return x >= 0 and x <= 59 and y >= 0 and y <= 14
def makeMove(board, chests, x, y):
# Change the board data structure with a sonar device character. Remove treasure chests
# from the chests list as they are found. Return False if this is an invalid move.
# Otherwise, return the string of the result of this move.
if not isValidMove(x, y):
return False
smallestDistance = 100 # any chest will be closer than 100.
for cx, cy in chests:
if abs(cx - x) > abs(cy - y):
distance = abs(cx - x)
else:
distance = abs(cy - y)
if distance < smallestDistance: # we want the closest treasure chest.
smallestDistance = distance
if smallestDistance == 0:
# xy is directly on a treasure chest!
chests.remove([x, y])
return 'You have found a sunken treasure chest!'
else:
if smallestDistance < 10:
board[x][y] = str(smallestDistance)
return 'Treasure detected at a distance of %s from the sonar device.' % (smallestDistance)
else:
board[x][y] = 'O'
return 'Sonar did not detect anything. All treasure chests out of range.'
def enterPlayerMove():
# Let the player type in her move. Return a two-item list of int xy coordinates.
print('Where do you want to drop the next sonar device? (0-59 0-14) (or type quit)')
while True:
move = input()
if move.lower() == 'quit':
print('Thanks for playing!')
sys.exit()
move = move.split()
if len(move) == 2 and move[0].isdigit() and move[1].isdigit() and isValidMove(int(move[0]), int(move[1])):
return [int(move[0]), int(move[1])]
print('Enter a number from 0 to 59, a space, then a number from 0 to 14.')
def playAgain():
# This function returns True if the player wants to play again, otherwise it returns False.
print('Do you want to play again? (yes or no)')
return input().lower().startswith('y')
print('S O N A R !')
print()
while True:
# game setup
game=OceanTreasure()
sonarDevices = 20
theBoard = game.getNewBoard()
theChests = getRandomChests(3)
drawBoard(theBoard)
previousMoves = []
while sonarDevices > 0:
# Start of a turn:
# sonar device/chest status
if sonarDevices > 1: extraSsonar = 's'
else: extraSsonar = ''
if len(theChests) > 1: extraSchest = 's'
else: extraSchest = ''
print('You have %s sonar device%s left. %s treasure chest%s remaining.' % (sonarDevices, extraSsonar, len(theChests), extraSchest))
x, y = enterPlayerMove()
previousMoves.append([x, y]) # we must track all moves so that sonar devices can be updated.
moveResult = makeMove(theBoard, theChests, x, y)
if moveResult == False:
continue
else:
if moveResult == 'You have found a sunken treasure chest!':
# update all the sonar devices currently on the map.
for x, y in previousMoves:
makeMove(theBoard, theChests, x, y)
drawBoard(theBoard)
print(moveResult)
if len(theChests) == 0:
print('You have found all the sunken treasure chests! Congratulations and good game!')
break
sonarDevices -= 1
if sonarDevices == 0:
print('We\'ve run out of sonar devices! Now we have to turn the ship around and head')
print('for home with treasure chests still out there! Game over.')
print(' The remaining chests were here:')
for x, y in theChests:
print(' %s, %s' % (x, y))
if not playAgain():
sys.exit() #I thought this is a better way than just break or make false, correct me if I am wrong
Every class method in Python receives the instance it is called from as the first parameter automatically. That means, that the first parameter is always self:
def drawBoard(self, board):

Categories