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

\$\endgroup\$
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)
\$\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\$ May 18 '21 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 '21 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 '21 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 '21 at 9:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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