Recursion in python didn't work out - python

def make_ship(length):
ship = []
ship_tmp = []
ship_row = random_row(board, length)
ship.append(ship_row)
ship_col = random_col(board, length)
ship.append(ship_col)
i = 0
if randint(0,1) == 0:
while i<length:
ship_tmp.append(ship[:])
ship[0] += 1
for ship in ship_tmp:
if ship in ship_all:
make_ship(length)
else:
ship_all.append(ship)
i+=1
else:
while i<length:
ship_tmp.append(ship[:])
ship[1] += 1
for ship in ship_tmp:
if ship in ship_all:
make_ship(length)
else:
ship_all.append(ship)
i+=1
The aim of this problem is to generate several ship on the board and prevent them from touching each other,but the make_ship() recursion didn't work out, how to solve this problem?

Using gobal variable:
global i
i=0
def make_ship(length):
global i
ship = []
ship_tmp = []
ship_row = random_row(board, length)
ship.append(ship_row)
ship_col = random_col(board, length)
ship.append(ship_col)
if randint(0,1) == 0:
while i<length:
ship_tmp.append(ship[:])
ship[0] += 1
for ship in ship_tmp:
if ship in ship_all:
make_ship(length)
else:
ship_all.append(ship)
i+=1
else:
while i<length:
ship_tmp.append(ship[:])
ship[1] += 1
for ship in ship_tmp:
if ship in ship_all:
make_ship(length)
else:
ship_all.append(ship)
i+=1
You may also try to use class to solve the problem:
class ship_class(object):
def __int__(self,length):
self.i=0
self.length=length
def make_ship(self):
ship = []
ship_tmp = []
ship_row = random_row(board, length)
ship.append(ship_row)
ship_col = random_col(board, length)
ship.append(ship_col)
if randint(0,1) == 0:
while self.i<self.length:
ship_tmp.append(ship[:])
ship[0] += 1
for ship in ship_tmp:
if ship in ship_all:
make_ship(self.length)
else:
ship_all.append(ship)
self.i+=1
else:
while self.i<self.length:
ship_tmp.append(ship[:])
ship[1] += 1
for ship in ship_tmp:
if ship in ship_all:
make_ship(self.length)
else:
ship_all.append(ship)
self.i+=1

Things you should learn:
Global variables are rarely a good idea; they break encapsulation and make debugging hard because you can't tell where changes came from (or didn't come from, sometimes!).
Meaningful comments are a very good thing. Meaningful variable names are even better. Well-factored, meaningful classes are a gift from heaven.
Keep your functions simple - ideally less than 10 or 12 lines. This lets you reason about the whole thing at once, so you can see most problems at a glance. If it's too complicated to think about the whole thing at once, maybe you should break it down further.
Recursion is good for dealing with branching structures. A ship is not a branching structure.
Here is a simple class-based solution:
import random
class Board:
def __init__(self, width, height, empty_char="."):
"""
Create a new gameboard
"""
self.width = width
self.height = height
self.empty_char = empty_char
self.ships = []
def __str__(self):
# make an empty board
board = [[self.empty_char] * self.width for y in range(self.height)]
# add ships
for ship in self.ships:
ship.draw(board)
# return as string
return "\n".join("".join(row) for row in board)
def add_rand_ship(self, length, char, tries=10):
"""
Add a ship at a random location on the board,
not overlapping any existing ships
"""
for try_ in range(tries):
# create a random Ship
new_ship = Ship.rand_ship(length, char, self.width, self.height)
# make sure it doesn't intersect any existing ships
if not any(new_ship.hits(ship) for ship in self.ships):
self.ships.append(new_ship)
return
raise ValueError("Failed creating new ship after {} tries".format(tries))
class Ship:
def __init__(self, x, y, length, char, horiz=True):
self.x = x
self.y = y
self.length = length
self.char = char
self.horiz = horiz
# get every square occupied by this ship
if self.horiz:
self.locations = set((x + dx, y) for dx in range(self.length))
else:
self.locations = set((x, y + dy) for dy in range(self.length))
def draw(self, board):
"""
Draw ship to board
"""
for x,y in self.locations:
board[y][x] = self.char
def hits(self, ship):
"""
Does this ship occupy any of the same locations as the other one?
"""
return bool(self.locations & ship.locations)
#classmethod
def rand_ship(cls, length, char, board_width, board_height):
"""
Create a new Ship at a random board location
"""
horiz = random.choice((False, True))
x = random.randint(0, board_width - (length if horiz else 1))
y = random.randint(0, board_height - (1 if horiz else length))
return cls(x, y, length, char, horiz)
def main():
bd = Board(30, 20)
for length in (2, 2, 3, 4):
for side in ("X", "O"):
bd.add_rand_ship(length, side)
print(bd)
main()
which produces something like:
..............................
..............................
..............................
.X............................
.X............................
.X............................
..............................
..............................
..........OOO.................
...............XX.............
..............................
...X..........................
...X......OOOO................
...X..........................
...X..........................
............OO................
..............................
..............................
...X.....................O....
...X.....................O....

