Skip to content

Commit 7cf29c1

Browse files
authored
Merge pull request #828 from Debilski/feature/use_rng_instead_of_seed
RF: Rename rnd to rng and use instead of seed if applicable.
2 parents 3dae424 + eeb9c6f commit 7cf29c1

22 files changed

+237
-185
lines changed

contrib/ci_engine.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@
4646
import itertools
4747
import json
4848
import logging
49-
import random
5049
import sqlite3
5150
import subprocess
5251
import sys
52+
from random import Random
5353

5454
import click
5555
from rich.console import Console
@@ -184,6 +184,7 @@ def start(self, n):
184184
185185
"""
186186
loop = itertools.repeat(None) if n == 0 else itertools.repeat(None, n)
187+
rng = Random()
187188

188189
for _ in loop:
189190
# choose the player with the least number of played game,
@@ -193,9 +194,9 @@ def start(self, n):
193194
game_count = [(self.dbwrapper.get_game_count(p['name']), idx) for idx, p in enumerate(self.players)]
194195
players_sorted = [idx for count, idx in sorted(game_count) if not idx in broken_players]
195196
a, rest = players_sorted[0], players_sorted[1:]
196-
b = random.choice(rest)
197+
b = rng.choice(rest)
197198
players = [a, b]
198-
random.shuffle(players)
199+
rng.shuffle(players)
199200

200201
self.run_game(players[0], players[1])
201202
self.pretty_print_results(highlight=[self.players[players[0]]['name'], self.players[players[1]]['name']])

pelita/base_utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from random import Random
2+
3+
def default_rng(seed=None):
4+
"""Construct a new RNG from a given seed or return the same RNG.
5+
6+
Parameters
7+
----------
8+
seed : Random | int | None
9+
RNG to re-use or seed to initialise a new RNG or None to initialise a RNG without seed
10+
"""
11+
if isinstance(seed, Random):
12+
return seed
13+
return Random(seed)

pelita/game.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import logging
44
import os
5-
from random import Random
65
import subprocess
76
import sys
87
import time
@@ -14,6 +13,7 @@
1413
from .gamestate_filters import noiser, update_food_age, relocate_expired_food
1514
from .layout import initial_positions, get_legal_positions
1615
from .network import setup_controller, ZMQPublisher
16+
from .base_utils import default_rng
1717
from .team import make_team
1818
from .viewer import ProgressViewer, AsciiViewer, ReplyToViewer, ReplayWriter, ResultPrinter
1919

@@ -88,7 +88,7 @@ def controller_exit(state, await_action='play_step'):
8888
return False
8989

9090
def run_game(team_specs, *, layout_dict, layout_name="", max_rounds=300,
91-
seed=None, allow_camping=False, error_limit=5, timeout_length=3,
91+
rng=None, allow_camping=False, error_limit=5, timeout_length=3,
9292
viewers=None, viewer_options=None, store_output=False,
9393
team_names=(None, None), team_infos=(None, None),
9494
allow_exceptions=False, print_result=True):
@@ -119,8 +119,8 @@ def run_game(team_specs, *, layout_dict, layout_name="", max_rounds=300,
119119
max_rounds : int
120120
The maximum number of rounds to play before the game is over. Default: 300.
121121
122-
seed : int
123-
seed used to initialize the random number generator.
122+
rng : random.Random | int | None
123+
random number generator or a seed used to initialize a new one.
124124
125125
error_limit : int
126126
The limit of non fatal errors to reach for a team before the
@@ -196,7 +196,7 @@ def run_game(team_specs, *, layout_dict, layout_name="", max_rounds=300,
196196
layout_name=layout_name, max_rounds=max_rounds,
197197
allow_camping=allow_camping,
198198
error_limit=error_limit, timeout_length=timeout_length,
199-
seed=seed, viewers=viewers,
199+
rng=rng, viewers=viewers,
200200
viewer_options=viewer_options,
201201
store_output=store_output, team_names=team_names,
202202
team_infos=team_infos,
@@ -271,7 +271,7 @@ def setup_viewers(viewers=None, options=None, print_result=True):
271271
return viewer_state
272272

273273

274-
def setup_game(team_specs, *, layout_dict, max_rounds=300, layout_name="", seed=None,
274+
def setup_game(team_specs, *, layout_dict, max_rounds=300, layout_name="", rng=None,
275275
allow_camping=False, error_limit=5, timeout_length=3,
276276
viewers=None, viewer_options=None, store_output=False,
277277
team_names=(None, None), team_infos=(None, None),
@@ -313,6 +313,8 @@ def setup_game(team_specs, *, layout_dict, max_rounds=300, layout_name="", seed=
313313

314314
viewer_state = setup_viewers(viewers, options=viewer_options, print_result=print_result)
315315

316+
rng = default_rng(rng)
317+
316318
# Initialize the game state.
317319

318320
game_state = dict(
@@ -415,7 +417,7 @@ def setup_game(team_specs, *, layout_dict, max_rounds=300, layout_name="", seed=
415417
teams=[None] * 2,
416418

417419
#: Random number generator
418-
rnd=Random(seed),
420+
rng=rng,
419421

420422
#: Timeout length, int, None
421423
timeout_length=timeout_length,
@@ -534,7 +536,7 @@ def prepare_bot_state(game_state, idx=None):
534536
# We assume that we are in get_initial phase
535537
turn = idx
536538
bot_turn = None
537-
seed = game_state['rnd'].randint(0, sys.maxsize)
539+
seed = game_state['rng'].randint(0, sys.maxsize)
538540
elif bot_finalization:
539541
# Called for remote players in _exit
540542
turn = idx
@@ -555,7 +557,7 @@ def prepare_bot_state(game_state, idx=None):
555557
enemy_positions=enemy_positions,
556558
noise_radius=game_state['noise_radius'],
557559
sight_distance=game_state['sight_distance'],
558-
rnd=game_state['rnd'])
560+
rng=game_state['rng'])
559561

560562

561563
# Update noisy_positions in the game_state
@@ -669,7 +671,7 @@ def prepare_viewer_state(game_state):
669671

670672
# remove unserializable values
671673
del viewer_state['teams']
672-
del viewer_state['rnd']
674+
del viewer_state['rng']
673675
del viewer_state['viewers']
674676
del viewer_state['controller']
675677

@@ -855,7 +857,7 @@ def apply_move(gamestate, bot_position):
855857
# There was an error for this round and turn
856858
# but the game is not over.
857859
# We execute a random move
858-
bot_position = gamestate['rnd'].choice(legal_positions)
860+
bot_position = gamestate['rng'].choice(legal_positions)
859861
game_print(turn, f"Setting a legal position at random: {bot_position}")
860862

861863
# take step

pelita/gamestate_filters.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
""" collecting the game state filter functions """
2-
import random
2+
from .base_utils import default_rng
33

44

5-
def noiser(walls, shape, bot_position, enemy_positions, noise_radius=5, sight_distance=5, rnd=None):
5+
def noiser(walls, shape, bot_position, enemy_positions, noise_radius=5, sight_distance=5, rng=None):
66
"""Function to make bot positions noisy in a game state.
77
88
Applies uniform noise in maze space. Noise will only be applied if the
@@ -38,7 +38,7 @@ def noiser(walls, shape, bot_position, enemy_positions, noise_radius=5, sight_di
3838
the radius for the uniform noise
3939
sight_distance : int, optional, default: 5
4040
the distance at which noise is no longer applied.
41-
rnd : Random, optional
41+
rng : Random, optional
4242
the game’s random number generator (or None for an independent one)
4343
4444
Returns
@@ -48,8 +48,7 @@ def noiser(walls, shape, bot_position, enemy_positions, noise_radius=5, sight_di
4848
"""
4949

5050
# set the random state
51-
if rnd is None:
52-
rnd = random.Random()
51+
rng = default_rng(rng)
5352

5453
# store the noised positions
5554
noised_positions = [None] * len(enemy_positions)
@@ -64,7 +63,7 @@ def noiser(walls, shape, bot_position, enemy_positions, noise_radius=5, sight_di
6463

6564
if cur_distance is None or cur_distance > sight_distance:
6665
# If so then alter the position of the enemy
67-
new_pos, noisy_flag = alter_pos(b, noise_radius, rnd, walls, shape)
66+
new_pos, noisy_flag = alter_pos(b, noise_radius, rng, walls, shape)
6867
noised_positions[count] = new_pos
6968
is_noisy[count] = noisy_flag
7069
else:
@@ -74,7 +73,7 @@ def noiser(walls, shape, bot_position, enemy_positions, noise_radius=5, sight_di
7473
return { "enemy_positions": noised_positions, "is_noisy": is_noisy }
7574

7675

77-
def alter_pos(bot_pos, noise_radius, rnd, walls, shape):
76+
def alter_pos(bot_pos, noise_radius, rng, walls, shape):
7877
""" alter the position """
7978

8079
# get a list of possible positions
@@ -110,7 +109,7 @@ def alter_pos(bot_pos, noise_radius, rnd, walls, shape):
110109
noisy = False
111110
else:
112111
# select a random position
113-
final_pos = rnd.choice(possible_positions)
112+
final_pos = rng.choice(possible_positions)
114113
noisy = True
115114

116115
# return the final_pos and a flag if it is noisy or not
@@ -153,7 +152,7 @@ def relocate_expired_food(game_state, team, radius, max_food_age=None):
153152
food_age = [dict(team_food_age) for team_food_age in game_state['food_age']]
154153
width, height = game_state['shape']
155154
walls = game_state['walls']
156-
rnd = game_state['rnd']
155+
rng = game_state['rng']
157156
if max_food_age is None:
158157
max_food_age = game_state['max_food_age']
159158

@@ -186,7 +185,7 @@ def relocate_expired_food(game_state, team, radius, max_food_age=None):
186185
# relocated at the next round
187186
continue
188187
# choose a new position at random
189-
new_pos = rnd.choice(targets)
188+
new_pos = rng.choice(targets)
190189

191190
# remove the new pellet position from the list of possible targets for new pellets
192191
targets.remove(new_pos)

pelita/layout.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import importlib.resources as importlib_resources
1+
22
import io
33
import os
4-
import random
4+
import importlib.resources as importlib_resources
5+
6+
from .base_utils import default_rng
57

68
# bot to index conversion
79
BOT_N2I = {'a': 0, 'b': 2, 'x': 1, 'y': 3}
810
BOT_I2N = {0: 'a', 2: 'b', 1: 'x', 3: 'y'}
911

1012

11-
RNG = random.Random()
12-
13-
def get_random_layout(size='normal', seed=None, dead_ends=0):
13+
def get_random_layout(size='normal', dead_ends=0, rng=None):
1414
""" Return a random layout string from the available ones.
1515
1616
Parameters
@@ -34,13 +34,15 @@ def get_random_layout(size='normal', seed=None, dead_ends=0):
3434
the name of the layout, a random layout string
3535
3636
"""
37-
if seed is not None:
38-
RNG.seed(seed)
39-
if dead_ends and RNG.random() < dead_ends:
37+
38+
# set the random state
39+
rng = default_rng(rng)
40+
41+
if dead_ends and rng.random() < dead_ends:
4042
layouts_names = get_available_layouts(size=size, dead_ends=True)
4143
else:
4244
layouts_names = get_available_layouts(size=size, dead_ends=False)
43-
layout_choice = RNG.choice(layouts_names)
45+
layout_choice = rng.choice(layouts_names)
4446
return layout_choice, get_layout_by_name(layout_choice)
4547

4648
def get_available_layouts(size='normal', dead_ends=False):

0 commit comments

Comments
 (0)