Prepare for refresh

This commit is contained in:
Thomas Forgione 2019-03-28 10:56:22 +01:00
parent d4d13edc1a
commit 36d26f5004
No known key found for this signature in database
GPG Key ID: 203DAEA747F48F41
7 changed files with 203 additions and 89 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ assets/
node_modules node_modules
package.lock package.lock
*.pyc *.pyc
config.js

2
pytron

@ -1 +1 @@
Subproject commit b2504f49f9e30e3ffa07ec3ab11d6b465829b593 Subproject commit 8d27a9293e2ffbb1119b9c3c453aec76be612a50

View File

@ -1,4 +1,34 @@
from os.path import dirname, basename, isfile from os.path import dirname, basename, isfile, getmtime
import glob from importlib import import_module
modules = glob.glob(dirname(__file__)+"/*/ai.py") from glob import glob
__all__ = ['.'.join(f.split('.')[:-1]) for f in modules if isfile(f)]
modules = glob(dirname(__file__)+"/*/ai.py")
__all__ = []
class UploadedAi:
def __init__(self, name, module, constructor, date):
self.name = name
self.module = module
self.constructor = constructor
self.date = date
for path in [f for f in modules if isfile(f)]:
# Remove the .py
toto = '.'.join(path.split('.')[:-1])
# Compute the name
name = toto.split('/')[-2]
# Find the module
module = import_module('.'.join(toto.split('/')[-3:]))
# Find the constructor
constructor = getattr(module, 'Ai')
# Moment when the file was last modified
date = getmtime(path)
# Append to the list of uploaded ais
__all__.append(UploadedAi(name, module, constructor, date))
__all__ = sorted(__all__, key = lambda ai: ai.name)

77
pytron_run/refresh.py Executable file
View File

@ -0,0 +1,77 @@
#!/usr/bin/env python3
import os
import pathlib
import sys
import json
sys.path.append('../pytron')
from tron.map import Map
from tron.game import Game, PositionPlayer
from tron.player import Direction, ConstantPlayer
import ai_manager
from utils import run_battle
ASSETS_PATH = "assets/data.json"
LAST_REFRESH_PATH = "assets/refresh.dat"
width = 10
height = 10
def main():
print('Welcome to pytron refresh!')
sys.stdout.flush()
# Read the last moment when this script was run
last_refresh = os.path.getmtime(LAST_REFRESH_PATH)
# Set last update time
pathlib.Path(LAST_REFRESH_PATH).touch()
# Find the ais that need to be refreshed
ais_to_refresh = [ai for ai in ai_manager.__all__ if ai.date > last_refresh]
print('New ais: ', list(map(lambda x: x.name, ais_to_refresh)))
print('Ais: ', list(map(lambda x: x.name, ai_manager.__all__)))
# Read current state
with open(ASSETS_PATH, 'r') as file:
dictionnary = json.loads(file.read())
# Dictionnary to record battles that already occured
battles_done = {}
for ai1 in ais_to_refresh:
for ai2 in ai_manager.__all__:
if ai1.name == ai2.name:
continue
# Sort ais by name just to be sure
if ai1.name > ai2.name:
(sai2, sai1) = (ai1, ai2)
else:
(sai1, sai2) = (ai1, ai2)
slash_name = sai1.name + "/" + sai2.name
# Record battle to be done, skip if already done
if battles_done.get(slash_name, None) is None:
battles_done[slash_name] = True
else:
continue
print("Battling {} vs {}".format(sai1.name, sai2.name))
sys.stdout.flush()
(score1, score2, nulls) = run_battle(sai1, sai2, width, height)
dictionnary[slash_name] = [score1, score2, nulls]
with open(ASSETS_PATH, "w") as f:
f.write(json.dumps(dictionnary))
print('Pytron run has finished')
if __name__ == '__main__':
main()

View File