Related

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)

TrapRoomTile has no attribute trap?

My TrapRoomTile is now throwing an error TrapRoomTile has no attribute trap. I declare self.trap = items.Pitfall() its written exactly how my Enemy tiles are written but I keep getting the error. I imagine I'm overlooking something small like usual so any help would be appreciated
import enemies
import npc
import random
import time
import items
class MapTile:
def __init__(self, x, y):
self.x = x
self.y = y
def intro_text(self):
raise NotImplementedError("Create a subclass instead!")
def modify_player(self, player):
pass
class StartTile(MapTile):
def intro_text(self):
return """
\n You find yourself in a cave with a flickering torch on the wall.
You can make out four paths, each equally as dark and foreboding.
"""
time.sleep(0.5)
class EnemyTile(MapTile):
'''
def __init__(self, x, y):
r = random.random()
if r < 0.50:
self.enemy = enemies.GiantSpider()
self.alive_text = "\nA giant spider jumps down from " \
"its web in front of you!"
self.dead_text = "\nThe corpse of a dead spider " \
"rots on the ground."
elif r < 0.80:
self.enemy = enemies.Ogre()
self.alive_text = "\n An ogre is blocking your path!"
self.dead_text = "\nA dead ogre reminds you of your triumph."
elif r < 0.95:
self.enemy = enemies.BatColony()
self.alive_text = "\nYou hear a squeaking noise growing louder" \
"...suddenly you are lost in swarm of bats!"
self.dead_text = "\nDozens of dead bats are scattered on the ground."
else:
self.enemy = enemies.RockMonster()
self.alive_text = "\nYou've disturbed a rock monster " \
"from his slumber!"
self.dead_text = "\nDefeated, the monster has reverted " \
"into an ordinary rock."
super().__init__(x, y)
'''
def intro_text(self):
text = self.alive_text if self.enemy.is_alive() else self.dead_text
time.sleep(0.1)
return text
def modify_player(self, player):
if self.enemy.is_alive():
player.hp = player.hp - self.enemy.damage
print("Enemy does {} damage. You have {} HP remaining.".
format(self.enemy.damage, player.hp))
if not self.enemy.is_alive():
player.gold = player.gold + self.enemy.gold
if self.enemy.gold == 0:
pass
player.exp = player.exp + self.enemy.exp
total_exp = player.exp
levels = [0,200,450,1012]
if True:
current_level = sum(1 for x in levels if x <= total_exp)
player.player_lvl = current_level
if not self.enemy.is_alive():
self.enemy.exp = 0
class GoblinScoutTile(EnemyTile):
def __init__(self,x,y):
self.enemy = enemies.GoblinScout()
r = random.random()
if r < .20:
self.alive_text = "\nA small goblin jumps out at you its not much to look at..."\
"Lookout its got a knife!"
elif r < 50:
self.alive_text = "\nOut of a dark recess in the wall jumps a goblin"\
" ready to scewer you with his dagger"
else:
self.alive_text = "\nYou hear a gutteral voice out of the dark "\
"walks a goblin ready for battle!"
self.dead_text = "\nA dead goblin body."
super().__init__(x, y)
class GoblinBasherTile(EnemyTile):
def __init__(self,x,y):
self.enemy = enemies.GoblinBasher()
self.alive_text = "\nLookout a Goblin basher and he is looking for a fight."
self.dead_text = "\n The body of a dead Goblin basher"
super().__init__(x,y)
class VictoryTile(MapTile):
def modify_player(self,player):
player.victory = True
def intro_text(self):
return """
You see a bright light in the distance...
... it grows as you get closer! It's sunlight!
Victory is yours!
"""
class FindGoldTile(MapTile):
def __init__(self, x, y):
self.gold = random.randint(1, 50)
self.gold_claimed = False
super().__init__(x, y)
def modify_player(self, player):
if not self.gold_claimed:
self.gold_claimed = True
player.gold = player.gold + self.gold
print("+{} gold added.".format(self.gold))
def intro_text(self):
if self.gold_claimed:
return """
Another unremarkable part of the cave. You must forge onwards.
"""
else:
return """
Someone dropped some gold. You pick it up.
"""
class TrapRoomTile(MapTile):
def __init__(self, x, y):
r = random.randint(1,2)
if r == 1:
self.trap = items.PitFall()
self.tripped_text = "The open hole of a Pit Fall trap obstructs the tunnel."
self.set_text = "The floor in this hallway is unusually clean."
else:
self.set_text = "Looks like more bare stone... "
super().__init__(x, y)
def modify_player(self,player):
if not self.trap.is_tripped():
player.hp = player.hp - self.items.damage
print("You stumbled into a trap!")
time.sleep(1)
print("\nTrap does {} damage. You have {} HP remaining.".
format(self.items.damage, player.hp))
def intro_text(self):
text = self.tripped_text if self.trap.is_tripped() else self.set_text
time.sleep(0.1)
return text
class EmptyRoomTile(MapTile):
def intro_text(self):
r = random.random()
if r < .10:
return"""
Rough hewn stone walls are all you can make out in the flickering tourch light.
"""
elif r < .30:
return"""
There is nothing remarkable in this part of the tunnel keep moving onward!
"""
elif r < .50:
return"""
The dirt in this part of th ecave is scuffed but otherise there is nothing
remarkable here. best push on.
"""
elif r < 70:
return"""
You've been walking for a while without finding anyone or anything.
no sense in going back now better keep moving.
"""
else:
return"""
Great more stone... Is that a breeze I feel better keep going.
"""
class TraderTile(MapTile):
def __init__(self, x, y):
self.trader = npc.Trader()
super().__init__(x, y)
def check_if_trade(self, player):
while True:
print("Would you like to (B)uy, (S)ell, or (Q)uit?")
user_input = input()
if user_input in ['Q', 'q']:
return
elif user_input in ['B', 'b']:
print("Here's whats available to buy: ")
self.trade(buyer=player, seller=self.trader)
elif user_input in ['S', 's']:
print("Here's whats available to sell: ")
self.trade(buyer=self.trader, seller=player)
else:
print("Invalid choice!")
def trade(self, buyer, seller):
for i, item in enumerate(seller.inventory, 1):
print("{}. {} - {} Gold".format(i, item.name, item.value))
while True:
user_input = input("Choose an item or press Q to exit: ")
if user_input in ['Q', 'q']:
return
else:
try:
choice = int(user_input)
to_swap = seller.inventory[choice - 1]
self.swap(seller, buyer, to_swap)
except ValueError:
print("Invalid choice!")
def swap(self, seller, buyer, item):
if item.value > buyer.gold:
print("That's too expensive")
return
seller.inventory.remove(item)
buyer.inventory.append(item)
seller.gold = int(seller.gold) + int(item.value)
buyer.gold = int(buyer.gold) - int(item.value)
print("Trade complete!")
def intro_text(self):
return """
A frail not-quite-human, not-quite-creature squats in the corner
clinking his gold coins together. He looks willing to trade.
"""
world_dsl = """
|EN|EN|VT|EN|EN|
|EN| | | |EN|
|EN|FG|GS| |TT|
|TT| |ST|FG|EN|
|FG| |TR| |FG|
"""
def is_dsl_valid(dsl):
if dsl.count("|ST|") != 1:
return False
if dsl.count("|VT|") == 0:
return False
lines = dsl.splitlines()
lines = [l for l in lines if l]
pipe_counts = [line.count("|") for line in lines]
for count in pipe_counts:
if count != pipe_counts[0]:
return False
return True
tile_type_dict = {"VT": VictoryTile,
"EN": EnemyTile,
"ST": StartTile,
"FG": FindGoldTile,
"TT": TraderTile,
"GS": GoblinScoutTile,
"GB": GoblinBasherTile,
"ER": EmptyRoomTile,
"TR":TrapRoomTile,
" ": None}
world_map = []
start_tile_location = None
def parse_world_dsl():
if not is_dsl_valid(world_dsl):
raise SyntaxError("DSL is invalid!")
dsl_lines = world_dsl.splitlines()
dsl_lines = [x for x in dsl_lines if x]
for y, dsl_row in enumerate(dsl_lines):
row = []
dsl_cells = dsl_row.split("|")
dsl_cells = [c for c in dsl_cells if c]
for x, dsl_cell in enumerate(dsl_cells):
tile_type = tile_type_dict[dsl_cell]
if tile_type == StartTile:
global start_tile_location
start_tile_location = x, y
row.append(tile_type(x, y) if tile_type else None)
world_map.append(row)
def tile_at(x, y):
if x < 0 or y < 0:
return None
try:
return world_map[y][x]
except IndexError:
return None
You create the trap only sometimes. 50% of the time you don't put that attribute to your TrapRoomTile at all:
r = random.randint(1,2)
if r == 1:
self.trap = items.PitFall()
You could put self.trap = None to the else there, if you really want to have trap tiles without traps. Then you need to check if the trap tile has a trap when you try to use it.
It might also be that a component based approach, instead of subclassing, would serve you better, but that's another story.

