3
\$\begingroup\$

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

Graipher
41.6k7 gold badges70 silver badges134 bronze badges
asked May 18, 2021 at 6:48
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

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)
answered May 18, 2021 at 10:03
\$\endgroup\$
4
  • \$\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\$ Commented 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 to robots. 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\$ Commented 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\$ Commented 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\$ Commented May 24, 2021 at 9:29

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.