Skip to content

Commit

Permalink
Merge pull request #828 from Debilski/feature/use_rng_instead_of_seed
Browse files Browse the repository at this point in the history
RF: Rename rnd to rng and use instead of seed if applicable.
  • Loading branch information
otizonaizit authored Oct 9, 2024
2 parents 3dae424 + eeb9c6f commit 7cf29c1
Show file tree
Hide file tree
Showing 22 changed files with 237 additions and 185 deletions.
7 changes: 4 additions & 3 deletions contrib/ci_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@
import itertools
import json
import logging
import random
import sqlite3
import subprocess
import sys
from random import Random

import click
from rich.console import Console
Expand Down Expand Up @@ -184,6 +184,7 @@ def start(self, n):
"""
loop = itertools.repeat(None) if n == 0 else itertools.repeat(None, n)
rng = Random()

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

self.run_game(players[0], players[1])
self.pretty_print_results(highlight=[self.players[players[0]]['name'], self.players[players[1]]['name']])
Expand Down
13 changes: 13 additions & 0 deletions pelita/base_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from random import Random

def default_rng(seed=None):
"""Construct a new RNG from a given seed or return the same RNG.
Parameters
----------
seed : Random | int | None
RNG to re-use or seed to initialise a new RNG or None to initialise a RNG without seed
"""
if isinstance(seed, Random):
return seed
return Random(seed)
24 changes: 13 additions & 11 deletions pelita/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import logging
import os
from random import Random
import subprocess
import sys
import time
Expand All @@ -14,6 +13,7 @@
from .gamestate_filters import noiser, update_food_age, relocate_expired_food
from .layout import initial_positions, get_legal_positions
from .network import setup_controller, ZMQPublisher
from .base_utils import default_rng
from .team import make_team
from .viewer import ProgressViewer, AsciiViewer, ReplyToViewer, ReplayWriter, ResultPrinter

Expand Down Expand Up @@ -88,7 +88,7 @@ def controller_exit(state, await_action='play_step'):
return False

def run_game(team_specs, *, layout_dict, layout_name="", max_rounds=300,
seed=None, allow_camping=False, error_limit=5, timeout_length=3,
rng=None, allow_camping=False, error_limit=5, timeout_length=3,
viewers=None, viewer_options=None, store_output=False,
team_names=(None, None), team_infos=(None, None),
allow_exceptions=False, print_result=True):
Expand Down Expand Up @@ -119,8 +119,8 @@ def run_game(team_specs, *, layout_dict, layout_name="", max_rounds=300,
max_rounds : int
The maximum number of rounds to play before the game is over. Default: 300.
seed : int
seed used to initialize the random number generator.
rng : random.Random | int | None
random number generator or a seed used to initialize a new one.
error_limit : int
The limit of non fatal errors to reach for a team before the
Expand Down Expand Up @@ -196,7 +196,7 @@ def run_game(team_specs, *, layout_dict, layout_name="", max_rounds=300,
layout_name=layout_name, max_rounds=max_rounds,
allow_camping=allow_camping,
error_limit=error_limit, timeout_length=timeout_length,
seed=seed, viewers=viewers,
rng=rng, viewers=viewers,
viewer_options=viewer_options,
store_output=store_output, team_names=team_names,
team_infos=team_infos,
Expand Down Expand Up @@ -271,7 +271,7 @@ def setup_viewers(viewers=None, options=None, print_result=True):
return viewer_state


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

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

rng = default_rng(rng)

# Initialize the game state.

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

#: Random number generator
rnd=Random(seed),
rng=rng,

#: Timeout length, int, None
timeout_length=timeout_length,
Expand Down Expand Up @@ -534,7 +536,7 @@ def prepare_bot_state(game_state, idx=None):
# We assume that we are in get_initial phase
turn = idx
bot_turn = None
seed = game_state['rnd'].randint(0, sys.maxsize)
seed = game_state['rng'].randint(0, sys.maxsize)
elif bot_finalization:
# Called for remote players in _exit
turn = idx
Expand All @@ -555,7 +557,7 @@ def prepare_bot_state(game_state, idx=None):
enemy_positions=enemy_positions,
noise_radius=game_state['noise_radius'],
sight_distance=game_state['sight_distance'],
rnd=game_state['rnd'])
rng=game_state['rng'])


# Update noisy_positions in the game_state
Expand Down Expand Up @@ -669,7 +671,7 @@ def prepare_viewer_state(game_state):

# remove unserializable values
del viewer_state['teams']
del viewer_state['rnd']
del viewer_state['rng']
del viewer_state['viewers']
del viewer_state['controller']

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

# take step
Expand Down
19 changes: 9 additions & 10 deletions pelita/gamestate_filters.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
""" collecting the game state filter functions """
import random
from .base_utils import default_rng


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

# set the random state
if rnd is None:
rnd = random.Random()
rng = default_rng(rng)

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

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


def alter_pos(bot_pos, noise_radius, rnd, walls, shape):
def alter_pos(bot_pos, noise_radius, rng, walls, shape):
""" alter the position """

# get a list of possible positions
Expand Down Expand Up @@ -110,7 +109,7 @@ def alter_pos(bot_pos, noise_radius, rnd, walls, shape):
noisy = False
else:
# select a random position
final_pos = rnd.choice(possible_positions)
final_pos = rng.choice(possible_positions)
noisy = True

# return the final_pos and a flag if it is noisy or not
Expand Down Expand Up @@ -153,7 +152,7 @@ def relocate_expired_food(game_state, team, radius, max_food_age=None):
food_age = [dict(team_food_age) for team_food_age in game_state['food_age']]
width, height = game_state['shape']
walls = game_state['walls']
rnd = game_state['rnd']
rng = game_state['rng']
if max_food_age is None:
max_food_age = game_state['max_food_age']

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

# remove the new pellet position from the list of possible targets for new pellets
targets.remove(new_pos)
Expand Down
20 changes: 11 additions & 9 deletions pelita/layout.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import importlib.resources as importlib_resources

import io
import os
import random
import importlib.resources as importlib_resources

from .base_utils import default_rng

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


RNG = random.Random()

def get_random_layout(size='normal', seed=None, dead_ends=0):
def get_random_layout(size='normal', dead_ends=0, rng=None):
""" Return a random layout string from the available ones.
Parameters
Expand All @@ -34,13 +34,15 @@ def get_random_layout(size='normal', seed=None, dead_ends=0):
the name of the layout, a random layout string
"""
if seed is not None:
RNG.seed(seed)
if dead_ends and RNG.random() < dead_ends:

# set the random state
rng = default_rng(rng)

if dead_ends and rng.random() < dead_ends:
layouts_names = get_available_layouts(size=size, dead_ends=True)
else:
layouts_names = get_available_layouts(size=size, dead_ends=False)
layout_choice = RNG.choice(layouts_names)
layout_choice = rng.choice(layouts_names)
return layout_choice, get_layout_by_name(layout_choice)

def get_available_layouts(size='normal', dead_ends=False):
Expand Down
Loading

0 comments on commit 7cf29c1

Please sign in to comment.