Chapter 3 - Han Solo: The Random Walker¶
Hi human. Glad to see you here. I thought you were lost in some capitalist leisure streaming service.
In this chapter, you will learn how to move once for all from your primitive planet and explore the galaxy. Once completed this tutorial you will be a globetrotter on the galaxy. The Han Solo of the Pythonium universe.
Warning
If you don’t know who Han Solo is stop here and come back once you were watched the full original trilogy of Star Wars.
target
: Where do you want to go?¶
Each ship
has a target
attribute indicating where the ship is going. This is one of the control variables
for your ships. You can edit this parameter to order your ships to go to some specific point in the galaxy.
Start the ipdb
debugger as you learned in Chapter 2, and select some random ship to be
your explorer:
ipdb> my_ships = galaxy.get_player_ships(self.name) # Find all your ships
ipdb> explorer_ship = next(my_ships) # Select the first ship
Now let’s see where the explorer ship is going:
ipdb> print(explorer_ship.target)
None
This means the ship has no target. In the next turn, it will be in the same position.
You can verify it easily.
ipdb> galaxy.turn # Check the current turn
0
ipdb> explorer_ship.position # Check the ship's position
(43, 37)
ipdb> c # Move one turn forward
...
ipdb> galaxy.turn # Now you are in turn 1
1
ipdb> my_ships = galaxy.get_player_ships(self.name) # Find the explorer ship again
ipdb> explorer_ship = next(my_ships)
ipdb> explorer_ship.position # The ship position is the same as previous turn
(43, 37)
The ship stays in the same position when time moves forward. It is not going anywhere.
Note
Note that when you move one turn forward ipbb
do not save the variables declared in the previous turn.
That’s why we need to search the explorer_ship
again.
Knowing the neighborhood¶
The next step is to find a destination for the explorer_ship
For sure you want to visit one of the many unknown planets around you (those with player=None
), and possibly you don’t
want to travel for all eternity. We need to find some unknown planet near yours to arrive fast. The ship should arrive
by the next turn.
But wait a minute, how fast the explorer_ship
moves?
Every ship has a speed
attribute indicating how many light-years can travel in a single turn.
ipdb> explorer_ship.speed
80
Based on this we can say the ship can travel up to 80ly in a single turn. The next step is to find an unknown planet that is 80ly or less from your planet.
The Galaxy.nearby_planets
method allows you to find all the planets that are
up to a certain distance away (or less) from a specific position. This method takes a position
and a distance
(called neighborhood
) and returns a list with all the nearby planets around that position.
In our case, the neighborhood will be 80ly, the distance the ship can travel in one turn, and the position will be the ship location.
ipdb> neighborhood = galaxy.nearby_planets(explorer_ship.position, explorer_ship.speed)
ipdb> pp neighborhood
[Planet(id=7d9321ab-57cb-4a05-afaa-c2f4ef8e4627, position=(43, 37), player=Han Solo),
Planet(id=a374a560-ba94-43b1-87b0-78eca8ca5b97, position=(25, 41), player=None),
Planet(id=e3319ed0-24ec-491c-bb76-a418d9b8b508, position=(112, 50), player=None),
Planet(id=1b7d714e-22d2-4ca2-826a-bf0656138793, position=(115, 9), player=None),
Planet(id=70279963-541b-49c9-bb87-32cf6936f45f, position=(31, 42), player=None),
Planet(id=73f25d86-44f1-4cfc-a8ac-44a96affa1d9, position=(9, 21), player=None),
Planet(id=1c7ec1c3-7aea-44bf-b582-1f7e3cb3b7ec, position=(81, 27), player=None),
Planet(id=1378a7ab-2120-46d3-ac93-fc50632141b0, position=(96, 62), player=None),
Planet(id=fb0d019d-ca71-4353-a06c-d3b4898ffd82, position=(93, 44), player=None),
Planet(id=02539d23-2911-4354-81f5-9a1f83ef0936, position=(21, 86), player=None),
Planet(id=38ce324b-ce2a-4bf1-997c-bb8990ae7509, position=(67, 37), player=None),
Planet(id=4e19fda6-ac81-4d85-bdde-bd7244430a2e, position=(70, 33), player=None),
Planet(id=e2234771-dbeb-425f-9b0a-1e761f5cf3e1, position=(44, 18), player=None),
Planet(id=b5b025dd-dfcf-4ca5-8b03-67bb3a04479f, position=(30, 92), player=None),
Planet(id=4b29c3d8-3c2f-4b33-8ca7-f451eb269e21, position=(61, 110), player=None),
Planet(id=72b77b24-0063-42f1-aeb0-259f04125cbd, position=(67, 71), player=None),
Planet(id=bf00cfa3-aece-48e6-8d67-11b3797e2f2c, position=(42, 69), player=None),
Planet(id=43bcb3bb-b788-46e9-b425-8539caeff03c, position=(89, 64), player=None),
Planet(id=0a9f5a40-034e-4fe8-a6b1-83f3437e09c8, position=(109, 54), player=None),
Planet(id=a51d8923-1003-4357-bb2b-f3efa7d5023e, position=(17, 35), player=None),
Planet(id=da112184-1e01-41ee-b146-d073946ce41e, position=(32, 81), player=None),
Planet(id=765a19df-2639-4efd-8aa6-30ff3926039c, position=(75, 40), player=None),
Planet(id=40052c15-3ffa-4dfa-ad22-9afbd0a16091, position=(95, 57), player=None)]
Cool, right?
All those planets are one turn away the explorer_ship
. Notice that your planet is included in the neighborhood (because your ship is located in it and
the distance to it is zero).
Traveling¶
Now let’s select the target for the ship. For now, keep it simple: pic some random unknown planet from the list.
ipdb> unknown_nearby_planets = [p for p in neighborhood if p.player is None]
ipdb> import random
ipdb> target_planet = random.choice(unknown_nearby_planets)
ipdb> target_planet
Planet(id=1b7d714e-22d2-4ca2-826a-bf0656138793, position=(115, 9), player=None)
That’s your ship first destination. An unknown planet one turn away from your ship’s location.
The next step is set the ship’s target
as the planet’s position
and move one turn forward.
ipdb> galaxy.turn # Check the current turn
1
ipdb> explorer_ship.position # Check the ship position
(43, 37)
ipdb> explorer_ship.target = target_planet.position # set the ship target
ipdb> c # move one turn forward
Where is the ship now?
ipdb> galaxy.turn # you are one turn ahead
2
ipdb> my_ships = galaxy.get_player_ships(self.name) # Find all your ships
ipdb> explorer_ship = next(my_ships) # And keep the explorer ship
ipdb> explorer_ship.position # Check the ship position
(115, 9)
ipdb> explored_planet = galaxy.planets.get(explorer_ship.position) # Find the planet in the ship's position
ipdb> explored_planet
Planet(id=1b7d714e-22d2-4ca2-826a-bf0656138793, position=(115, 9), player=None)
Your explorer ship just arrived at the target planet. A new and unknown rock in the middle of the space with a lot of things to learn about and explore.
Congratulations human. You did it. You left the pathetic rock where you spent your whole life, and now you are in a different one. Probably more pathetic, probably more boring, maybe you don’t even have air to breathe or food to eat. But hey… you are a space traveler.
Putting the pieces together¶
In this chapter, we explained how to move your ships. You learned the first, and most basic command: Ship movement.
But we also developed a strategy. I call it “The Random Walker Strategy”: A group of ships moving around, exploring planets without much more to do but travel around the galaxy.
Let’s exit the debugger, edit your player class, and apply the random walker strategy to all your ships.
You will end up with something like this:
import random
from pythonium import AbstractPlayer
class Player(AbstractPlayer):
name = 'Han Solo'
def next_turn(self, galaxy, context):
# Get your ships
my_ships = galaxy.get_player_ships(self.name)
# For every of your ships...
for ship in my_ships:
# find the nearby planets...
nearby_planets = galaxy.nearby_planets(ship.position, ship.speed)
# pick any of them...
target_planet = random.choice(nearby_planets)
# an set the target to the selected planet
ship.target = target_planet.position
return galaxy
After executing your player the generated gif should look similar to this one:
Can you see those ships moving around? That, my friend, is what I call freedom.
Long travels¶
The implemented random walker strategy moves ships to planets that are one turn away from the original position only.
If you send a ship to a point that is furthest the distance the ship can travel in one turn (this is ship.speed
),
it will take more than one turn to arrive at the destination. In the next turn, the ship will be at some point in the
middle between the target and the original destination.
Of course, you can change the ship’s target at any time during travel.
Note
Challenge Build a random walker player that travels to planets that are two turns away only (and not planets that are one turn away)
Final thoughts¶
In this chapter we introduced the target
attribute, and how it can be used
to set a movement command for a ship.
We also explained how to find planets around certain position with the Galaxy.nearby_planets
method.
Finally, this chapter is a first attempt to describe a player-building methodology in pythonium. Usually, you will make use of the debugger to test some commands, try a few movements and see how they work from one turn to another. This will help you to start a draft for your player strategy, and after that, you will need to code it in your player class.
The debugger is a good tool for testing and see how things evolve in a rudimentary way. On more complex players it is hard
to track all the changes and commands that happen in one turn. Imagine you having an empire of more than
100 planets and around 150 ships, it is impossible to check all the positions and movements with the ipdb
debugger.
For those cases, there are more advanced techniques of analysis that involve the generated logs and the report file. But that is a topic for future chapters.
I hope to see you again, there’s still a lot more to learn.