Skip to content

Commit

Permalink
Introduce the --seed flag
Browse files Browse the repository at this point in the history
This patch makes each map generated from a random seed, the length of
the seed is controllerd by config.seed_length.

Since each run is seeded, it is possible to use a custom seed to start
the server, using:
```
$ ./rose-server --seed <seed>
```

This makes every run reproducible for debugging and testing.

Co-authored-by: Masha Shtivelberg <[email protected]>
Co-authored-by: Zoe Sasportas <[email protected]>
  • Loading branch information
2 people authored and bennyz committed Jul 31, 2024
1 parent 4c9b4aa commit 09e8c6c
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 15 deletions.
1 change: 1 addition & 0 deletions rose/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
game_duration = 60
number_of_cars = 4
is_track_random = True
seed_length = 5

# Matrix

Expand Down
6 changes: 0 additions & 6 deletions rose/common/obstacles.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
""" Game obstacles """

import random

NONE = "" # NOQA
CRACK = "crack" # NOQA
TRASH = "trash" # NOQA
Expand All @@ -11,7 +9,3 @@
BARRIER = "barrier" # NOQA

ALL = (NONE, CRACK, TRASH, PENGUIN, BIKE, WATER, BARRIER)


def get_random_obstacle():
return random.choice(ALL)
9 changes: 5 additions & 4 deletions rose/server/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ class Game(object):
Implements the server for the car race
"""

def __init__(self):
def __init__(self, seed):
self.hub = None
self.track = track.Track()
self.rng = random.Random(seed)
self.track = track.Track(seed=seed)
self.looper = task.LoopingCall(self.loop)
self.players = {}
self.free_cars = set(range(config.number_of_cars))
Expand Down Expand Up @@ -68,9 +69,9 @@ def add_player(self, name):
raise error.PlayerExists(name)
if not self.free_cars:
raise error.TooManyPlayers()
car = random.choice(tuple(self.free_cars))
car = self.rng.choice(tuple(self.free_cars))
self.free_cars.remove(car)
lane = random.choice(tuple(self.free_lanes))
lane = self.rng.choice(tuple(self.free_lanes))
self.free_lanes.remove(lane)
log.info("add player: %r, lane: %r, car: %r", name, lane, car)
self.players[name] = player.Player(name, car, lane)
Expand Down
23 changes: 22 additions & 1 deletion rose/server/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import random
import socket
import logging
import argparse
import string

from twisted.internet import reactor
from twisted.web import server, static
Expand All @@ -25,6 +27,13 @@ def main():
help="Definition of driver tracks: random or same."
"If not specified, random will be used.",
)
parser.add_argument(
"--seed",
"-s",
dest="seed",
default="",
help="Optional, use a custom seed for the map generation",
)

args = parser.parse_args()
"""
Expand All @@ -37,8 +46,16 @@ def main():
else:
config.is_track_random = True

if args.seed:
seed = args.seed
else:
seed = generate_seed(config.seed_length)

log.info(f"Seed for map: {seed}")
g = game.Game(seed=seed)

log.info("starting server")
g = game.Game()

h = net.Hub(g)
reactor.listenTCP(config.game_port, net.PlayerFactory(h))
root = static.File(config.web_root)
Expand All @@ -51,3 +68,7 @@ def main():
site = server.Site(root)
reactor.listenTCP(config.web_port, site)
reactor.run()


def generate_seed(seed_length=5):
return "".join(random.choice(string.ascii_lowercase) for _ in range(seed_length))
12 changes: 8 additions & 4 deletions rose/server/track.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@


class Track(object):
def __init__(self):
def __init__(self, seed=""):
self._matrix = None
self.rng = random.Random(seed)
self.reset()

# Game state interface
Expand Down Expand Up @@ -53,15 +54,18 @@ def _generate_row(self):
Otherwise, the tracks will be identical.
"""
row = [obstacles.NONE] * config.matrix_width
obstacle = obstacles.get_random_obstacle()
obstacle = self.get_random_obstacle()
if config.is_track_random:
for lane in range(config.max_players):
low = lane * config.cells_per_player
high = low + config.cells_per_player
cell = random.choice(range(low, high))
cell = self.rng.choice(range(low, high))
row[cell] = obstacle
else:
cell = random.choice(range(0, config.cells_per_player))
cell = self.rng.choice(range(0, config.cells_per_player))
for lane in range(config.max_players):
row[cell + lane * config.cells_per_player] = obstacle
return row

def get_random_obstacle(self):
return self.rng.choice(obstacles.ALL)

0 comments on commit 09e8c6c

Please sign in to comment.