"""
############################################################
Memit - All
############################################################
:Author: *Carlo E. T. Oliveira*
:Contact: carlo@nce.ufrj.br
:Date: $Date: 2013/03/17 $
:Status: This is a "work in progress"
:Revision: $Revision: 0.1 $
:Home: `Labase <http://labase.selfip.org/>`__
:Copyright: 2011, `GPL <http://is.gd/3Udt>`__.
Serious Game in cavalier projection for memetics.
__author__ = "Carlo E. T. Oliveira (carlo@nce.ufrj.br) $Author: carlo $"
__version__ = "0.2 $Revision$"[10:-1]
__date__ = "2013/03/17 $Date$"
"""
REPO = '/studio/%s'
def _logger(*a):
print(a)
if not '__package__' in dir():
log ('if not __package__')
import svg
from html import TEXTAREA
#from time import setinterval
import time
logger = log
pass
else:
logger = _logger
setinterval = lambda a,b:None
pass
"""
def noop(nop=''):
pass
HANDLER = {"_NOOP_":'noop()'}
VKHANDLER = dict([(k,noop) for k in range(32,40)])
def uuid():
r = jsptrand()
return '%i'%(JSObject(jsptdate).getTime()*1000+r)
def jshandler(event):
code = event.keyCode
if code in VKHANDLER:
VKHANDLER[code]()
#alert(event.keyCode)
if not '__package__' in dir():
doc.onkeypress=jshandler
def eventify(owner):
#alert('owner :'+owner)
HANDLER[owner]()
"""
TRANS = "translate rotate scale skewX skewY matrix".split()
EVENT = ("onfocusin onfocusout onactivate onload onclick onkeydown onkeyup" + \
" onmousedown onmouseup onmouseover onmousemove onmouseout").split()
[docs]class Dialog:
""" Floating panel holding an editable text area. :ref:`dialog`
"""
def __init__(self, gui, img = REPO%'paje.png', text = '', act = lambda x:None):
self._rect=gui.rect(0,100, 800, 440, style= {
'fillOpacity':'0.7', 'fill':'black'})
self._area=gui.textarea(text,80,130, 700, 400)
self._imag=gui.image(img,2,80, 32, 32)
self._imag.addEventListener('click', self.action)
self.act= act
[docs] def hide(self):
self._rect.style.visibility = 'hidden'
self._area.style.visibility = 'hidden'
self._imag.style.visibility = 'hidden'
#self._area.setVisible(self._area,False)
[docs] def show(self):
self._rect.style.visibility = 'visible'
self._area.style.visibility = 'visible'
self._imag.style.visibility = 'visible'
#self._area.setVisible(self._area,True)
[docs] def get_text(self):
return self._area.value
[docs] def set_text(self, text):
self._area.value = text
[docs] def action(self, event):
self.hide()
self.act(self)
[docs]class GUI:
""" Factory creating SVG elements, unpacking extra arguments. :ref:`gui`
"""
def __init__(self,panel,data):
global SVG
SVG = svg
logger('GUI __init__')
self.args = {}
self.panel = self._panel = panel
self.data = data
for child in panel: # iteration on child nodes
panel.remove(child)
[docs] def get_args(self):
args = self.args
for key, value in self.args.items():
args[key]= 'eventify(\\"%s\\")'%value
self.args = {}
p='"'
if len(args) != 0:
args = ', '+','.join(['%s = %s%s%s'%(k,p,v,p)
for k, v in args.items()])
else:
args = ''
return args
def _get_kwargs(self,kw):
trans =' '.join(
[key + ['(%s)','%s'][isinstance(value, tuple)]%str(value)
for key, value in kw.items() if key in TRANS])
return trans and ', transform="%s"'%trans or ''
[docs] def request(self, url = '/rest/studio/jeppeto?type=2', action = None, data=''):
req = ajax()
req.on_complete = action
req.set_timeout(8,self._err_msg)
req.open('GET',url,True)
req.set_header("Content-Type","text/plain; charset=utf-8")
req.send()
pass
def _err_msg(self, url = None, data = '', action = None, error = None):
pass
[docs] def textarea(self,text,x,y,w,h,style= {}):
def dpx(d):
return '%spx'%d
attrs = dict (position = 'absolute', top=dpx(y), left=dpx(x) ,
width=dpx(w) , height=dpx(h), color = 'navajowhite', border= 1,
resize = 'none', background = 'transparent')
attrs['top']= y
attrs = {'position' : 'absolute', 'top':dpx(y), 'left':dpx(x),
'width':dpx(w) , 'height':dpx(h), 'resize' : 'none','borderColor': 'darkslategrey',
'color': 'navajowhite', 'border': 1, 'background' : 'transparent' }
#t = TEXTAREA(text, style = {'position' : 'absolute', 'top':'100px', 'left':'40px'})#attrs)
t = TEXTAREA(text, style = attrs)
#d_rect=gui.rect(10,100, 540, 240, style= {'fill-opacity':'0.2', 'fill':'black'})
self.data <= t
return t
[docs] def dialog(self, text, img = REPO%'paje.png', act = lambda x:None):
t = Dialog(self,text=text, img=img, act=act)
#t.setStyleAttribute('border',0)
return t
[docs] def set(self, element):
self.panel = element
[docs] def up(self, element):
self.panel <= element
[docs] def cling(self,level, element):
level <= element
[docs] def clear(self):
self.panel = self._panel
[docs] def remove(self, element):
self.panel.removeChild(element)
[docs] def text(self, text,x=150,y=25, font_size=22,text_anchor="middle",
style= {}):
element = SVG.text(text,x=x,y=y,
font_size=font_size,text_anchor=text_anchor,
style=style)
self.panel <= element
return element
[docs] def group(self, group= None, layer=0):
element = group or SVG.g()
self.panel <= element
layer and self.set(element) or self.clear()
return element
[docs] def path(self, d,style={}, onMouseOver="noop", onMouseOut="noop"):
exec('element = SVG.path(d=%s,style=%s%s)'%(
str(d),str(style),self.get_args()))
self.panel <= element
return element
[docs] def image(self, href, x=0, y=0, width=100, height=50, **kw):
exec('element = SVG.image(href="%s", x=%i, y=%i, width=%i, height=%i%s)'%(
href, x, y, width, height,self._get_kwargs(kw)))
self.panel <= element
return element
[docs] def ellipse(self, href, cx=0, cy=0, rx=100, ry=50, style= {}, **kw):
exec('element = SVG.ellipse(cx=%i, cy=%i, rx=%i, ry=%i,style=%s%s)'%(
cx, cy, rx, ry,str(style),self.get_args()))
self.panel <= element
return element
[docs] def rect(self, x=0, y=0, width=100, height=50,style={}):
exec('element = SVG.rect(x=%i, y=%i, width=%i, height=%i,style=%s%s)'%(
x, y, width, height,str(style),self.get_args()))
self.panel <= element
return element
[docs] def handler(self, key, handle):
VKHANDLER[key] = handle
[docs] def avatar(self):
return Avatar(self)
def _decorate(self, handler, **kw):
self.args = {} #kw #dict(kw)
#alert(' '.join([k for k,v in kw.items()]))
for key, value in kw.items():
handler_id = uuid()
HANDLER[handler_id] = handler
self.args[key] = handler_id
#alert(key+':'+ self.args[key])
x =self.args
#alert(' ,'.join([k+':'+v for k,v in x.items()]))
return self
[docs] def click(self,handler):
self._decorate(handler, onClick=handler)
return self
[docs] def over(self,handler):
self._decorate(handler, onMouseOver=handler)
return
[docs]class Marker:
""" Colored shadow on the walls helping the user to deploy a piece in 3D. :ref:`marker`
"""
def __init__(self,gui, x, y, fill, face):
cls='red green blue'.split()
self.face = face
k, j, i = face
OA, OB, OC = 345, 172, 125
#skew
self.avatar = gui.ellipse(cx= x+35, cy = y+35, rx=35, ry=35,
style=dict(fill=fill, fillOpacity= 0.5))
self._off = (k * j * OA + k * i * OB + j * i * OC ,
k * j * OA+ k * i * OC + j * i * OB)
self.hide()
[docs] def show(self, x, y):
self.avatar.setAttribute("visibility",'hidden')
self.avatar.setAttribute('cx', x)
self.avatar.setAttribute('cy', y)
self.avatar.setAttribute("visibility",'visible')
[docs] def hide(self):
self.avatar.setAttribute("visibility",'hidden')
[docs] def on_over(self, ev, i, j, k):
OFFX, OFFY = self._off
#x, y, z = [c*f for c,f in zip(self.face,[i,j,k])]
f= self.face
x, y, z = k * f[0], j * f[1], i * f[2]
ax = OFFX+x*100+71*z
ay = OFFY+y*100+71*z
#logger('face %s ijk %s xyz %s ax %d ay %d'%(self.face,(i,j,k),(x,y,z),ax,ay))
self.show(ax, ay)
[docs]class Piece(Marker):
""" Represents the user choice when deployed insde the 3D open cube. :ref:`piece`
"""
def __init__(self,gui, x, y, fill, r, g, b, board, pid):
SIDE = 70
self.board, self.fill, self.pid = board, fill, pid
self.red, self.green, self.blue = r,g,b
#self.avatar = gui.ellipse(cx= x+35, cy = y+35, rx=20, ry=20,
# style=dict(fill=fill, fillOpacity= 0.5))
#self.avatex = gui.text(pid, x= x+35, y = y+35+10,
# style=dict(fill='navajowhite', fillOpacity= 0.7))
self.avatar = gui.image(href=REPO%fill,
x=x ,y=y, width=SIDE,height=SIDE)
#self.ascore= gui.text(pid, x= 45, y = 300+ pid*30,
# style=dict(fill='black', fillOpacity= 0.7))
self.avatar.addEventListener('mouseover', self.on_over)
#self.avatex.addEventListener('mouseover', self.on_over)
self.avatar.addEventListener('mouseout', self.on_out)
self.avatar.addEventListener('click', self.on_click)
#self.avatex.addEventListener('click', self.on_click)
self.house = board
#self.hide()
[docs] def show(self, x, y):
self.avatar.setAttribute("visibility",'hidden')
self.avatar.setAttribute('x', x)
self.avatar.setAttribute('y', y)
self.avatar.setAttribute("visibility",'visible')
[docs] def do_markers(self, *a):
pass
def _busy(self, *a):
pass
[docs] def on_over(self, ev):
self.do_markers(ev)
def _on_over(self, ev):
i, j, k = self._ijk
self.red.on_over(ev, i, j, k)
self.green.on_over(ev, i, j, k)
self.blue.on_over(ev, i, j, k)
[docs] def next_jig(self):
"""Remove the next piece from the puzzle. """
self.board.next_jig()
self.next_jig = self._busy
def _next_jig(self):
"""Remove the next piece from the puzzle. """
self.board.next_jig()
self.next_jig = self._busy
[docs] def on_click(self, ev):
self.board.drag(self)
[docs] def reset(self, x, y):
self.house.remove(self)
self.house = self.board
self.avatar.setAttribute("opacity", 1.0)
self.show(x, y)
self.do_markers = self._busy
self.next_jig = self._next_jig
[docs] def place(self, z, y, x, house):
self.house.remove(self)
self.house = house
self.avatar.setAttribute("opacity", 0.4+z*0.3)
self._ijk = (z, y, x)
OFFX, OFFY = 170-35, 170-35
ax = OFFX+x*100+71*z
ay = OFFY+y*100+71*z
self.show(ax, ay)
#self.avatex.setAttribute("x",ax)
#self.avatex.setAttribute("y",ay+10)
#self.ascore.text = '%d=%d.%d.%d'%(self.pid,z, y, x)
self.do_markers = self._on_over
self.next_jig()
[docs] def on_out(self, ev):
self.red.hide()
self.green.hide()
self.blue.hide()
[docs]class House:
""" marks a 3D location inside the cube where a piece can be deployed. :ref:`house`
"""
def __init__(self,gui, i, j, k, fill, r, g, b, board):
OFF =170
SIDE = 99
RDX = 30
self.board = board
self.place = self._place
self.level = board.house_layers[k]
self.avatar = gui.rect(x= OFF+k*100+71*i, y = OFF+j*100+71*i,
width=SIDE-(2-i)*RDX, height=SIDE-(2-i)*RDX,
style=dict(fill=fill, fillOpacity= 0.2))
self.avatar.addEventListener('mouseover', self.on_over)
self.avatar.addEventListener('mouseout', self.on_out)
self.avatar.addEventListener('click', self.on_click)
self.red, self.green, self.blue = r,g,b
self._ijk = (i, j, k)
[docs] def on_over(self, ev):
"""Projects three guiding shadows on the orthogonal cube walls"""
i, j, k = self._ijk
self.red.on_over(ev, i, j, k)
self.green.on_over(ev, i, j, k)
self.blue.on_over(ev, i, j, k)
def _busy(self, *a):
"""State method associated with a busy occupied house."""
pass
def _place(self, ev):
"""State method of a house that can recieve a piece, register it to the
board and disable new deployments here"""
self.board.place(self._ijk, self)
self.place = self._busy
[docs] def remove(self,piece):
"""Remove a piece from the house and set state to receive a new piece"""
self.place = self._place
[docs] def on_click(self, ev):
self.place(ev)
[docs] def on_out(self, ev):
self.red.hide()
self.green.hide()
self.blue.hide()
[docs]class Cube:
""" A 3D game memetic space represented in a cavalier projection. :ref:`cube`
"""
def __init__(self,gui,bottom_image, rear_image, side_image):
cls='red green blue'.split()
OFF =123
SIDE = 300
RDX = 30
bottom = gui.image(href=REPO%bottom_image,
x=SIDE,y=-2*SIDE, width=SIDE,height=SIDE, rotate= 90)
rear = gui.image(href=REPO%rear_image,
x=0,y=OFF, width=SIDE,height=SIDE, skewX=45, scale=(1,0.71))
left = gui.image(href=REPO%side_image,
x=OFF,y=0, width=SIDE,height=SIDE, skewY=45, scale=(0.71,1))
self.parts = [bottom, rear, left]
[docs] def hide(self):
for part in self.parts:
part.hide()
[docs] def show(self):
for part in self.parts:
part.show()
[docs]class Phase:
""" A game stage with a particular scenario and pieces. :ref:`phase`
"""
def __init__(self, gui, back_layer, puzzle, component):
back, jigs, faces, pieces = component
gui.set(back_layer)
self.group = gui.group(layer=1)
self.back = [gui.image(REPO%bk, 550, 150,200,100) for bk in puzzle]
for jig in self.back[:]:
jig.setAttribute("visibility",'hidden')
self.current_jig = -1
#: The 3D cube for this phase.
self.cube = Cube(gui, *faces)
gui.clear()
Z2TW, TW2Z = [0, 1, 2], [2, 1, 0]
#P_PLC = [[i+j*3, 350 + 50 * i,610 + 50*j] for j in Z2TW for i in TW2Z]
## Brython failure FIX
def ij(i,j):
k = i%2
l = i//2
return [i+j*3, 10 + 610 * k,150 + 210* k +210* l + 70*j]
P_PLC = [ij(i,j) for j in Z2TW for i in TW2Z]
#: Original placement of pieces at phase startup.
self.piece_places = P_PLC
#: Set of pieces to play in this phase.
self.pieces = pieces
[docs] def next_jig(self):
"""Remove the next piece from the puzzle. """
print(self.back, self.current_jig, self.current_jig +1)
if self.current_jig >= 0:
self.back[self.current_jig].setAttribute("visibility",'hidden')
self.current_jig += 1
self.back[self.current_jig].setAttribute("visibility",'visible')
pass
[docs] def reset(self):
"""Rearrange all pieces into original placement. """
self.group.setAttribute('visibility','visible')
[self.pieces[fid].reset(x, y) for fid, x, y in self.piece_places]
pass
[docs] def hide(self):
self.group.setAttribute('visibility','hidden')
[piece.hide() for piece in self.pieces]
[docs] def show(self):
self.group.setAttribute('visibility','visible')
[self.pieces[fid].show(x, y) for fid, x, y in self.piece_places]
[docs]class Board:
""" A meme game board with a 3D cube, some pieces, score and puzzle. :ref:`board`
"""
[docs] def remove(self,piece):
"acts as a default null house"
pass
def _parse_response(self, response, prefices):
def _figures(response = response):
#workaround for brython bug
resp = eval(response.text)
return resp['result']
#figures = resp['result']
return [
[[img for img in _figures()
if ('%s0%d'%(prefix, infix)) in img] for infix in range(10)
]
for prefix in prefices.split()]
def _load_scenes(self, response):
logger('loading from memit type 2, ')
self.face_imgs, self.back_imgs =self._parse_response(response, 'face backs')
self._build_phases()
def _load_figures(self, response):
self.piece_imgs, self.jig_imgs, self.puzzle_imgs = self._parse_response(
response, 'piece jigs puzzle_')
logger('loading from memit type 1 pieces :%s'%self.piece_imgs)
self.gui.request('/rest/studio/memit?type=2', self._load_scenes)
def _load_inventory_from_server(self):
self.gui.request('/rest/studio/memit?type=1', self._load_figures)
def _build_markers(self, gui):
self.red = Marker(gui, 300,300,'red',(0,1,1))
self.green = Marker(gui, 300,300,'green',(1,0,1))
self.blue = Marker(gui, 300,300,'blue',(1,1,0))
[docs] def place(self, *a):
"""Placement state method. Assumes _place (active) or _busy states"""
pass
def _place(self, position = None, house = None):
self.piece.place(*position, house = house)
logger('_place %s %s %s'%(house.level,self.piece.avatar,self.piece))
#self.gui.set(house.level)
#self.gui.up(self.piece.avatar)
#self.gui.clear()
#self.gui.cling(house.level,self.piece.avatar)
self.place = self._busy
return self.piece
def _busy(self, *a):
pass
def _drag(self, p =None):
i, j, k = self._ijk
[docs] def next_jig(self):
"""Remove the next piece from the puzzle. """
self.value = 0
self.phases[0].next_jig()
print(self.phases[0].current_jig)
if self.phases[0].current_jig >= 9:
self.inc = 0
self.value = 0
__ = [drop.setAttribute('visibility', 'hidden') for drop in self.drops]
time.clear_interval()
#time.set_interval(self.tick,3000)
[docs] def drag(self, p =None):
"""Enable placement of pieces. Arg p is the piece being dragged """
self.piece = p
self.place = self._place
def __init__(self,gui):
logger('Board __init__ %s'%gui)
self.gui = gui
self.houses = []
self.phases = []
self.piece = None
self.phase = 0
self._load_inventory_from_server()
def _build_layers(self,gui):
self.back_layer = gui.group(layer=0)
self.marker_layer = gui.group()
gui.clear()
gui.set(self.marker_layer)
self._build_markers(gui)
self.house_layers = [gui.group(None,0) for ly in range(3)]
gui.clear()
self.pieces_layer = gui.group(layer=0)
def _build_inventory_locally(self):
# not being used currently, should be a fallback for server failure
PHASES = 7
PIECES = 9
#self.faces = ['valor.png','beleza.png','conforto.png'] * PHASES
self.back_imgs = ['back%02d.jpg'%(phase)
for phase in range(PHASES)]
self.puzzle_img = ['puzzle%02d.jpg'%(phase)
for phase in range(PHASES)]
self.jig_imgs = [
['jigs%02d_%02d.jpg'%(phase,face) for face in range(PIECES)]
for phase in range(PHASES)]
self.face_imgs = [['face%02d_%02d.jpg'%(phase,face) for face in [0,1,2]]
for phase in range(PHASES)]
self.piece_imgs = ['piece%02d_%02d.png'%(kind,piece)
for piece in range(PIECES) for kind in [0,1]]
def _build_phases(self):
gui= self.gui
CLS='red green blue'.split()
Z2TW, TW2Z = [0, 1, 2], [2, 1, 0]
KINDS = [0,1]#[0]*2+[1]*5
self.avatar = gui.image(href=REPO%'memit/background_base.png', x= 0, y = 0,
width=800, height=600, style=dict(opacity= 1))
self.pump = gui.image(href=REPO%'memit/bomba.png', x= 390, y = 5,
width=400, height=112, style=dict(opacity= 1))
self.drops = [gui.image(REPO%'memit/gota.png',750, 50 + 100*i,
40, 52) for i in range(6)]
self.puzzle = gui.image(href=REPO%'memit/puzzle00_00.png', x= 550, y = 150,
width=200, height=100, style=dict(fill='blue', fillOpacity= 1))
self._build_layers(gui)
r, g, b = RGB = [self.red, self.green, self.blue]
#piece_places = [[[350 + 50 * i,610 + 50*j]
# for j in Z2TW] for i in TW2Z]
piece_places = [[i+j*3, 350 + 50 * i,610 + 50*j]
for j in Z2TW for i in TW2Z]
#print (piece_places)
gui.set(self.pieces_layer)
def create_hidden(fid, x, y, kind):
piece = Piece(gui, x, y, self.piece_imgs[kind][fid], r, g, b, self, fid)
piece.hide()
return piece
pc = self.pieces = [
[create_hidden(fid, x, y , kind)
for fid, y, x in piece_places] for kind in KINDS]
logger('to b form')
gui.clear()
piece_imgs = [pc[i] for i in [1,1,1,1,1,1,1]]
gui.set(self.back_layer)
self.puzzle_imgs = [puz[0] for puz in self.puzzle_imgs]
self.phases = [Phase(gui, self.back_layer, self.puzzle_imgs, components)
for components in zip(self.back_imgs,
self.jig_imgs, self.face_imgs, piece_imgs)]
gui.clear()
gui.set(self.marker_layer)
self.houses = [House(gui, i, j, k, CLS[i], r, g, b, self)
for k in Z2TW for j in Z2TW for i in TW2Z]
gui.clear()
gui.up(self.back_layer)
gui.clear()
gui.up(self.marker_layer)
gui.clear()
gui.up(self.pieces_layer)
gui.clear()
self.phases[0].reset()
self.next_jig()
#: initialize pump digits, pump value and start 100ms timer
self.digits = [
gui.text('0', 425 +50*i, 65, 48, 'middle', {'fill': 'white'})
for i in range(4)]
self.value =0
self.inc =1
time.set_interval(self.tick,100)
[docs] def tick(self):
"""Time tick updates pump display value and makes the drops fall"""
value = self.value //10
for i, drop in enumerate(self.drops):
y = 50 + (i * 100 + (10 * self.value) % 100) % 500
drop.setAttribute('y' , y)
#print ('tick', value, value %10, value //10)
for i in range(4)[::-1]:
self.digits[i].text = str(value % 10)
value //= 10
self.value += self.inc
[docs]def main(dc,pn, gui, repo):
""" Starting point """
logger('Starting point')
global REPO
#REPO = repo
return Board(gui)
"""
#for phase in phases:
# Phase(gui, self.back_layer)
#self.phases= [
# [Cube(gui, *faces),None] for faces in self.face_imgs[phase]]
#self._build_markers(gui)
#for i in [2,1,0]:
# for j in [0,1,2]:
# for k in [0,1,2]:
# self.houses.append( House(gui, i, j, k, cls[i],
# self.red, self.green, self.blue, self))
#for i in [2,1,0]:
# for j in [0,1,2]:
# Piece(gui,610 + 50*j, 350 + 50 * i, 'black',
# self.red, self.green, self.blue, self,3*i+j+1)
#self._build_form(gui)
"""