@ -2,82 +2,43 @@
import sys import sys
import json import json
import pathlib
sys.path.append('../pytron') sys.path.append('../pytron')
from tron.map import Map from tron.map import Map
from tron.game import Game, PositionPlayer from tron.game import Game, PositionPlayer
from tron.player import Direction, ConstantPlayer from tron.player import Direction, ConstantPlayer
from importlib import import_module
import positions
import ai_manager import ai_manager
from utils import run_battle
# Find all the AIs ASSETS_PATH = "assets/data.json"
class AiClass: LAST_REFRESH_PATH = "assets/refresh.dat"
def __init__(self, name, builder):
self.name = name
self.builder = builder
ais = []
for real_ai in ai_manager.__all__:
ai_name = real_ai.split('/')[-2]
ai_module = import_module('.'.join(real_ai.split('/')[-3:]))
ai_class = getattr(ai_module, "Ai")
ais.append(AiClass(ai_name, ai_class))
# This script shows how to create a game with AI, that will run automatically.
# It is made to be fast and not to be used by humans. It especially doesn't
# display and window and doesn't listen to any keystrokes.
width = 10 width = 10
height = 10 height = 10
def run_battle(ai1, ai2):
games = 50
ai1_victories = 0
ai2_victories = 0
for (initial_position_one, initial_position_two) in positions.positions():
game = Game(width, height, [
PositionPlayer(1, ai1.builder(), initial_position_one),
PositionPlayer(2, ai2.builder(), initial_position_two),
])
game.main_loop()
if game.winner == 1:
ai1_victories += 1
elif game.winner == 2:
ai2_victories += 1
# Inverse positions and replay to be symmetrical
game = Game(width, height, [
PositionPlayer(1, ai2.builder(), initial_position_one),
PositionPlayer(2, ai1.builder(), initial_position_two),
])
game.main_loop()
if game.winner == 1:
ai2_victories += 1
elif game.winner == 2:
ai1_victories += 1
return (ai1_victories, ai2_victories, 2 * games - ai1_victories - ai2_victories)
def main(): def main():
print('Welcome to pytron run!') print('Welcome to pytron run!')
dictionnary = {"ais": list(map(lambda x: x.name, ais)), "battles": {}} dictionnary = {}
for (id1, ai1) in enumerate(ais): # Set last update time
for (id2, ai2) in enumerate(ais): pathlib.Path(LAST_REFRESH_PATH).touch()
for (id1, ai1) in enumerate(ai_manager.__all__):
for (id2, ai2) in enumerate(ai_manager.__all__):
if id1 >= id2: if id1 >= id2:
continue continue
print("Battling {} vs {}".format(ai1.name, ai2.name)) # Sort ais by name just to be sure
(score1, score2, nulls) = run_battle(ai1, ai2) if ai1.name > ai2.name:
dictionnary["battles"][ai1.name + "/" + ai2.name] = [score1, score2, nulls] (sai2, sai1) = (ai1, ai2)
else:
(sai1, sai2) = (ai1, ai2)
print("Battling {} vs {}".format(sai1.name, sai2.name))
(score1, score2, nulls) = run_battle(sai1, sai2, width, height)
dictionnary[sai1.name + "/" + sai2.name] = [score1, score2, nulls]
with open("assets/data.json", "w") as f: with open("assets/data.json", "w") as f:
f.write(json.dumps(dictionnary)) f.write(json.dumps(dictionnary))

34
pytron_run/utils.py Normal file
View File

@ -0,0 +1,34 @@
from positions import positions
from tron.game import Game, PositionPlayer
def run_battle(ai1, ai2, width, height):
games = 50
ai1_victories = 0
ai2_victories = 0
for (initial_position_one, initial_position_two) in positions():
game = Game(width, height, [
PositionPlayer(1, ai1.constructor(), initial_position_one),
PositionPlayer(2, ai2.constructor(), initial_position_two),
])
game.main_loop()
if game.winner == 1:
ai1_victories += 1
elif game.winner == 2:
ai2_victories += 1
# Inverse positions and replay to be symmetrical
game = Game(width, height, [
PositionPlayer(1, ai2.constructor(), initial_position_one),
PositionPlayer(2, ai1.constructor(), initial_position_two),
])
game.main_loop()
if game.winner == 1:
ai2_victories += 1
elif game.winner == 2:
ai1_victories += 1
return (ai1_victories, ai2_victories, 2 * games - ai1_victories - ai2_victories)

