implemented level generator
This commit is contained in:
parent
794c987899
commit
65f195fecf
124
gauss-turing/game/level_generator.py
Normal file
124
gauss-turing/game/level_generator.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
from gauss_turing import Program, Board, Command, Robot
|
||||
import numpy as np
|
||||
import json
|
||||
|
||||
levels = {
|
||||
0: lambda cmds: len(cmds) <= 3,
|
||||
1: lambda cmds: len(cmds) == 3
|
||||
}
|
||||
|
||||
def rate_level(robot_path, cmds, board):
|
||||
path_length = len(set(robot_path))
|
||||
n_cmds = len(cmds)
|
||||
n_cmd_colors = len(set([tuple(c.color) for c in cmds]))
|
||||
|
||||
difficulty = (path_length - 1) * (n_cmds + n_cmd_colors)
|
||||
|
||||
# place coins on the robot path to create a solution
|
||||
if difficulty > 0:
|
||||
n_coins = np.random.randint(1, min(path_length, 5)) - 1
|
||||
|
||||
# put one coin on last tile visited
|
||||
coins = [robot_path[-1]]
|
||||
|
||||
# distribute other coins randomly on the path
|
||||
# path without first and list tile
|
||||
unique_tiles = list(set(robot_path) - {robot_path[-1]} - {robot_path[0]})
|
||||
|
||||
for _ in range(n_coins):
|
||||
c = np.random.randint(0, len(unique_tiles))
|
||||
new_coin = unique_tiles.pop(c)
|
||||
coins.append(new_coin)
|
||||
pass
|
||||
else:
|
||||
coins = []
|
||||
|
||||
return difficulty, coins
|
||||
|
||||
def generate_level(dimx, dimy, max_steps=100):
|
||||
n_cmds = np.random.randint(2, 6)
|
||||
assert n_cmds <= 5
|
||||
|
||||
# generate random board without any coins
|
||||
board = Board(dimx, dimy, n_coins=0)
|
||||
|
||||
cmds = []
|
||||
actions = list(sorted(Command.valid_actions - {'-'}))
|
||||
# generate random commands
|
||||
for i in range(n_cmds):
|
||||
action = np.random.choice(actions)
|
||||
color = Board.valid_colors[np.random.randint(len(Board.valid_colors))]
|
||||
cmds.append(Command(action, color))
|
||||
|
||||
# generate robot at random position
|
||||
rx = np.random.randint(0, dimx-1)
|
||||
ry = np.random.randint(0, dimy-1)
|
||||
orientation = np.random.choice(['>','v','<','^'])
|
||||
r = Robot(rx, ry, orientation)
|
||||
|
||||
prg = Program(r, board, cmds)
|
||||
continue_running = True
|
||||
state = 'running'
|
||||
prg_counter_old = prg.prg_counter
|
||||
|
||||
robot_path = [(r.x, r.y)]
|
||||
step = 0
|
||||
|
||||
while continue_running and step < max_steps:
|
||||
#print(f"prg_counter = {prg.prg_counter} - robot: {r} - state: {state}")
|
||||
state = prg.step(state, check_victory=False)
|
||||
|
||||
robot_path.append((r.x, r.y))
|
||||
|
||||
stuck = prg.prg_counter == prg_counter_old
|
||||
|
||||
prg_counter_old = prg.prg_counter
|
||||
|
||||
if state == 'game_over' or stuck:
|
||||
continue_running = False
|
||||
|
||||
step += 1
|
||||
|
||||
last_pos = robot_path[-1]
|
||||
if not ((0 <= last_pos[0] < dimx) and (0 <= last_pos[1] < dimy)):
|
||||
# remove last entry of path if robot leaves the board
|
||||
robot_path.pop(-1)
|
||||
|
||||
difficulty, coins = rate_level(robot_path, cmds, board)
|
||||
|
||||
# put coins on the board
|
||||
for coin in coins:
|
||||
board.tiles[coin[1], coin[0]]['star'] = True
|
||||
n_coins = len(coins)
|
||||
|
||||
|
||||
return difficulty, board, n_coins, set(robot_path), (rx, ry, orientation), cmds
|
||||
|
||||
if __name__ == "__main__":
|
||||
np.random.seed(2)
|
||||
|
||||
levels = {}
|
||||
|
||||
for i in range(100):
|
||||
diff, board, n_coins, robot_path, init_robot_pos, solution = generate_level(7, 4)
|
||||
if diff > 0:
|
||||
print("difficulty: ", diff, "n_coins: ", n_coins, "path length: ", len(robot_path))
|
||||
if diff in levels:
|
||||
if n_coins > levels[diff]['n_coins'] and len(robot_path) > levels[diff]['path_length']:
|
||||
levels[diff] = {'board': board, 'init_robot_pos': init_robot_pos, 'solution': solution,
|
||||
'n_coins': n_coins, 'path_length': len(robot_path)}
|
||||
else:
|
||||
levels[diff] = {'board': board, 'init_robot_pos': init_robot_pos, 'solution': solution,
|
||||
'n_coins': n_coins, 'path_length': len(robot_path)}
|
||||
|
||||
level_info = {}
|
||||
for l, data in levels.items():
|
||||
np.save(f'levels/{l}.npy', data['board'].tiles)
|
||||
sol = [(cmd.action, tuple(map(int, cmd.color))) for cmd in data['solution']]
|
||||
level_info[l] = {'init_robot_pos': data['init_robot_pos'], 'solution': sol,
|
||||
'n_coins': int(data['n_coins']), 'path_length': int(data['path_length']),
|
||||
'file': f'levels/{l}.npy'}
|
||||
|
||||
with open('levels/level_info.json', 'w') as f:
|
||||
json.dump(level_info, f, indent=4)
|
||||
pass
|
Loading…
Reference in New Issue
Block a user