+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/game.py b/game.py
index 0a2b99b..c2b131d 100644
--- a/game.py
+++ b/game.py
@@ -1,12 +1,38 @@
-#
-import sys
import traceback
from helper import print_scoresheets
-
from generala import get_random_dice, valid_play, play_value
+"""Library necessary to copy the list "scoresheets" to pass by value to the plugin"""
+from copy import deepcopy
+"""Libraries necessary for timing the plugin's response"""
+import signal
+"""Library for displaying the winner"""
+import operator
+"""Libraries for sandboxing"""
+from sandboxing import getPlay#for the sandboxing
+TIME_AVAILABLE = 1#time available to compute the plugin's response
+
+class Timeout():
+ """Timeout class using ALARM signal."""
+
+ class Timeout(Exception):
+ pass
+
+ def __init__(self, sec):
+ self.sec = sec
+
+ def __enter__(self):
+ signal.signal(signal.SIGALRM, self.raise_timeout)
+ signal.alarm(self.sec)
+
+ def __exit__(self, *args):
+ signal.alarm(0) # disable alarm
+
+ def raise_timeout(self, *args):
+ raise Timeout.Timeout()
-class Player():#segundo comentario de prueba
+
+class Player():#
def __init__(self, name):
self.name = name
@@ -31,18 +57,17 @@ class Game():
def __init__(self, nscoresheets):
self.nscoresheets = nscoresheets
self.nplayers = 0
- self.players_plugins = {}
- self.players = []
+ self.players_plugins = {} #the name of the file of the plugins
+ self.players = [] #the name() of the plugins
self.scoresheets = []
for i in range(nscoresheets):
self.scoresheets.append({})
- def add_player(self, player):
- name = player.name()
- self.players_plugins[name] = player
- self.players.append(name)
+ def add_player(self, namePlayer,plugin):
+ self.players_plugins[namePlayer] = plugin
+ self.players.append(namePlayer)
for i in range(self.nscoresheets):
- self.scoresheets[i][name] = {}
+ self.scoresheets[i][namePlayer] = {}
self.nplayers = self.nplayers + 1
def start(self):
@@ -61,38 +86,65 @@ def start(self):
def results(self):
print_scoresheets(self.scoresheets)
+ """calculating the winner"""
+ total = {}
+ for player in self.players:
+ total[player] = 0
+ for scoresheet in self.scoresheets:
+ for player in scoresheet:
+ for play, score in scoresheet[player].items():
+ total[player] += score
+ print "The winner is!:",max(total.iteritems(),key=operator.itemgetter(1))[0]
def turn(self, player):
- plugin = self.players_plugins[player]
- r = get_random_dice(5)
+ plugin = self.players_plugins[player]#name of the module
+ print "turn", plugin
+ r = get_random_dice(5)#obtain the dices as a list eg: [2,1,4,4,6]
nroll = 5
- for i in range(3):
+ for i in range(3):#ith opportunity of the current player
try:
- bonus = (nroll == 5)
- roll, decision, scoresheet = plugin.play(i, r, bonus, self.players, self.scoresheets)
- decision = decision.upper() if decision else None
- nroll = len(roll)
- if nroll > 0:
- r0 = get_random_dice(nroll)
- i = 0
- for new_r in roll:
- r[new_r] = r0[i]
- i = i+1
- else:
- if not valid_play(decision):
- raise Exception('Play [{0}] is invalid'.format(decision))
- scoresheet = self.scoresheets[scoresheet][player]
- if decision not in scoresheet:
- scoresheet[decision] = play_value(decision, r, bonus)
- else:
- raise Exception('Decision [{0}] is already taken'.format(decision))
- break
-
-
+ """It executes the corresponding turn for the plugin with TIME_AVAILABLE seconds to decide"""
+ with Timeout(TIME_AVAILABLE):
+ bonus = (nroll == 5)
+ """
+ The return parameters of the play function of the plugin should be:
+ roll: which dices should be re-rolled referencing the indexes of the r list
+ decision: the final decision of the turn as a string. The avalaible decisions are stated in helper.py
+ scorsheet: which scoresheet should the play be applied
+ """
+ copyScoresheets = deepcopy(self.scoresheets)#make a copy of the scoresheets because we want to send them by value not by reference for safety
+ """getPlay from the sandboxing.py with the parameters
+ plugin: name of the file's plugin eg: serial_dicer.py
+ i: ith opportunity to throw again the dice
+ r: the dices itself
+ bonus: if that throw contains a bonus
+ player: the current players playing the game
+ Scoresheets: the poins currently assigned
+ """
+ roll, decision, scoresheet = getPlay(plugin,i, r, bonus, self.players, copyScoresheets)
+ #roll, decision, scoresheet = plugin.play(i, r, bonus, self.players, copyScoresheets)<--reemplazado
+ decision = decision.upper() if decision else None
+ nroll = len(roll)#how many dices should be re-roll
+ if nroll > 0:#the player has decided re-roll again at least one dice
+ r0 = get_random_dice(nroll)#it obtains "nroll" new dices
+ i = 0
+ for new_r in roll:#it updates the new dices list
+ r[new_r] = r0[i]
+ i = i+1
+ else:#the player has decided that no dice shoul be re-rolled
+ if not valid_play(decision):#the player has not stated a valid play in the format stated in generala.py
+ raise Exception('Play [{0}] is invalid'.format(decision))
+ scoresheet = self.scoresheets[scoresheet][player]#retrieve the plays that player has already played in that scoresheet
+ if decision not in scoresheet:
+ #The player adds a new play in that scoresheet
+ scoresheet[decision] = play_value(decision, r, bonus)
+ else:
+ raise Exception('Decision [{0}] is already taken'.format(decision))
+ break
+ except Timeout.Timeout:#Times up for the ith opportunity
+ print "Plugin Timeout",plugin
+ break
except Exception as e:
print(traceback.format_exc())
print("Error inesperadamente inesperado: {0}".format(e))
# NOTIFY
-
-
-
diff --git a/game.pyc b/game.pyc
new file mode 100644
index 0000000..9a7dc9b
Binary files /dev/null and b/game.pyc differ
diff --git a/generai.py b/generai.py
index fe066ce..2fdcf90 100644
--- a/generai.py
+++ b/generai.py
@@ -1,13 +1,13 @@
+# coding=utf-8
from os import listdir
from os.path import isfile, join
from importlib import import_module
from game import Game
-
+from sandboxing import getName
# plugins
plugins = {}
-plugins_list = []
-
+plugins_list=[]
def load_plugins():
print("Loading plugins...")
plugin_files = [f for f in listdir('plugins') if isfile(join('plugins',
@@ -18,11 +18,13 @@ def load_plugins():
plugin_name = plugin_file[:-3]
print("Loading plugin {0}".format(plugin_name))
try:
- m = import_module('plugins.{0}'.format(plugin_name))
- plugins_loaded = plugins_loaded + 1
- name = m.name()
- plugins[name] = m
- plugins_list.append(m)
+ name = getName(plugin_file)
+ if(name is not None):
+ plugins_loaded = plugins_loaded + 1
+ plugins[name] = plugin_file
+ plugins_list.append(name)
+ else:
+ raise Exception(name)
except Exception as e:
print("Plugin {0} was not loaded {1}".format(plugin_name, e))
invalid_plugins = invalid_plugins + 1
@@ -33,7 +35,7 @@ def list_plugins(title=True):
print("---------------- PLUGINS -----------------")
i = 0
for plugin in plugins_list:
- print("{0}) {1}".format(i, plugin.name()))
+ print("{0}) {1}".format(i, plugin))
i = i + 1
print("\n")
@@ -41,12 +43,12 @@ def start_game():
print("---------------- GENERALA -----------------")
list_plugins(False)
- players_input = input("Ingrese los jugadores (separándolos con ,): ")
+ players_input = raw_input("Ingrese los jugadores (separándolos con ,): ")
players = [int(x.strip()) for x in players_input.split(",")]
- nscoresheets = int(input("Cuántas casillas? "))
+ nscoresheets = int(raw_input("Cuántas casillas? "))
game = Game(nscoresheets)
for player in players:
- game.add_player(plugins_list[player])
+ game.add_player(plugins_list[player],plugins[plugins_list[player]])
game.start()
game.results()
@@ -78,7 +80,7 @@ def menu():
def process_option(opt):
for option in options:
- if (isinstance(option["val"], list) and opt in option["val"]) or (opt == option["val"]):
+ if (isinstance(option["val"], list) and opt in option["val"]) or (str(opt) == option["val"]):
option["fn"]()
if __name__ == "__main__":
diff --git a/generala.pyc b/generala.pyc
new file mode 100644
index 0000000..cf0f020
Binary files /dev/null and b/generala.pyc differ
diff --git a/helper.pyc b/helper.pyc
new file mode 100644
index 0000000..5b55e32
Binary files /dev/null and b/helper.pyc differ
diff --git a/plugins/__init__.pyc b/plugins/__init__.pyc
new file mode 100644
index 0000000..adcc47c
Binary files /dev/null and b/plugins/__init__.pyc differ
diff --git a/plugins/console.py b/plugins/console.py
index f874508..17a102d 100644
--- a/plugins/console.py
+++ b/plugins/console.py
@@ -8,7 +8,7 @@ def name():
# this plugin uses console I/O to make plays
def roll_dice_eval(roll_dice):
- return [int(x) - 1 for x in roll_dice if x in string.digits]
+ return [int(x) - 1 for x in list(roll_dice)]
def play(roll_no, dice, bonus, players, scoresheets):
print_scoresheets(scoresheets)
@@ -18,6 +18,6 @@ def play(roll_no, dice, bonus, players, scoresheets):
if roll_dice:
return roll_dice_eval(roll_dice), None, None
else:
- decision = input("jugada? ")
- scoresheet = int(input("casilla {0}? ".format(str(list(range(len(scoresheets)))))))
+ decision = raw_input("jugada? ")
+ scoresheet = int(raw_input("casilla {0}? ".format(str(list(range(len(scoresheets)))))))
return ([], decision, scoresheet)
diff --git a/plugins/console.pyc b/plugins/console.pyc
new file mode 100644
index 0000000..29905a4
Binary files /dev/null and b/plugins/console.pyc differ
diff --git a/plugins/random_dicer.py b/plugins/random_dicer.py
index d34f3a3..c43335b 100644
--- a/plugins/random_dicer.py
+++ b/plugins/random_dicer.py
@@ -1,7 +1,7 @@
def name():
return "random_roshkero 1.0"
-def play(dice, servido, players, scoresheets):
+def play(turno, dice, servido, players, scoresheets):
print("MY TURN! -> {0} [{1}]".format(1, dice))
return (1, 2, 3)
diff --git a/plugins/random_dicer.pyc b/plugins/random_dicer.pyc
new file mode 100644
index 0000000..a175d46
Binary files /dev/null and b/plugins/random_dicer.pyc differ
diff --git a/plugins/se1.py b/plugins/se1.py
new file mode 100644
index 0000000..555da0a
--- /dev/null
+++ b/plugins/se1.py
@@ -0,0 +1,26 @@
+
+def name():
+ return "SERIAL 1"
+
+# this plugin will play serially to the next available free space
+# in its corresponding scoresheet
+def play(roll_no, dice, bonus, players, scoresheets):
+ # where
+ i = 0
+ for ss in scoresheets:
+ my_ss = ss[name()]
+ if '4' not in my_ss:
+ return [], '4', i
+ elif '5' not in my_ss:
+ return [], '5', i
+ elif '6' not in my_ss:
+ return [], '6', i
+ elif 'ESCALERA' not in my_ss:
+ return [], 'ESCALERA', i
+ elif 'FULLHOUSE' not in my_ss:
+ return [], 'FULLHOUSE', i
+ elif 'POKER' not in my_ss:
+ return [], 'POKER', i
+ elif 'GENERALA' not in my_ss:
+ return [], 'GENERALA', i
+ i = i + 1
\ No newline at end of file
diff --git a/plugins/se2.py b/plugins/se2.py
new file mode 100644
index 0000000..c62695c
--- /dev/null
+++ b/plugins/se2.py
@@ -0,0 +1,29 @@
+
+def name():
+ return "SERIAL 2"
+
+
+# this plugin will play serially to the next available free space
+# in its corresponding scoresheet
+
+def play(roll_no, dice, bonus, players, scoresheets):
+ # where
+
+ i = 0
+ for ss in scoresheets:
+ my_ss = ss[name()]
+ if '4' not in my_ss:
+ return [], '4', i
+ elif '5' not in my_ss:
+ return [], '5', i
+ elif '6' not in my_ss:
+ return [], '6', i
+ elif 'ESCALERA' not in my_ss:
+ return [], 'ESCALERA', i
+ elif 'FULLHOUSE' not in my_ss:
+ return [], 'FULLHOUSE', i
+ elif 'POKER' not in my_ss:
+ return [], 'POKER', i
+ elif 'GENERALA' not in my_ss:
+ return [], 'GENERALA', i
+ i = i + 1
diff --git a/plugins/serial_dicer.pyc b/plugins/serial_dicer.pyc
new file mode 100644
index 0000000..d7b7996
Binary files /dev/null and b/plugins/serial_dicer.pyc differ
diff --git a/plugins/while1.py b/plugins/while1.py
new file mode 100644
index 0000000..7e28158
--- /dev/null
+++ b/plugins/while1.py
@@ -0,0 +1,10 @@
+
+def name():
+ return "while1"
+
+# this plugin will play serially to the next available free space
+# in its corresponding scoresheet
+def play(roll_no, dice, bonus, players, scoresheets):
+ # where
+ while(1):
+ pass
\ No newline at end of file
diff --git a/sandbox.py b/sandbox.py
new file mode 100644
index 0000000..3206d02
--- /dev/null
+++ b/sandbox.py
@@ -0,0 +1,62 @@
+
+from RestrictedPython import compile_restricted #for compiling the code safely
+from RestrictedPython.Guards import safe_builtins#the builtins that are safe
+from RestrictedPython.Guards import full_write_guard#never lets restricted code modify (assign, delete an attribute or item) it shouldn't to
+import sys#for manipulating the parameters recieved
+import ast
+"""preparing the safe_builtins"""
+safe_builtins["_getiter_"]= list
+safe_builtins["type"]= __builtins__.type
+safe_builtins["_getattr_"]= getattr
+safe_builtins["_write_"]= full_write_guard
+
+SliceType = type(slice(0))
+DisallowedObject = []
+
+class AccessDenied (Exception):
+ pass
+
+def guarded_getitem(ob, index):
+ if type(index) is SliceType and index.step is None:
+ start = index.start
+ stop = index.stop
+ if start is None:
+ start = 0
+ if stop is None:
+ v = ob[start:]
+ else:
+ v = ob[start:stop]
+ else:
+ v = ob[index]
+ if v is DisallowedObject:
+ raise AccessDenied
+ return v
+
+safe_builtins["_getitem_"]= guarded_getitem
+
+
+restricted_globals = dict(__builtins__ = safe_builtins)#
+"""open the plugin for retrieving the code as a string"""
+with open(sys.argv[1], 'r') as plugin:
+ data=plugin.read()
+loc = {}#the locals for the sandboxed environment
+"""compling the code with the restricted funcionalities such as import, using names starting with underscore _, etc"""
+byte_code = compile_restricted(data, sys.argv[1], 'exec')
+"""executing the byte code with the restricted globals"""
+exec(byte_code, restricted_globals, loc)
+"""updating the globals"""
+restricted_globals.update(loc)
+for nombre, value in restricted_globals.items():
+ globals()[nombre] = value
+"""executes the function in sanbox.py environment, by this point the code should be safe"""
+if (sys.argv[2]=="name"):
+ print restricted_globals[sys.argv[2]]()
+else:
+ """parsing the parameters"""
+ roll_no = ast.literal_eval(sys.argv[3])
+ dice = ast.literal_eval(sys.argv[4])
+ bonus = ast.literal_eval(sys.argv[5])
+ players =ast.literal_eval(sys.argv[6])
+ scoresheets = ast.literal_eval(sys.argv[7])
+ """executing the play"""
+ print restricted_globals["play"](roll_no,dice,bonus,players,scoresheets)
\ No newline at end of file
diff --git a/sandboxing.py b/sandboxing.py
new file mode 100644
index 0000000..ad1f47b
--- /dev/null
+++ b/sandboxing.py
@@ -0,0 +1,32 @@
+import subprocess #for calling a new process in a sandboxed environment
+import ast#for parsing the sandboxed plugin response
+
+
+"""In every function we passed the sanboxed environment:
+1) the name of the file's plugin(SE ENTIENDE? el nombre de los archivos de los plugins, no el name() del plugin EJ: serial_dicer.py)
+2) The function it should be executing --> name() or play(). In the case of play we send the corresponding values needed
+"""
+def getName(plugin):
+ modulo = "plugins/" + plugin
+ try:
+ output = (subprocess.check_output(["python","sandbox.py",modulo,"name"], stderr=subprocess.STDOUT)).strip("\n")
+ return output
+ except subprocess.CalledProcessError as e:
+ print "Ocurrio un error en el sandboxing"
+ print "El error es el sgte:\n", e.output
+
+def getPlay(plugin,roll_no,dice,bonus,players,scoresheets):
+ modulo = "plugins/" + plugin
+ try:
+ output = (subprocess.check_output(["python","sandbox.py",modulo,"play",str(roll_no),str(dice),str(bonus),str(players),str(scoresheets)], stderr=subprocess.STDOUT)).strip("\n")
+ #parsing the output
+ variable = output[1:-1]
+ variable = variable.replace(" ", "")
+ nueva = variable.split(",")
+ roll=ast.literal_eval(nueva[0])
+ decision=ast.literal_eval(nueva[1])
+ scoresheet=ast.literal_eval(nueva[2])
+ return list(roll), str(decision), int(scoresheet)
+ except subprocess.CalledProcessError as e:
+ print "Ocurrio un error en el sandboxing"
+ print "El error es el sgte:\n", e.output
diff --git a/sandboxing.pyc b/sandboxing.pyc
new file mode 100644
index 0000000..d4667c7
Binary files /dev/null and b/sandboxing.pyc differ