View File

@ -9,13 +9,7 @@ const pug = require('pug');
const unzip = require('unzip'); const unzip = require('unzip');
const touch = require('touch'); const touch = require('touch');
const bcrypt = require('bcryptjs'); const bcrypt = require('bcryptjs');
const { port, pythonPath, aisPath, aisPathOld, hashPath } = require('./config');
// Consts
const port = 8000;
const pythonPath = '/home/pytron/miniconda3/envs/pytron/bin/python'
const aisPath = 'pytron_run/ai_manager/'
const aisPathOld = 'pytron_run/ai_manager_old'
const hashPath = "__bcrypt__hash.txt"
// Create the directories to store the files // Create the directories to store the files
try { fs.mkdirSync(aisPath); } catch { } try { fs.mkdirSync(aisPath); } catch { }
@ -34,7 +28,7 @@ function runPython() {
} }
process.stdout.write('\n'); process.stdout.write('\n');
let p = spawn(pythonPath, ['run.py'], {cwd: 'pytron_run'}); let p = spawn(pythonPath, ['refresh.py'], {cwd: 'pytron_run'});
p.stdout.on('data', (data) => { p.stdout.on('data', (data) => {
let content = data.toString().split('\n'); let content = data.toString().split('\n');
for (let line of content) { for (let line of content) {
@ -62,35 +56,52 @@ function runPython() {
} }
}); });
} }
// parsed.ais.push({
// });
function parse(data) { function parse(data) {
let content = JSON.parse(data); let content = JSON.parse(data);
let parsed = {ais: [], battles: {}}; let parsed = {ais: [], battles: {}};
for (let ai of content.ais) {
parsed.ais.push({
name: ai,
victories: 0,
defeats: 0,
nulls: 0,
score: 0,
});
}
for (let key in content.battles) { for (let key in content) {
let battlers = key.split('/'); let battlers = key.split('/');
let ai1 = battlers[0]; let ai1 = battlers[0];
let ai2 = battlers[1]; let ai2 = battlers[1];
parsed.battles[ai1 + '/' + ai2] = content.battles[key][0]; parsed.battles[ai1 + '/' + ai2] = content[key][0];
parsed.battles[ai2 + '/' + ai1] = content.battles[key][1]; parsed.battles[ai2 + '/' + ai1] = content[key][1];
let realAi1 = parsed.ais.find((x) => x.name == ai1); let realAi1 = parsed.ais.find((x) => x.name == ai1);
if (realAi1 === undefined) {
realAi1 = {
name: ai1,
victories: 0,
defeats: 0,
nulls: 0,
score: 0,
};
parsed.ais.push(realAi1);
}
let realAi2 = parsed.ais.find((x) => x.name == ai2); let realAi2 = parsed.ais.find((x) => x.name == ai2);
realAi1.victories += content.battles[key][0];
realAi1.defeats += content.battles[key][1]; if (realAi2 === undefined) {
realAi2.victories += content.battles[key][1]; realAi2 = {
realAi2.defeats += content.battles[key][0]; name: ai2,
realAi1.nulls += content.battles[key][2]; victories: 0,
realAi2.nulls += content.battles[key][2]; defeats: 0,
nulls: 0,
score: 0,
};
parsed.ais.push(realAi2);
}
realAi1.victories += content[key][0];
realAi1.defeats += content[key][1];
realAi2.victories += content[key][1];
realAi2.defeats += content[key][0];
realAi1.nulls += content[key][2];
realAi2.nulls += content[key][2];
} }
parsed.sortedAis = parsed.ais.slice(0); parsed.sortedAis = parsed.ais.slice(0);