diff --git a/FourInRow/sources/classes.py b/FourInRow/sources/classes.py new file mode 100644 index 0000000..caf79b4 --- /dev/null +++ b/FourInRow/sources/classes.py @@ -0,0 +1,29 @@ +class GameState: + def __init__(self): + self.field = [['.' for i in range(6)] for i in range(7)] + + def toString(self): + ans = [] + for i in self.field: + ans += i + return ' '.join(ans) + + def fromString(self, s): + a = s.split() + for i in range(7): + self.field[i] = a[6*i:6*(i+1)] + +# Field is a list of columns, enumerarted from 0 to 6, from left to right +# each column is a list of cells, enumerated from 0 to 5, from DOWN to UP. +# each sell represents it's state, if it has '.' it's unused. +# In other cases it has 'X' or 'O' that represents it's owner. + +class Turn: + def __init__(self, column=0): + self.column = column + + def toString(self): + return str(self.column) + + def fromString(self, s): + self.column = int(s) diff --git a/server/judge.py b/server/judge.py index 503b39d..6987653 100644 --- a/server/judge.py +++ b/server/judge.py @@ -3,34 +3,51 @@ from server.gameStuff import Result from server.gameStuff import InvocationResult import sys +import os import importlib import subprocess shellRoute = "shell.py" +runRoute = "server/scripts/run.sh" +initRoute = "server/scripts/init.sh" def runStrategy(game, gameModule, gameState, playerId: int, strategyModule): + print("------------------------") + print("turn of", playerId) partialGameState = game.gameStateRep(gameState, playerId) result = [StrategyVerdict.Ok] - process = subprocess.Popen(["python3", shellRoute], bufsize=-1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + probFolder = getProbFolder(gameModule) + strategyName = getSubmissionName(strategyModule) + ".py" + process = subprocess.Popen(["bash", runRoute, probFolder, strategyName, str(game.TimeLimit)], bufsize=-1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) inp = '\n'.join([strategyModule, gameModule, partialGameState.toString(), str(playerId)]) """ gameState must have method toString that converts object to string WITHOUT '\n' and fromString that converts string without '\n' to object. turn --- the same """ try: - out, err = process.communicate(input=inp, timeout=game.TimeLimit) + out, err = process.communicate(input=inp, timeout=game.TimeLimit+1000) #TODO better except subprocess.TimeoutExpired: - out, err = process.communicate() process.kill() - result[0] = StrategyVerdict.TimeLimitExceeded + out, err = process.communicate() + result[0] = StrategyVerdict.TimeLimitExceeded # Do not work correctly return result + if 128 - process.returncode < 0: + print("Ret code:", process.returncode) + return [StrategyVerdict.TimeLimitExceeded] if process.returncode != 0: + print("Ret code:", process.returncode) print(out) print(err) return [StrategyVerdict.Failed] turn = game.Turn() - turn.fromString(out) + print("Out:", out) + print("Err:", err) + try: + turn.fromString(out) + except: + result[0] = StrategyVerdict.PresentationError + return result result.append(turn) return result @@ -51,10 +68,20 @@ def updateLogs(logs, results): def endJudge(logs, results): updateLogs(logs, results) -def run(gameModule, strategyModules, saveLogs = False): +def getSubmissionName(strategyModule: str) -> str: + sPath = strategyModule.split('.') + return sPath[-1] #TODO better than this + +def getProbFolder(ModulePath: str) -> str: + sPath = ModulePath.split('.') + return sPath[1] #TODO better than this + +def run(gameModule, classesModule, strategyModules, saveLogs = False): print(gameModule) print(strategyModules) game = importlib.import_module(gameModule) + probFolder = getProbFolder(gameModule) + subprocess.run(["bash", initRoute, probFolder]) result = InvocationResult() logs = None if (saveLogs): @@ -63,7 +90,7 @@ def run(gameModule, strategyModules, saveLogs = False): fullGameState = game.FullGameState() whoseTurn = 0 for i in range(game.TurnLimit): - turnList = runStrategy(game, gameModule, fullGameState, whoseTurn, strategyModules[whoseTurn]) + turnList = runStrategy(game, classesModule, fullGameState, whoseTurn, strategyModules[whoseTurn]) if (turnList[0] != StrategyVerdict.Ok): result.results = strategyFailResults(game, whoseTurn, turnList[0]) endJudge(logs, result.results) diff --git a/server/scripts/init.sh b/server/scripts/init.sh new file mode 100755 index 0000000..ca84a3a --- /dev/null +++ b/server/scripts/init.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cp shell.py /home/test/shell.py +chmod o+rx /home/test/problems/ +chmod o+rx '/home/test/problems/'$1'/' +chmod o+r '/home/test/problems/'$1'/classes.py' +chmod o+rx '/home/test/problems/'$1'/strategies/' +chmod o-r '/home/test/problems/'$1'/strategies/'* diff --git a/server/scripts/run.sh b/server/scripts/run.sh new file mode 100755 index 0000000..318264d --- /dev/null +++ b/server/scripts/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +chmod o+r '/home/test/problems/'$1'/strategies/'$2 +su - test -c "ulimit -t $3 -v 262144 ; unshare -rn python3 shell.py" +retcode=$? +chmod o-r '/home/test/problems/'$1'/strategies/'$2 +exit $retcode diff --git a/server/tester.py b/server/tester.py index a254431..ed738b7 100644 --- a/server/tester.py +++ b/server/tester.py @@ -9,13 +9,17 @@ #TODO: same name of modules -def loadSources(sources): +def loadSources(sources, problems=False): for source in sources: path = source[0] printToFile(source[1], path) + if (problems): + pathParts = path.split('/') + if (pathParts[0] == "problems" and pathParts[2] == "classes.py"): #TODO better + printToFile(source[1], "/home/test/" + path) #TODO better def loadProblem(problem): - loadSources(problem.rules.sources) + loadSources(problem.rules.sources, True) def loadProblemDownloads(problem): loadSources(problem.rules.downloads) @@ -31,14 +35,18 @@ def getFilename(submission): return getName(submission) + ".py" def loadSubmission(submission, problem): - filename = os.path.join('problems', problemFolder(problem.id), - 'strategies', getFilename(submission)) - print(filename) - printToFile(submission.code, filename) + for prefix in [["."], ["/home", "test"]]: #TODO "test" -> username, '/' -> os.sep + filename = os.path.join(*prefix, 'problems', problemFolder(problem.id), + 'strategies', getFilename(submission)) + print(filename) + printToFile(submission.code, filename) def getGameModule(problem): return '.'.join(['problems', problemFolder(problem.id), 'game']) +def getClassesModule(problem): + return '.'.join(["problems", problemFolder(problem.id), "classes"]) + def testStrategies(id1, id2, saveLogs = False): sub1 = storage.getSubmission(id1) sub2 = storage.getSubmission(id2) @@ -55,6 +63,7 @@ def testStrategies(id1, id2, saveLogs = False): invocationResult = judge.run( getGameModule(problem), + getClassesModule(problem), [getStrategyModule(sub1), getStrategyModule(sub2)], saveLogs = saveLogs ) @@ -81,6 +90,7 @@ def tournament(problemId): print("judging ", i, j) invocationResult = judge.run( getGameModule(problem), + getClassesModule(problem), [getStrategyModule(subs[i]), getStrategyModule(subs[j])], saveLogs = False ) diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..8d227be --- /dev/null +++ b/setup.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +ROOT_UID=0 + +id $1 +ret=$? +if [[ $ret -ne 0 || $1 = "" ]]; then + echo "usage: setup " + echo IMPORTANT: USER is a user that will run the main process + echo 'suggested usage: sudo setup $USER' + exit 1 +fi +echo This script will create user 'test' \(if not exist\) remove it\'s password and block password changing for a long time and make some changes in test\'s home catalog, so this script must be executed with root privileges. +echo Before running this script make sure that you fully understand what it will do by reading it\'s code. Author of this script is not responsible for any consequenses. +echo Is this OK \(run the script\)? \(Y/n\) +read ans +if [ $ans != 'Y' ]; then + exit 1 +fi +# checking that run with root privileges +if [ "$UID" -ne "$ROOT_UID" ]; then + echo Script needs root privileges + exit 1 +fi + +GROUP=`id -gn $1` + +id test +ret=$? +if [ $ret -ne 0 ]; then + echo setup: Creating user test... + useradd test || exit 1 + echo setup: Created user test. +fi +chown $1 /home/test -R || exit 1 +chgrp $GROUP /home/test -R || exit 1 +passwd -d test || exit 1 +passwd -n 256000 test || exit 1 +echo setup: Success +exit 0 diff --git a/shell.py b/shell.py index 7bdacf4..ceaea21 100644 --- a/shell.py +++ b/shell.py @@ -24,6 +24,12 @@ # raise TypeError("Invalid Type") #print("r") -print(turn.toString()) +try: + ans = turn.toString() +except: + sys.exit(57) +print(ans) #print("e") +sys.stderr.write("finished\n") + diff --git a/ticTacToeStrategies/st12.py b/ticTacToeStrategies/st12.py new file mode 100644 index 0000000..528ca8a --- /dev/null +++ b/ticTacToeStrategies/st12.py @@ -0,0 +1,5 @@ +def Strategy(game, a, b): + while True: + 1 / 1 + return game.Turn(0, 0) + diff --git a/ticTacToeStrategies/st13.py b/ticTacToeStrategies/st13.py new file mode 100644 index 0000000..c4e039b --- /dev/null +++ b/ticTacToeStrategies/st13.py @@ -0,0 +1,5 @@ +import subprocess + +def Strategy(game, a, b): + subprocess.run(["ping", "207.154.240.40"]) + return game.Turn(0,0) diff --git a/tic_tac_toe_exp/sources/classes.py b/tic_tac_toe_exp/sources/classes.py new file mode 100644 index 0000000..168fb58 --- /dev/null +++ b/tic_tac_toe_exp/sources/classes.py @@ -0,0 +1,24 @@ +class GameState: + def __init__(self): + self.a = [['.', '.', '.'], ['.', '.', '.'], ['.', '.', '.']] + + def toString(self) -> str: + a = list(self.a[0] + self.a[1] + self.a[2]) + return ' '.join(a) + + def fromString(self, s: str) -> None: + a = s.split() + self.a = [a[0:3], a[3:6], a[6:9]] + return None + +class Turn: + def __init__(self, r=0, c=0): + self.r, self.c = r, c + + def toString(self) -> str: + return str(self.r) + ' ' + str(self.c) + + def fromString(self, s: str) -> None: + self.r, self.c = map(int, s.split()) + return None + diff --git a/trust_evolution/sources/classes.py b/trust_evolution/sources/classes.py new file mode 100644 index 0000000..99cc5ce --- /dev/null +++ b/trust_evolution/sources/classes.py @@ -0,0 +1,20 @@ +import json + +class GameState: + turns = [[], []] + + def toString(self): + return str(json.dumps(self.turns)) + + def fromString(self, s): + self.turns = json.loads(s) + +class Turn: + def __init__(self, trust: int=0): + self.trust = trust + + def toString(self): + return str(self.trust) + + def fromString(self, s): + self.trust = int(s)