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

    def name(self):
        return self._name

    def name(self, value):
        if isinstance(value, str):
            self._name = value
            raise TypeError("must be a string")
    def place(self):
        return self._place

    def place(self, value):
        if isinstance(value, list):
            self._start = value
            raise TypeError("must be a list")
    def start(self):
        return self._start

    def start(self, value):
        if isinstance(value, tuple):
            self._start = value
            raise TypeError("must be a tuple")

    def power(self):
        return self._power

    def power(self, value):
        if isinstance(value, int):
            self._start = value
            raise TypeError("must be a int")

    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

            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

            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
                    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
                    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")

        to_delete = []
        for r_nr in range(len(robots)):
            strona_rand = randint(0,1)
            ruch_value = randint(0,4)

            if strona_rand == 0:

            elif strona_rand == 1:

        for r_nr in sorted(to_delete, reverse=True):
            print(f'Robot {robots[r_nr].name} lost all the power')
            del robots[r_nr]


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),


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
            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!")
        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\$ 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\$
    – Graipher
    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\$ 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
    May 24, 2021 at 9:29

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.