Implementing a parametric L-system using python

I have been working on an implementation of a parametric L-system with python. My case is a 2D tree therefore i am using python turtle library. I wrote this simple code for a non-parametric L-system which it works pretty good. Here is my code:
import turtle as T
class LSystem:
def __init__(self, axiom, width, length, angle):
self.axiom = axiom
self.state = axiom
self.width = width
self.length = length
self.angle = angle
self.rules = {}
T.pensize(self.width)
def add_rules(self, *rules):
for arg in rules:
self.rules[arg[0]] = arg[-1]
def single_generation(self):
next_state = ""
for char in self.state:
if char in self.rules:
next_state += self.rules[char]
else:
next_state += char
self.state = next_state
def set_turtle(self, my_tuple):
T.up()
T.goto(my_tuple[0], my_tuple[1])
T.seth(my_tuple[2])
T.down()
def length_function(self, r):
self.length *= r
def width_function(self, q, e):
self.width *= q**e
def draw_turtle(self):
turtle_state = []
# ***************
T.tracer(0, 0)
T.down()
T.ht()
T.speed(0)
T.seth(90)
# ***************
for move in self.state:
if move == "[":
turtle_state.append((T.xcor(), T.ycor(), T.heading(), T.pensize()))
elif move == "]":
xcor, ycor, head, wid = turtle_state.pop()
self.set_turtle((xcor, ycor, head))
self.width = wid
elif move == 'F':
T.fd(self.length)
T.pensize(self.width)
elif move == '+':
T.left(self.angle)
elif move == '-':
T.right(self.angle)
T.getscreen()
T.done()
if __name__ == '__main__':
my_axiom = "A"
my_width = 10
my_length = 60
my_angle = 33.5
LSys = LSystem(my_axiom, my_width, my_length, my_angle)
my_rule = ("A", "F[+A][-A]")
LSys.add_rules(my_rule)
LSys.single_generation()
LSys.single_generation()
LSys.single_generation()
LSys.single_generation()
LSys.single_generation()
LSys.draw_turtle()
The problem is this code is working for a simple non-parametric L-system but i want to decrease diameter and length of my tree in each step. I have wrote two functions for this, length_function and width_functionbut i don't know where or how to use it. Here is my L-system rules and axiom:
A(s,w) ------> F(s,w)[+A(s*r1, w* q^e)][-A(s*r2, w* (1-q)^e]
axiom = "A(s0, w0)"
The values for r1, r2, q, e are known. also the s0 & w0 are known. I don't want to store the values of these parameters in a string format, i want them in a list or array but i don't know how. Here is a picture of the tree i'm trying to draw vs what my code draws:
You correctly store the pensize when you encounter a '[' but you do not reduce it.
Do something like:
if move == "[":
self.width *= 0.95
turtle_state.append((T.xcor(), T.ycor(), T.heading(), self.width))

Python find closest turtle via mouse click

I'm in the process of creating a minesweeper style game using a turtle-based grid setup. I need to find the closest cell within the grid and reveal the icon located under it whether that be a bomb or a number icons. I'm not looking to make it exact, I just need the mouse click to find the nearest cell in the grid even if the click isn't directly on the board. Currently my code only reveals the icon of the last turtle created on the board and then does nothing else with further clicks.
What can I do to make it recognize the real closest click and do it multiple times until the last bomb is found?
import random
import turtle
import cell
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__probelist = []
offset = (size-1) * 17
for x in range(size):
for y in range(size):
t = cell.Cell(x,y)
t.up()
t.shape('question.gif')
t.goto(y*34-offset, offset-x*34)
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, (self.__boardsize**2) - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, x, y):
for t in self.__boardlist:
pos = t.position()
distx = abs(x - pos[0])
disty = abs(y - pos[1])
distfinal = (distx ** 2 + disty ** 2) ** 0.5
curdist = 0
if curdist < distfinal:
curdist = distfinal
closest = t
if closest in self.__probelist:
return (self.__probe, self.__bombnum)
elif closest in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
else:
closest.shape("0.gif")
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
def registershapes():
wn = turtle.Screen()
wn.register_shape('0.gif')
wn.register_shape('1.gif')
wn.register_shape('2.gif')
wn.register_shape('3.gif')
wn.register_shape('4.gif')
wn.register_shape('5.gif')
wn.register_shape('6.gif')
wn.register_shape('7.gif')
wn.register_shape('8.gif')
wn.register_shape('9.gif')
wn.register_shape('bomb.gif')
wn.register_shape('question.gif')
I believe you're approaching this problem the wrong way. You're activating screen.onclick() and trying to map it to a turtle. Instead, activate turtle.onclick() on the individual turtles, deactivating it when a turtle is selected. Then you don't have to search for the turtle in question, and not actively ignore turtles that have already been selected.
Below is my rework of your code from this and your previous question into an example you can run. I had to guess about the definition of the Cell class:
from turtle import Turtle, Screen
import random
class Cell(Turtle):
def __init__(self, number):
super().__init__("question.gif")
self.__number = number
self.penup()
def number(self):
return self.__number
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__rnums = None
offset = (size - 1) * 17
for y in range(size):
for x in range(size):
t = Cell(x + y * size)
t.goto(x * 34 - offset, offset - y * 34)
t.onclick(lambda x, y, self=t: closure(self))
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, self.__boardsize ** 2 - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, closest):
closest.onclick(None)
if closest.number() in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
else:
closest.shape("0.gif")
self.__probe += 1
return (self.__probe, self.__bombnum)
def registershapes():
screen.register_shape('0.gif')
# ...
screen.register_shape('bomb.gif')
screen.register_shape('question.gif')
def closure(closest):
_, rem = mine.probe(closest)
if rem == 0:
over = screen.textinput("Text Input", "Would you like to play again? (Y)es or (N)o")
if over.upper() == 'Y':
main()
else:
screen.bye()
def main():
global mine
board = screen.numinput("Numeric Input", "Enter desired board size: ")
mine = Game(int(board))
nummine = screen.numinput("Numeric Input", "Enter desired number of mines: ")
mine.hideMines(int(nummine))
screen = Screen()
mine = None
main()
screen.mainloop()

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