Good morning guys!
I've just got done fixing my previous version of this code, and here we are with the "final" version. How would I improve it further?
I wanted to create the board, and the players, but my skillset is severely limited. But I'm trying to improve everyday!
from typing import List, Tuple
from random import randint
class Robot:
def __init__(self, name: str, place : List[int], start: Tuple[int, int] = (0,0), power: int = 100):
self._name = name
self._place = place
self._start = start
self._power = power
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if isinstance(value, str):
self._name = value
else:
raise TypeError("must be a string")
@property
def place(self):
return self._place
@place.setter
def place(self, value):
if isinstance(value, list):
self._start = value
else:
raise TypeError("must be a list")
@property
def start(self):
return self._start
@start.setter
def start(self, value):
if isinstance(value, tuple):
self._start = value
else:
raise TypeError("must be a tuple")
@property
def power(self):
return self._power
@power.setter
def power(self, value):
if isinstance(value, int):
self._start = value
else:
raise TypeError("must be a int")
@property
def check_power(self):
if self._power <= 0:
raise ValueError("No power")
def left(self, value):
# self.sprawdz_power()
self.power -= value
if self.place[0] - value < 0:
self.place[0] = self.place[0] - value + 8
else:
self.place[0] = self.place[0] - value
def up(self, value):
# self.sprawdz_power()
self.power -= value
if self.place[1] + value > 7:
self.place[1] = self.place[1] + value - 8
else:
self.place[1] = self.place[1] + value
if self.place[1] == 5:
self.power += 2
def __str__(self):
return "{} {} {}".format(self._name, self._place, self._power)
def check_position():
to_delete = []
for r_a_nr in range(len(robots)):
for r_b_nr in range(r_a_nr + 1, len(robots)):
if robots[r_a_nr].place == robots[r_b_nr].place:
if robots[r_a_nr].power >= robots[r_b_nr].power:
robots[r_a_nr].power = robots[r_a_nr].power + robots[r_b_nr].power
to_delete.append(r_b_nr)
print(f'Robot {robots[r_b_nr].name} has been slain by {robots[r_a_nr].name}')
elif robots[r_a_nr].power < robots[r_b_nr].power:
robots[r_b_nr].power = robots[r_b_nr].power + robots[r_a_nr].power
to_delete.append(r_a_nr)
print(f'Robot {robots[r_a_nr].name} has been slain by {robots[r_b_nr].name}')
for i in sorted(list(set(to_delete)), reverse=True):
del robots[i]
def game(number):
for _ in range(number):
if len(robots) == 1:
print(robots[0].name, "is victorious")
break
to_delete = []
for r_nr in range(len(robots)):
strona_rand = randint(0,1)
ruch_value = randint(0,4)
if strona_rand == 0:
try:
robots[r_nr].up(ruch_value)
except:
to_delete.append(r_nr)
elif strona_rand == 1:
try:
robots[r_nr].left(ruch_value)
except:
to_delete.append(r_nr)
for r_nr in sorted(to_delete, reverse=True):
print(f'Robot {robots[r_nr].name} lost all the power')
del robots[r_nr]
check_position()
robots = [
Robot(name = "A", place = [3,4], start = (0,0), power = 100),
Robot(name = "B", place = [1,2], start = (0,0), power = 100),
Robot(name = "C", place = [1,2], start = (0,0), power = 100),
Robot(name = "D", place = [1,2], start = (0,0), power = 100),
Robot(name = "E", place = [1,2], start = (0,0), power = 100),
]
game(100)
The logic:
Using the robot class - implement robot battles.
Each player has 5 robots. People move the robots alternately, if the robots meet in one field, one takes part of the energy of the other (or all). When the robot's power runs out, a second robot automatically appears.
or implement a fully random battle
1 Answer 1
Your check_position
function could use some more improvements. First, I would rename it to something like game_round
. Then I would get rid of dealing with indices and directly deal with the robots, and finally I would make the list of robots a parameter of the function:
from itertools import combinations
from random import choice, randint
def game_round(robots):
for robot in robots:
move = choice([robot.up, robot.left])
move(randint(0, 4))
robots = [robot for robot in robots if robot.power > 0]
losers = set()
for a, b in combinations(robots, 2):
if a.place == b.place:
loser, winner = sorted([a, b], key=lambda robot: robot.power)
winner.power += loser.power
losers.add(loser)
print(f'Robot {loser.name} has been slain by {winner.name}')
return [robot for robot in robots if robot not in losers]
I also added the movements into this function now.
Note that this function, just like yours, allows a robot to be slain by multiple other robots or even slay others and be slain at the same time. This also means that the sum of the powers of all robots is not constant.
Use it like this:
def game(robots, num_rounds):
for _ in range(num_rounds):
if len(robots) == 1:
print(f"robot {robots[0].name} was victorious!")
break
robots = game_round(robots)
if __name__ == "__main__":
robots = [...]
game(robots, 100)
-
\$\begingroup\$ Hmmm your function is great and all, but is there any chances to get any other result than victory of robot E? I also want to notice that, when I'm using your code, and using the robots from the list robots, robot A is not doing anything. Also if I have this function game_round, would I give up on function game? \$\endgroup\$KermitTheFrog– KermitTheFrog2021年05月18日 11:43:42 +00:00Commented May 18, 2021 at 11:43
-
\$\begingroup\$ @Daro1234451 This function is meant as a replacement of your
check_position
function. Robot A does not do anything (in round one) because it is not in the same place as any other robot. If it doesn't do anything in the other rounds you probably forgot to assign the output of the function torobots
. My function is a "pure function", i.e. it takes some input and returns an output that only depends on the input, without modifying anything in-place, in contrast to your function, which takes no input (just the global variables) and returns no output (but modifies a global variable in-place). \$\endgroup\$Graipher– Graipher2021年05月18日 11:48:54 +00:00Commented May 18, 2021 at 11:48 -
\$\begingroup\$ Hi i have still one question, would you like to explain it further? I will give u a example: When i was using my function check_positionprogram had different results, for example, if I used check_position in the game function, then after calling: pastebin.com/eUcfP8yw and your function is giving me the same output pastebin.com/QS5T1Y2w all the time, i dont know how to make it play, like go to round 2 or something like that? \$\endgroup\$KermitTheFrog– KermitTheFrog2021年05月24日 09:10:07 +00:00Commented May 24, 2021 at 9:10
-
\$\begingroup\$ @Daro1234451 I made the example more complete by also incorporating the movement part. Note that I assign the output of the function back to
robots
every iteration. \$\endgroup\$Graipher– Graipher2021年05月24日 09:29:54 +00:00Commented May 24, 2021 at 9:29