Forked from facundobatista/gist:b9747e8ec361bccabf0c3ad9692a7873
Created
February 24, 2020 00:10
-
-
Save iglosiggio/ad493db274ac6d34cdb04a1f9a77aa7e to your computer and use it in GitHub Desktop.
Alocado Alocador
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#--------------------- game.py | |
#--------------------- header.py | |
instrucciones = [ | |
"You are the memory allocator: your job is to place code segments in RAM", | |
"Place the segments before the user loses her patience", | |
"Use space or right click to rotate memory segments", | |
"The score will increase as you optimize the space by making rectangular areas", | |
"When a segment is not yet optimized you can still move it", | |
"You get higher scores if your areas are more 'square'", | |
"When a memory segment is no longer needed it will be released by the GC", | |
] | |
tips = instrucciones * 3 + [ | |
"Alocado Alocador! - 62684 bytes of pure fun", | |
"visit our website: http://www.python.com.ar/moin/Proyectos/AlocadoAlocador", | |
"(c) 2006 Team PyAr: lucio, nubis, dave, chaghi, fbatista, alecu", | |
"missing in action: leito, un tal pablo. thanks to all the testers", | |
"made for pydraw 2006 - License: GPL", # find it at: http://www.gnu.org/copyleft/gpl.html | |
] | |
import math | |
import pygame, sys, random | |
import os, sys, pygame, pygame.font, pygame.image | |
from pygame.locals import * | |
#--------------------- trimedAS.py | |
#!/usr/bin/env python | |
import pygame | |
from math import cos, sin, radians, sqrt | |
from pygame.locals import * | |
from pygame import Surface | |
from pygame.sprite import Sprite | |
from pygame.sprite import RenderUpdates, OrderedUpdates | |
import os, sys | |
def listify(fn): | |
def rval(*args): | |
return list(fn(*args)) | |
return rval | |
lmap = listify(map) | |
lfilter = listify(filter) | |
class RootSprite(Sprite): | |
''' | |
Pantalla principal de la GUI, aca se define la resolucion, el color de fondo y los fps | |
Se encarga de llamar al update de todos los sprites. | |
Es un singleton, | |
Se instancia una sola vez y luego se llama a get() para obtener la instancia actual. | |
NOTA: Esta forma de implementar el singleton es propensa a cambiar. | |
Quizas se podria usar un archivo de configuracion para los fps, color de fondo y resolucion | |
y asi se podria instanciar en este modulo y dejar accesible como ActionSprite.root | |
''' | |
_root = None | |
@staticmethod | |
def get(): | |
#Obtener la instancia actual de Root | |
return RootSprite._root | |
def __init__(self, width=640, height=480, color=(255,255,255), fps=29): | |
RootSprite._root = self | |
self.allChilds = OrderedUpdates() | |
self.childs = OrderedUpdates() | |
Sprite.__init__(self) | |
pygame.init() | |
self.fps = fps | |
self.width = width | |
self.height = height | |
self.color = color | |
self.screen = pygame.display.set_mode((width, height)) | |
self.background = pygame.Surface(self.screen.get_size()) | |
self.background = self.background.convert() | |
self.background.fill(color) | |
self.screen.blit(self.background, (0,0)) | |
pygame.display.update() | |
self.timer = pygame.time.Clock() | |
def run(self): | |
while True: | |
self.timer.tick(self.fps) | |
self.allChilds.update() | |
self.allChilds.clear(self.screen, self.background) | |
rects = self.allChilds.draw(self.screen) | |
pygame.display.update(rects) | |
class _familyguy(object): | |
''' | |
FamilyGuy contiene la funcionalidad de anidacion de ActionSprite | |
dejando disponible un puntero al parent, a los Sprites 'hijos' (childs) | |
y al sprite root | |
''' | |
def __init__(self, parent): | |
self.parent = parent | |
parent.childs.add(self) | |
self.childs = OrderedUpdates() | |
if hasattr(parent, "root"): | |
self.root = parent.root | |
else: | |
self.root = parent | |
self.root.allChilds.add(self) | |
class ActionSprite(Sprite, _familyguy): | |
rect = Rect(0,0,0,0) | |
def __init__(self, parent, x=0, y=0, width=10, height=10, rotation=0, color=None): | |
Sprite.__init__(self) | |
_familyguy.__init__(self, parent) | |
self.rect = Rect(x, y, width, height) | |
self.colorkey = (0,0,0) | |
self.x = x | |
self.y = y | |
self.width = width | |
self._orig_width = width | |
self.height = height | |
self._orig_height = height | |
self.rotation = rotation | |
if not hasattr(self, "imagen_original"): | |
self.imagen_original = pygame.Surface( (self.rect.width, self.rect.height)) | |
self.imagen_original.convert() | |
if color: | |
self.color = color | |
else: | |
self.imagen_original.set_alpha(0) | |
self.image = self.imagen_original | |
self.lastImage = self.image | |
self.init() | |
self.dirty = True #flag para evitar redraws innecesarios | |
self.dragging = False #Estamos moviendo con el mouse o no | |
def init(self): pass | |
def inside(self, x, y): | |
dx = self._getDrawingX() | |
dy = self._getDrawingY() | |
if dx<=x<=dx+self.width and dy<=y<=dy+self.height: | |
return True | |
return False | |
def update(self): | |
self.onEnterFrame() | |
self._ifDragging() | |
self._draw() | |
def onEnterFrame(self): | |
pass | |
def _ifDragging(self): | |
if self.dragging: | |
x,y = pygame.mouse.get_pos() | |
dx = self.parent._getDrawingX() | |
dy = self.parent._getDrawingY() | |
self.x = x - dx | |
self.y = y - dy | |
@property | |
def yscale(self): | |
return (self.height*100)/self._orig_height | |
@property | |
def xscale(self): | |
return (self.width*100)/self._orig_width | |
def _draw(self): | |
''' | |
Dibjuar el sprite | |
Teniendo en cuenta las transformaciones de los clips padres | |
''' | |
#Obtener las medidas, rotacion y posicion definitivas para dibujar | |
self.rect.left = self._getDrawingX() | |
self.rect.top = self._getDrawingY() | |
width = self._getDrawingWidth() | |
height = self._getDrawingHeight() | |
#dibujamos la imagen | |
if not self.dirty: | |
self.image = self.lastImage | |
return | |
self.image = pygame.transform.scale(self.imagen_original, (width, height)) | |
self.image = pygame.transform.rotozoom(self.image, self.rotation, 1) | |
self.image.set_colorkey(self.colorkey) | |
self.lastImage = self.image | |
self.dirty = False | |
def _getDrawingXScale(self): | |
try: | |
scale = self.parent.xscale*self.parent._getDrawingXScale()/100 | |
except AttributeError: | |
scale = 100 | |
return scale | |
def _getDrawingYScale(self): | |
try: | |
scale = self.parent.yscale*self.parent._getDrawingYScale()/100 | |
except AttributeError: | |
scale = 100 | |
return scale | |
def _getDrawingX(self): | |
try: | |
x = self.parent.rect.x+(self.x*self._getDrawingXScale()/100) | |
except AttributeError: | |
x = self.x | |
return x | |
def _getDrawingY(self): | |
try: | |
y = self.parent.rect.y+(self.y*self._getDrawingYScale()/100) | |
except AttributeError: | |
y = self.y | |
return y | |
def _getDrawingWidth(self): | |
return int(self.width*self._getDrawingXScale()/100) | |
@property | |
def boundBoxWidth(self): | |
return (self.image.get_width()*100)/self._getDrawingXScale() | |
def _getDrawingHeight(self): | |
return int(self.height*self._getDrawingYScale()/100) | |
@property | |
def boundBoxHeight(self): | |
return (self.image.get_height()*100)/self._getDrawingYScale() | |
def _getRotation(self): | |
return self.__dict__['rotation'] | |
def _setRotation(self, rotation): | |
self.dirty = True | |
if rotation > 360: | |
rotation -= 360 | |
elif rotation < 0: | |
rotation += 360 | |
self.__dict__['rotation'] = rotation | |
rotation = property(_getRotation, _setRotation) | |
def dirtyProperty(name): | |
def set(self, value): | |
self.dirty = True | |
self.childs.dirty = True | |
self.__dict__[name] = value | |
def get(self): | |
return self.__dict__[name] | |
return property(get,set) | |
width = dirtyProperty('width') | |
height = dirtyProperty('height') | |
x = dirtyProperty('x') | |
y = dirtyProperty('y') | |
def _setColor(self, value): | |
self.__dict__['color'] = value | |
self.dirty = True | |
self.imagen_original.fill(value) | |
self.imagen_original.set_alpha(255) | |
def _getColor(self): | |
return self.__dict__.get('color') | |
color = property(_getColor, _setColor) | |
@property | |
def xmouse(self): | |
return pygame.mouse.get_pos()[0] - self._getDrawingX() | |
@property | |
def ymouse(self): | |
return pygame.mouse.get_pos()[1] - self._getDrawingY() | |
def kill(self): | |
self.imagen_original.set_alpha(0) | |
self.lastImage.set_alpha(0) | |
self._draw() | |
for s in self.childs.sprites(): | |
s.kill() | |
Sprite.kill(self) | |
#--------------------- ASGrid.py | |
#--------------------- grid.py | |
ROTFUNC = [ lambda x,y:(x,y), | |
lambda x,y:(-y-1, x), | |
lambda x,y:(-x-1,-y-1), | |
lambda x,y:(y,-x-1)] | |
class Piece: | |
def __init__(self): | |
self.mirror = 0 | |
def getSize(self): | |
f = [lambda x,y:(x,y), lambda x,y:(y,x)][self.mirror%2] | |
return f(*self.size) | |
def at(self, x,y): | |
return self._at(*ROTFUNC[self.mirror](x,y)) | |
def _at(self, x,y): | |
"""subclasses must implement this""" | |
raise 'error' | |
def __str__(self): | |
return 'X' | |
def tiles(self): | |
sx,sy = self.getSize() | |
l = [] | |
for y in range(sy): | |
for x in range(sx): | |
if self.at(x,y): | |
l.append((x,y)) | |
return l | |
def rotate(self): | |
self.mirror = (self.mirror+1)%4 | |
def show(self): | |
sx,sy = self.getSize() | |
for y in range(sy): | |
s='' | |
for x in range(sx): | |
s+=[' ','X'][self.at(x,y)] | |
print(s) | |
print('-'*10) | |
class PieceString(Piece): | |
def __init__(self, lineset): | |
Piece.__init__(self) | |
self.size = len(lineset[0]),len(lineset) | |
self.lineset=lineset | |
def _at(self,x,y): | |
return self.lineset[y][x]=='X' | |
# def temporal para probar el generador de piezas | |
PS = PieceString | |
class GExp (Exception): pass | |
class Grid: | |
def __init__(self, m, n): | |
self.frozen_set = set() | |
self.size = m, n | |
g = [] | |
for y in range(n): | |
l = [] | |
for x in range(m): l+=[' '] | |
g.append(l) | |
self.grid = g | |
self.pieces = {} | |
def at(self, x, y): | |
return self.grid[y][x] | |
def draw(self): | |
g=self.grid | |
for l in g: | |
print(''.join(lmap(lambda x:str(x),l))) | |
print('-'*10) | |
def cempty(self, pos, tiles): | |
px,py=pos | |
for x,y in tiles: | |
if self.at(px+x,py+y)!=' ': | |
return False | |
return True | |
def setTiles(self, pos, tiles, Content=' '): | |
px,py=pos | |
for x,y in tiles: | |
self.grid[py+y][px+x] = Content | |
def remove(self, piece): | |
p = self.pieces | |
pos = p[piece] | |
del p[piece] | |
self.setTiles(pos, piece.tiles()) | |
for (x,y) in piece.tiles(): | |
if (x,y) in self.frozen_set: | |
self.frozen_set.remove( (x,y) ) | |
return pos | |
def put(self, piece, pos): | |
pt=piece.tiles() | |
x,y=pos | |
px,py=piece.getSize() | |
m,n=self.size | |
if px+x>m or py+y>n: raise GExp() | |
if not self.cempty(pos, pt): raise GExp() | |
self.setTiles(pos, pt, piece) | |
self.pieces[piece]=pos | |
value = self.checkRectangle(pos, piece, pt) | |
if value: | |
area, (sx, sy, ex, ey) = value | |
self.freeze(sx,sy,ex,ey) | |
return value | |
return 0 | |
def freeze(self, sx, sy, ex,ey): | |
for x in range(sx,ex): | |
for y in range(sy,ey): | |
self.frozen_set.add( (x,y) ) | |
def frozen(self, x, y): | |
if (x,y) in self.frozen_set: | |
return True | |
else: | |
return False | |
def move(self,piece,pos): | |
self.remove(piece) | |
self.put(piece,pos) | |
def rotate(self, piece): | |
pos = self.remove(piece) | |
ok=False | |
while not ok: #this ends because we at last go back to first position | |
piece.rotate() | |
print(pos) | |
try: self.put(piece,pos) | |
except GExp: pass | |
else: ok=True | |
def checkRectangle(self, pos, piece, tiles=None): | |
if tiles==None: tiles=piece.tiles() | |
m,n=self.size | |
x,y = pos | |
tile = tiles[0] | |
x+=tile[0] | |
y+=tile[1] | |
if 0: print('tile at:',x,y) | |
empty = ' ' | |
sx,ex=x,x | |
sy,ey=y,y | |
while (ex<m-1) and (not self.at(ex+1,y)==empty): ex+=1 | |
while (sx>0) and (not self.at(sx-1,y)==empty): sx-=1 | |
while (ey<n-1) and (not self.at(x,ey+1)==empty): ey+=1 | |
while (sy>0) and (not self.at(x,sy-1)==empty): sy-=1 | |
ex+=1 | |
ey+=1 | |
if 0: | |
print('rect.candidate:',repr((sx,sy)),' ', repr((ex,ey))) | |
tpos=[] | |
xpos=[] | |
#copy rectangle bounds | |
tsx,tsy,tex,tey=sx,sy,ex,ey | |
#expand them 1 in every possible direction to check emptiness | |
if tsx>0: tsx-=1 | |
if tsy>0: tsy-=1 | |
if tex<m-1: tex+=1 | |
if tey<n-1: tey+=1 | |
ok = True | |
for x in range(tsx,tex): | |
for y in range(tsy,tey): | |
if x<sx or x>=ex or y<sy or y>=ey: | |
#self.grid[y][x]='E' #draw empty check rect. | |
#self.draw() | |
if self.at(x,y)!=empty: | |
ok=False | |
if 0: | |
o = self.grid[y][x] | |
self.grid[y][x]='*' | |
self.draw() | |
self.grid[y][x]=o | |
break | |
else: | |
if self.at(x,y)==empty: | |
ok=False | |
if 0: | |
o = self.grid[y][x] | |
self.grid[y][x]='*' | |
self.draw() | |
self.grid[y][x]=o | |
break | |
if ok: | |
print('Rectangle found!!!') | |
size = (ey-sy)*(ex-sx) | |
print('size = ',size) | |
return size, (sx, sy, ex, ey) | |
return None | |
def test(): | |
import random | |
random.seed(5) | |
print('-'*10) | |
g = Grid(20,10) | |
pL = PieceString(['XXX','X ']) | |
#g.draw() | |
g.put(pL,(3,3)) | |
if 0: | |
g.draw() | |
g.move(pL,(1,0)) | |
g.draw() | |
g.move(pL,(1,1)) | |
g.draw() | |
g = Grid(20,10) | |
pL.rotate() | |
g.put(pL,(3,3)) | |
g = Grid(20,10) | |
pL = PieceString(['XXX','X ']) | |
g.put(pL,(3,3)) | |
p2 = PieceString([' XX','XXX']) | |
g.put(p2,(3,4)) | |
#g.draw() | |
import math | |
TILESIZE = 32 | |
#COLORES | |
GRIS_CLARO = (100,100,100) | |
GRIS_OSCURO = (200,200,200,127) | |
NARANJA = (250, 180, 0) | |
BLANCO = (255,255,255) | |
VIOLETA = (80,80,130) | |
FONDO = BLANCO | |
PIEZA = GRIS_OSCURO | |
GRID = (255,204,102) #NARANJA | |
class ASGrid(Grid, ActionSprite): | |
def __init__(self, parent, x, y, gs_x, gs_y, color=GRID): | |
width = gs_x * TILESIZE | |
self.piece_to_aspiece = {} | |
height = gs_y * TILESIZE | |
Grid.__init__(self, gs_x, gs_y) | |
ActionSprite.__init__(self, parent=parent, x=x, y=y, width=width, height=height, color=color) | |
self.floatingPiece = None | |
self.tilesize = TILESIZE | |
self._gridImage() | |
def _gridImage(self): | |
for i in range(self.size[0]): | |
pygame.draw.line(self.imagen_original, (0,0,0,), (self.tilesize*i,0), (self.tilesize*i,self.imagen_original.get_height())) | |
for i in range(self.size[1]): | |
pygame.draw.line(self.imagen_original, (0,0,0,), (0,self.tilesize*i), (self.imagen_original.get_width(), self.tilesize*i)) | |
def put(self, piece, pos): | |
self.piece_to_aspiece[ piece.piece ] = piece | |
r = Grid.put(self, piece.piece, pos) | |
if r: | |
area, (sx, sy, ex, ey) = r | |
for x in range(sx,ex): | |
for y in range(sy, ey): | |
p = self.at(x, y) | |
self.piece_to_aspiece[p].set_color(VIOLETA) | |
self.piece_to_aspiece[p].piece_color = (VIOLETA) | |
self.piece_to_aspiece[p].freeze() | |
return (area**3)/int(math.sqrt((ex-sx)**2)+(ey-sy)**2) | |
return r | |
def as_piece_at(self, x, y): | |
piece = Grid.at(self, x, y) | |
if piece and piece!=' ': | |
return self.piece_to_aspiece[piece] | |
return None | |
def getTileSize(self): | |
return self._getDrawingWidth()/self.size[0] | |
def presentPiece(self, piece): | |
self.floatingPiece = ASPiece(self, piece, 0,0) | |
self.floatingPiece.dragging = True | |
def getCoords(self): | |
tilesize = self.getTileSize() | |
xm = self.xmouse // tilesize | |
ym = self.ymouse // tilesize | |
if xm < 0: | |
xm = 0 | |
if ym < 0: | |
ym = 0 | |
if self.size[0] < xm: | |
xm = self.size[0] | |
if self.size[1] < ym: | |
ym = self.size[1] | |
if self.size[0] < xm or xm < 0 or self.size[1] < ym or ym < 0: | |
raise 'WATAFAAAAAAKERRORRR: '+str(((self.xmouse, self.ymouse), (self.size[0],self.size[1]))) | |
x = self._getDrawingX() + xm*tilesize | |
y = self._getDrawingY() + ym*tilesize | |
return ((xm,ym), (x,y)) | |
def test(): | |
RootSprite(width= WIDTH+20, height= HEIGHT+20, color=FONDO, fps=29) | |
_root = RootSprite.get() | |
g = ASGrid(_root) | |
pL = PieceString(['XXX','X ']) | |
g.put(pL, (1,1)) | |
_root.run() | |
from pygame.sprite import OrderedUpdates | |
#--------------------- piecegen.py | |
from random import choice | |
_mktiles = lambda rx,ry:lmap(lambda x:[(x,y) for y in range(ry)] , range(rx)) | |
mktiles = lambda x,y: reduce( lambda u,v: u+v, _mktiles(x,y), []) | |
def freeAround(libres, ocupados): | |
r = [-1, 1] | |
tilesalrededor = [] | |
for tile in ocupados: | |
tx, ty= tile | |
for x in r: | |
tilesalrededor += [(tx+x, ty)] | |
for y in r: | |
tilesalrededor += [(tx, ty+y)] | |
s= lfilter(lambda tile: tile in libres, tilesalrededor) | |
return s | |
def addPoint(l): | |
tiles = mktiles(len(l[0]),len(l)) | |
ocupados = lfilter(lambda pos:l[pos[1]][pos[0]]=='X', tiles) | |
libres = lfilter(lambda pos:l[pos[1]][pos[0]]==' ', tiles) | |
freeAround(libres, ocupados) | |
x,y = choice(freeAround(libres, ocupados)) | |
l[y][x]='X' | |
return x,y | |
def mkpiece(sx,sy,wanted=4): | |
l=[] | |
for y in range(sy): | |
linea = [' ']*sx | |
l.append(linea) | |
poslist=[] | |
l[sy//2][sx//2]='X' | |
while wanted>1: | |
poslist+=[addPoint(l)] | |
wanted-=1 | |
pieceLines=[] | |
for linea in l: | |
pieceLines.append(''.join(linea)) | |
wrk = PieceTrimmer(pieceLines) | |
return wrk.trimmedLines() | |
class PieceTrimmer(PS): | |
def trimmedLines(self): | |
sx,sy = self.getSize() | |
bx,by,ex,ey = sx,sy, 0, 0 #obtuse values | |
#get only used coords | |
for tile in self.tiles(): | |
tx,ty = tile | |
if tx<bx: bx=tx | |
if tx>ex: ex=tx | |
if ty<by: by=ty | |
if ty>ey: ey=ty | |
return lmap ( lambda line:line[bx:ex+1], self.lineset[by:ey+1] ) | |
def test(): | |
x=10 | |
y=10 | |
piece = mkpiece(x,y,8) | |
g = Grid(x,y) | |
pL = PS(piece) | |
#g.put(pL,(0,0)) | |
#g.draw() | |
def show(piece): | |
px,py = piece.getSize() | |
for y in range(py): | |
s='' | |
for x in range(px): | |
s+=['_','X'][piece.at(x,y)] | |
print(s) | |
print('-'*20) | |
show(pL) | |
pL.rotate() | |
show(pL) | |
pL.rotate() | |
show(pL) | |
pL.rotate() | |
show(pL) | |
pL.rotate() | |
show(pL) | |
#--------------------- tinySynth.py | |
# | |
# tinySynth.py - (c) 2006 alecu [pyar] | |
# | |
# Licenciado con la GPL | |
# | |
# requiere python 2.4, pygame 1.7 | |
# Para armar una melodia: | |
# nota[:octavos, default:4[:octava, default: 0]]<espacio> | |
# nota = [ABCDEFG-][b#] | |
# #comentarios | |
# feliz cumpleagnos / el payaso plin-plin | |
cumpleagnos = """ | |
C:2 C:2 D C F E:8 | |
C:2 C:2 D C G F:8 | |
C:2 C:2 C:4:1 A:4 F E D | |
B:2 B:2 A:4 F G F:8 | |
""" | |
flyme = """ | |
#1start C:4:1 B A:2 G:6 F:6 G:2 A C:4:1 B A G:2 F:6 E:16 #1end | |
#2start A G F:2 E:6 D:6 E:2 F A G# F E:2 D:6 #2end | |
#short1 C:12 C# D:2 A A:14 C:8:1 B G:28 | |
#short2 B:8:-1 C:4 F:8 F:28 A:16 G:8 F:16 E:48 | |
#1start C:4:1 B A:2 G:6 F:6 G:2 A C:4:1 B A G:4 F:2 E:16 #1end | |
#2start A G F:2 E:6 D:6 E:2 F A G# F E:2 D:6 #2end | |
#short1 C:12 C# D:2 A A:14 C:8:1 B G:28 | |
#short2b G# A:2 C C:10 C D C:16 -:16 | |
#1start C:4:1 B A:2 G:6 F:6 G:2 A C:4:1 B A G:4 F:2 E:16 #1end | |
#2start A G F:2 E:6 D:6 E:2 F A G# F E:2 D:6 #2end | |
#short1 C:12 C# D:2 A A:14 C:8:1 B G:28 | |
#ending E:28:1 C:4:1 D:2:1 A:2 A:14 B:8 D:2:1 C:28 | |
""" | |
ateam = """ | |
D#:4 A#:2:-1 D#:8 -:2 | |
G#:2:-1 A#:4:-1 D#:6:-1 -:2 G:1:-1 A:1:-1 | |
D#:2 A#:2:-1 F:2 D#:8 -:2 | |
C#:3 C:1 A#:1:-1 G#:3:-1 A#:8:-1 | |
D#:3 D#:1 A#:2:-1 D#:8 -:2 | |
G:2:-1 G#:2:-1 F:2:-1 A#:2:-1 D#:8:-1 | |
F#:3:-1 G#:1:-1 C:2 C#:24 -:2 | |
C#:2 C:2 -:2 G#:2:-1 C#:4 C:4 | |
G:3:-1 G#:1:-1 A#:2:-1 D#:8 -:2 | |
A#:2:-1 G#:2:-1 -:2 D#:2:-1 A#:4:-1 G#:4:-1 | |
G#:2:-1 G:2:-1 D#:2:-1 D:2:-1 D#:8:-1 | |
-:16 | |
D#:4 A#:4:-1 D#:8 -:2 | |
G#:2:-1 A#:4:-1 D#:6:-1 -:2 G:1:-1 A:1:-1 | |
D#:2 A#:2:-1 F:2 D#:8 -:2 | |
C#:3 C:1 A#:1:-1 G#:3:-1 A#:8:-1 | |
D#:3 D#:1 A#:2:-1 D#:8 -:2 | |
G:2:-1 G#:2:-1 F:2:-1 A#:2:-1 D#:8:-1 | |
G#:2:-1 G:4:-1 D#:2:-1 G#:4:-1 G:4:-1 | |
G#:4:-1 A#:4:-1 C:2 D:6 | |
D#:4 | |
""" | |
imperial=""" | |
G:6:-1 -:2 -:1 G:6:-1 -:1 G:8:-1 D#:4:-1 -:2 A#:2:-1 | |
G:8:-1 -:1 D#:4:-1 -:1 -:1 A#:1:-1 G:8:-1 -:8 | |
D:6 -:2 -:1 D:6 -:1 D:8 D#:4 -:2 A#:2:-1 | |
F#:8:-1 D#:4:-1 -:4 A#:4:-1 G:8:-1 -:8 | |
G:8 G:3:-1 -:1 -:4 G:1:-1 G:6 -:1 -:1 F#:4 -:1 -:2 | |
F:1 E:2 -:1 D#:1 E:4 -:4 G#:4:-1 -:1 C#:6 -:1 -:1 C:4 -:1 -:1 B:2:-1 | |
-:1 A#:2:-1 -:1 A:2:-1 A#:2:-1 -:1 -:2 D#:4:-1 F#:6:-1 -:2 -:1 D#:4:-1 -:1 -:1 F:1:-1 | |
A#:6:-1 -:2 -:1 G:4:-1 -:1 -:1 A:1:-1 D:12 -:4 | |
G:8 G:3:-1 -:1 -:4 G:1:-1 G:6 -:1 -:1 F#:4 -:1 -:2 | |
F:1 E:2 -:1 D#:1 E:4 -:4 G#:4:-1 -:1 C#:6 -:1 -:1 C:4 -:1 -:1 B:2:-1 | |
-:1 A#:2:-1 -:1 A:2:-1 A#:2:-1 -:1 -:2 D#:4:-1 F#:6:-1 -:2 -:1 D#:4:-1 -:1 -:1 A:1:-1 | |
G:6:-1 -:2 -:1 D#:4:-1 -:1 -:1 A#:1:-1 G:12:-1 -:4 | |
""" | |
montypython=""" | |
F:4 E:1 -:1 D:4 C#:1 -:1 | |
C:3 -:1 B:1:-1 -:1 A#:4:-1 A:2:-1 -:1 | |
G:1:-1 -:1 A:1:-1 -:1 A#:1:-1 -:1 A:2:-1 -:2 G:1:-1 -:1 | |
C:1 -:4 -:1 -:4 C:1 -:1 | |
A:1:-1 -:2 -:1 A:1:-1 -:1 A:2:-1 G#:2:-1 A:1:-1 -:1 | |
F:1 -:2 -:1 C:1 -:1 C:1 -:2 -:1 A:1:-1 -:1 | |
A#:1:-1 -:2 -:1 A:1:-1 -:1 A:1:-1 -:2 -:1 C:1 -:1 | |
D:8 -:2 A:1:-1 -:1 | |
G:1:-1 -:2 -:1 G:1:-1 -:1 G:1:-1 F#:2:-1 G:1:-1 -:1 | |
E:1 -:2 -:1 D:1 -:1 D:1 -:2 -:1 A#:1:-1 -:1 | |
A:1:-1 -:2 -:1 A:1:-1 -:1 A:1:-1 -:2 -:1 A#:1:-1 -:1 | |
C:8 -:2 C:1 -:1 | |
A:1:-1 -:2 -:1 A:1:-1 -:1 A:2:-1 G#:2:-1 A:1:-1 -:1 | |
A:1 -:2 -:1 F:1 -:1 F:1 -:2 C:1 -:1 | |
B:1:-1 -:2 G:1 -:1 G:1 -:2 -:1 G:1 -:1 | |
G:8 -:2 G:1 -:1 | |
E:1 -:2 -:1 G:1 -:1 G:2 F#:2 G:2 | |
D:1 -:2 -:1 G:1 -:1 G:2 F#:2 G:2 | |
C:1 -:2 -:1 B:1:-1 -:1 C:1 -:2 -:1 B:1:-1 -:1 | |
C:4 -:2 C:4 -:2 | |
A:1:-1 -:2 -:1 A:1:-1 -:1 A:2:-1 G#:1:-1 A:1:-1 -:1 | |
F:1 -:2 -:1 C:1 -:1 C:1 -:2 -:1 A:1:-1 -:1 | |
A#:1:-1 -:2 -:1 A#:1:-1 -:1 A#:1:-1 -:2 -:1 C:1 -:1 | |
D:8 -:2 A#:1:-1 -:1 | |
G:1:-1 -:2 -:1 G:1:-1 -:1 G:1:-1 -:1 F#:2:-1 G:1:-1 -:1 | |
E:1 -:2 -:1 D:1 -:1 D:1 -:2 -:1 A#:1:-1 -:1 | |
A:1:-1 -:2 -:1 A:1:-1 -:1 A:1:-1 -:2 -:1 A#:1:-1 -:1 | |
C:8 -:2 C:1 -:1 | |
A:1:-1 -:2 -:1 A:1:-1 -:1 A:2:-1 G#:2:-1 A:1:-1 -:1 | |
A:1 -:2 -:1 F:1 -:1 F:1 -:2 C:1 -:1 | |
B:1:-1 -:2 G:1 -:1 G:1 -:2 -:1 G:1 -:1 | |
G:8 -:2 G:1 -:1 | |
E:1 -:2 -:1 G:1 -:1 G:2 F#:2 G:1 -:1 | |
D:1 -:2 -:1 G:1 -:1 G:2 F#:2 G:1 -:1 | |
C:1 -:2 -:1 B:1:-1 -:1 C:1 -:2 -:1 B:1:-1 -:1 | |
C:4 -:2 C:4 -:2 | |
A:2:-1 G#:2:-1 A:1:-1 -:1 D:3 -:1 C:1 -:1 | |
A:4:-1 -:2 F:6:-1 | |
D:6:-1 G:6:-1 | |
F:8:-1 -:2 F:2:-1 | |
G:2:-1 A:1:-1 A#:2:-1 E:4 D:2 | |
C:6 F:6 | |
E:6 D:6 | |
C:8 -:2 C:2 | |
""" | |
pausa = "-:32 " | |
silencio = "-:1 " | |
melodia = cumpleagnos + pausa | |
melodia += flyme + pausa | |
melodia += ateam + pausa | |
melodia += imperial + pausa | |
melodia += montypython + pausa | |
DURACION_DEFAULT = 4 | |
OCTAVA_DEFAULT = 0 | |
RATE=22050 | |
DURACION_NOTA = 2.0 | |
DEBUG=0 | |
FREQUENCIA_DO_BASE=65.406391325149542 | |
#sonidosCalculados = range(12*5) | |
sonidosCalculados = set([14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 38, 40]) | |
# ------------------------------------------------------------------------------ | |
import pygame | |
import math, sys | |
from itertools import * | |
from functools import reduce | |
import wave | |
import struct | |
import random | |
#--------------------- adsr.py | |
def interpol(X0,X1,Y0,Y1): | |
dX = float(X1)-X0 | |
dY = float(Y1)-Y0 | |
def _interpol(Xn): | |
return float(Xn)*dY/dX + Y0 | |
return _interpol | |
def envelope(t1, t2, t4, l1, l2, l3): | |
def _envelope(dur): | |
inter = interpol(0, dur*t1, 0, l1) | |
for n in range(int(dur*t1)): | |
yield inter(n) | |
inter = interpol(0, dur*t2, l1, l2) | |
for n in range(int(dur*t2)): | |
yield inter(n) | |
inter = interpol(0, dur-dur*(t1+t2+t4), l2, l3) | |
for n in range(int(dur-(dur*(t1+t2+t4)))): | |
yield inter(n) | |
inter = interpol(0, dur*t4, l3, 0) | |
for n in range(int(dur*t4)): | |
yield inter(n) | |
return _envelope | |
BEAT = pygame.USEREVENT + 1 | |
def soundFromSamples(samples): | |
"""A partir de una lista de datos arma un sound de pygame""" | |
data = b"".join([ struct.pack("<h", int(sample)) for sample in samples]) | |
return pygame.mixer.Sound(buffer=data) | |
def square(length, cycle, vol): | |
"""Una onda cuadrada""" | |
samplesPerCycle = RATE / cycle | |
samples = [] | |
for n in range(int(length*RATE)): | |
val = (n%samplesPerCycle) > (samplesPerCycle/2) | |
samples.append( float(val*2-1) * vol ) | |
return samples | |
def triangle(length, cycle, vol): | |
"""Una onda triangular""" | |
samples=[] | |
samplesPerCycle = RATE / cycle | |
for n in range(int(length*RATE)): | |
samples.append( float(n%samplesPerCycle)/samplesPerCycle*vol*2-vol) | |
return samples | |
def noise(length, cycle, vol): | |
"""Ruido blanco/corbata negra""" | |
samples = [] | |
for n in range(int(length*RATE)): | |
samples.append(float(random.randint(int(-vol),int(vol)))) | |
return samples | |
def multiplicarSamples(*a): | |
return [ reduce(float.__mul__, vals) for vals in zip(*a) ] | |
frequencias = {} | |
def buildPiano(piano, onda, envelope): | |
st = 2**(1.0/12) | |
freq = FREQUENCIA_DO_BASE/st | |
for n, mult in zip(range(12*5), cycle([st])): | |
freq *= mult | |
if DEBUG: print(n, n/12, n%12, freq) | |
if n not in sonidosCalculados: | |
continue | |
osc1 = onda(DURACION_NOTA, freq, 0x800) | |
#osc2 = onda(DURACION_NOTA, freq*3.5, 1.5) | |
tonoEnvuelto = multiplicarSamples(osc1, envelope(len(osc1))) | |
#tonoEnvuelto = [ v*e for v, e in zip(samples, envelope(len(samples))) ] | |
piano[n] = soundFromSamples(tonoEnvuelto) | |
frequencias[n] = freq | |
yield None | |
class sequencer: | |
escala = [ 9, 11, 0, 2, 4, 5, 7 ] | |
def __init__(self): | |
self.channel = pygame.mixer.Channel(0) | |
self.melodia = [ "-:32" ] | |
self.instrumento = 0 | |
self.sonidosUsados = set() | |
def setBPS(self, bps): | |
self.bps = bps | |
pygame.time.set_timer(BEAT, int(1000.0/self.bps)) | |
def play(self, melodia, bps=14): | |
self.melodia = [ nota for nota in melodia.split() if nota[0] != "#" and nota.strip() != ""] | |
self.cursor = 0 | |
self.duracion = 0 | |
self.setBPS(bps) | |
def init(self): | |
pygame.time.set_timer(BEAT, 0) | |
ondas = [square, triangle] | |
onda = ondas[self.instrumento%len(ondas)] | |
envelopePiano = envelope(0.01, 0.1, 0.3, 1.0, 0.5, 0.2) | |
self.piano = {} | |
for step in buildPiano(self.piano, onda, envelopePiano): | |
yield step | |
self.cursor = 0 | |
self.duracion = 0 | |
self.instrumento += 1 | |
def getProximaNota(self): | |
nota= self.melodia[self.cursor] | |
partes = nota.split(":") | |
if len(partes) < 2: | |
partes.append(DURACION_DEFAULT) | |
if len(partes) < 3: | |
partes.append(OCTAVA_DEFAULT) | |
self.cursor +=1 | |
return partes | |
def doBeat(self): | |
if self.cursor >= len(self.melodia): | |
self.cursor = 0 | |
if DEBUG: print("sonidos usados: ", self.sonidosUsados) | |
#self.reset() | |
return | |
if self.duracion > 0: | |
self.duracion -= 1 | |
return | |
nota, duracion, octava = self.getProximaNota() | |
print(nota, duracion, octava) | |
self.duracion = int(duracion) - 1 | |
if "-" in nota: | |
self.channel.stop() | |
else: | |
dNota = self.escala[ord(nota[0])-ord("A")] | |
if "#" in nota: | |
dNota += 1 | |
if "b" in nota: | |
dNota -= 1 | |
bNota = 12*(2+int(octava)) | |
nNota = bNota + dNota | |
if DEBUG: print(nota, octava, nNota, frequencias[nNota]) | |
self.sonidosUsados.add(nNota) | |
sound = self.piano[nNota] | |
self.channel.play(sound) | |
def testSequencer(): | |
seq=sequencer() | |
print("sequencer init:") | |
for step in seq.init(): | |
print(".") | |
print("Done!") | |
seq.play(melodia) | |
clock = pygame.time.Clock() | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: | |
sys.exit(1) | |
if event.type == BEAT: | |
seq.doBeat() | |
clock.tick(30) | |
def testSonidos(): | |
pass | |
TIPS_LOADING_TIME = 1000 | |
DEBUG = 0 | |
#VARIABLES CONFIGURABLES DE LA GRILLA | |
GS_X = 10 | |
GS_Y = 15 | |
SW_X = 10 | |
SW_Y = 20 | |
MAX_GRID_HEIGHT = 380.0 | |
MAX_SWAP_WIDTH = 360.0 | |
MOVE_PLACED_PIECES = 1 | |
PIECE_RESIZE = 1 | |
FLASH_COLOR = (255,128,128) | |
PIECE_COLOR = (120,255,120) | |
def getTip(): | |
return random.choice(tips) | |
class Game: | |
def __init__(self, x_size, y_size, framerate=30): | |
pygame.init() | |
self.screen_size = x_size, y_size | |
self.x_size = x_size | |
self.y_size = y_size | |
pygame.mixer.pre_init(RATE, -16, 1, 2048) | |
self.screen = pygame.display.set_mode((x_size, y_size)) | |
pygame.mixer.set_reserved(3) | |
self.framerate = framerate | |
self.clock = pygame.time.Clock() | |
self.seq = sequencer() | |
lastTime = -100000 | |
for step in self.seq.init(): | |
thisTime = pygame.time.get_ticks() | |
if thisTime > lastTime + TIPS_LOADING_TIME: | |
self.showLoading(getTip()) | |
lastTime = thisTime | |
pieceBeepOSC = square(0.1, 440, 0x800) | |
envel = envelope(0.1, 0.2, 0.4, 1.0, 0.8, 0.3) | |
tonoEnvuelto = multiplicarSamples(pieceBeepOSC, envel(len(pieceBeepOSC))) | |
self.pieceBeep = soundFromSamples(tonoEnvuelto) | |
self.channel = pygame.mixer.Channel(4) | |
bonus = triangle(0.1, 300, 0x1200) | |
bonus += triangle(0.1, 700, 0x1200) | |
envel = envelope(0.1, 0.8, 0.9, 0.9, 0.7, 0.3) | |
tonoEnvuelto = multiplicarSamples(bonus, envel(len(bonus))) | |
self.bonusSound = soundFromSamples(tonoEnvuelto) | |
self.bonusChannel = pygame.mixer.Channel(5) | |
pygame.event.clear(pygame.KEYDOWN) | |
def playBeep(self): | |
self.channel.play(self.pieceBeep) | |
def playBonus(self): | |
self.bonusChannel.play(self.bonusSound) | |
def run(self, scene): | |
scene.run( ) | |
if DEBUG: print("FPS:", self.clock.get_fps()) | |
def tick(self): | |
self.clock.tick(self.framerate) | |
def showLoading(self, message=""): | |
self.screen.fill((0,0,0)) | |
font = pygame.font.Font(None, 50) | |
textSurface = font.render("Loading...", 1, (0,102,204)) | |
textRect=textSurface.get_rect() | |
textRect.center= self.screen.get_rect().center | |
textRect.top /= 4 | |
self.screen.blit(textSurface, textRect) | |
font = pygame.font.Font(None, 30) | |
textSurface = font.render(message, 1, (0,102,204)) | |
textRect=textSurface.get_rect() | |
textRect.center= self.screen.get_rect().center | |
textRect.top *= 3.0/4 | |
self.screen.blit(textSurface, textRect) | |
pygame.display.flip() | |
class SceneExit(Exception): | |
pass | |
class Scene: | |
bg_color = (0,0,0) | |
@property | |
def background(self): | |
if self._background is None: | |
self._background = pygame.Surface(self.game.screen.get_size()).convert() | |
self._background.fill(self.bg_color) | |
return self._background | |
def __init__(self, game, *args, **kwargs): | |
self.game = game | |
self._background = None | |
self.allChilds = OrderedUpdates() | |
self.childs = OrderedUpdates() | |
self.init(*args, **kwargs) | |
def init(self): pass | |
def end(self, value=None): | |
self.return_value = value | |
raise SceneExit() | |
def runScene(self, scene): | |
ret = scene.run() | |
if DEBUG: print("Left Scene", str(scene), "with", ret) | |
self.paint() | |
return ret | |
def run(self): | |
if DEBUG: print("Entering Scene:", str(self)) | |
self.game.screen.blit(self.background, (0,0)) | |
self.paint() | |
pygame.display.flip() | |
while 1: | |
self.game.tick() | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: sys.exit() | |
if event.type == BEAT: | |
try: | |
self.game.seq.doBeat() | |
except AttributeError: | |
pygame.time.set_timer(BEAT, 0) | |
else: | |
try: | |
self.event(event) | |
except SceneExit: | |
return self.return_value | |
try: | |
self.loop() | |
except SceneExit: | |
return self.return_value | |
self.allChilds.update() | |
self.allChilds.clear(self.game.screen, self.background) | |
rects = self.allChilds.draw(self.game.screen) | |
pygame.display.update(rects) | |
def event(self, evt): | |
pass | |
def loop(self): | |
pass | |
def update(self): | |
pass | |
def paint(self): | |
pass | |
class Square: | |
def __init__(self, color, rect, border=(0,0,0)): | |
(x1,y1,x2,y2) = rect | |
self.x1 = x1 | |
self.y1 = y1 | |
self.x2 = x2 | |
self.y2 = y2 | |
self.color = color | |
self.last_x_delta = 0 | |
self.last_y_delta = 0 | |
self.last_width = 0 | |
self.border = border | |
def blit(self, surface): | |
newrect = self.make_rect() | |
surface.fill( self.color, newrect ) | |
pygame.draw.rect(surface, self.border, newrect, self.make_width()) | |
def make_width(self): | |
nw = random.randint(0, 5) | |
if nw > self.last_width: | |
self.last_width += 1 | |
else: | |
self.last_width -= 1 | |
return max(self.last_width,1) | |
def make_rect(self): | |
xdelta = random.randint(1,10) | |
if xdelta > self.last_x_delta: | |
self.last_x_delta += 1 | |
else: | |
self.last_x_delta -= 1 | |
ydelta = random.randint(1,10) | |
if ydelta > self.last_y_delta: | |
self.last_y_delta += 1 | |
else: | |
self.last_y_delta -= 1 | |
xdelta = self.last_x_delta | |
ydelta = self.last_y_delta | |
return (self.x1-xdelta, self.y1-ydelta, | |
self.x2-self.x1+xdelta, | |
self.y2-self.y1+ydelta) | |
def contains(self, x, y): | |
if self.x1<=x<=self.x2 and self.y1<=y<=self.y2: | |
return True | |
return False | |
class Mondrian: | |
def __init__(self, x_size, y_size,colors=[(255,255,255), (255,0,0), (255,255,0), (0,0,255)], border=(0,0,0)): | |
self.x_size = x_size | |
self.y_size = y_size | |
self.border = border | |
self.colors=colors | |
self.reset() | |
def reset(self): | |
self.squares = [ Square( random.choice(self.colors),(0,0, self.x_size, self.y_size), border=self.border) ] | |
def select_square(self): | |
x = random.randint(0,int(self.x_size)) | |
y = random.randint(0,int(self.y_size)) | |
for i, sq in enumerate(self.squares): | |
if sq.contains(x,y): | |
return i | |
def select_split(self, start, end): | |
sel = -1 | |
while start>=sel or end<=sel: | |
sel = random.gauss((start+end)/2, (end-start)/8) | |
return sel | |
def split(self): | |
position = self.select_square() | |
s = selection = self.squares[ position ] | |
del self.squares[position] | |
color = random.choice(self.colors) | |
if s.x2-s.x1>s.y2-s.y1: | |
# partimos horizontal | |
part = self.select_split(s.x1, s.x2) | |
self.squares.append(Square(s.color, (s.x1, s.y1,part,s.y2), border=self.border)) | |
self.squares.append(Square(color, (part, s.y1,s.x2,s.y2), border=self.border)) | |
else: | |
# partimos vertical | |
part = self.select_split(s.y1, s.y2) | |
self.squares.append(Square(s.color, (s.x1, s.y1,s.x2,part),border=self.border)) | |
self.squares.append(Square(color, (s.x1, part,s.x2,s.y2),border=self.border)) | |
def blit(self, surface): | |
for square in self.squares: | |
square.blit( surface) | |
def get_image(self): | |
surf = pygame.Surface((self.x_size, self.y_size)) | |
self.blit(surf) | |
return surf | |
class MondrianAS(ActionSprite): | |
def init(self): | |
self.colors = [] | |
colorsteps = 6 | |
step = 255/colorsteps | |
for x in range(colorsteps): | |
for y in range(colorsteps): | |
for z in range(colorsteps): | |
self.colors.append( (x*step, y*step, z*step) ) | |
x,y = self.root.game.screen_size | |
colorset1 = [(255, 255, 255), | |
(255,204,255), | |
(255,153,255), | |
(255,102,255), | |
(255,204,51), | |
(255,153,51), | |
(204,255,255), | |
(204,51,153), | |
(204,204,255), | |
(204,153,255), | |
(255,51,204), | |
(255,102,204), | |
(153,255,255), | |
(153,204,255), | |
] | |
self.mondrian = Mondrian(x,y, colors=colorset1) | |
self.imagen_original = pygame.Surface((x, y)) | |
self.start = pygame.time.get_ticks() | |
self.last = 0 | |
def reset(self): | |
x,y = self.root.game.screen_size | |
self.start = pygame.time.get_ticks() | |
self.last = 0 | |
self.mondrian = Mondrian(x,y, colors = random.sample(self.colors, random.randint(0,len(self.colors)-1))) | |
def onEnterFrame(self): | |
if math.log( pygame.time.get_ticks() - self.start +1) > self.last + 0.15: | |
self.last = math.log( pygame.time.get_ticks() - self.start+1 ) | |
self.mondrian.split() | |
self.mondrian.blit(self.lastImage) | |
#self.dirty = True | |
class ActionTile(ActionSprite): | |
def __init__(self, parent, x, y, width, height, color, isLeft, isTop): | |
self.isLeft = isLeft | |
self.isTop = isTop | |
self.frozen = 0 | |
ActionSprite.__init__(self, parent=parent, x=x, y=y, width=width, height=height, color=color) | |
def _setColor(self, value): | |
self.__dict__['color'] = value | |
self.dirty = True | |
def _getColor(self): | |
return self.__dict__.get('color') | |
color = property(_getColor, _setColor) | |
def _draw(self): | |
#Obtener las medidas, rotacion y posicion definitivas para dibujar | |
self.rect.left = self._getDrawingX() | |
self.rect.top = self._getDrawingY() | |
width = self._getDrawingWidth() | |
height = self._getDrawingHeight() | |
#dibujamos la imagen | |
if not self.dirty: | |
self.image = self.lastImage | |
return | |
self.image = pygame.transform.scale(self.imagen_original, (width, height)) | |
self.image.fill(self.color) | |
w = 1 | |
claro = (255,255,255) | |
oscuro = (50,50,50) | |
contorno = (0,0,0) | |
if self.frozen: | |
contorno = claro | |
if self.isLeft: | |
bordeLeft = contorno | |
else: | |
bordeLeft = claro | |
if self.isTop: | |
bordeTop = contorno | |
else: | |
bordeTop = claro | |
pygame.draw.line(self.image, oscuro, (width-w,0), (width-w, height-w),w) | |
pygame.draw.line(self.image, oscuro, (0,height-w), (width-w, height-w),w) | |
pygame.draw.line(self.image, bordeLeft, (0,0), (0, height-w),w) | |
pygame.draw.line(self.image, bordeTop, (0,0), (width-w, 0),w) | |
self.image.set_alpha(255) | |
self.lastImage = self.image | |
self.dirty = False | |
class PieceAS(ActionSprite): | |
NORMAL, FLASHING, PLACING, PLACED, DEAD = range(5) | |
def __init__(self, parent, piece, x, y, scale, urgency, life): | |
self.piece = piece | |
x_size, y_size = piece.getSize() | |
w = x_size * scale | |
h = y_size * scale | |
self.flash_color = FLASH_COLOR | |
self.flash_duration = 200 | |
self.last = pygame.time.get_ticks() | |
self.creation = pygame.time.get_ticks() | |
self.urgency = urgency | |
self.life = life | |
self.state = self.NORMAL | |
self.piece = piece | |
self.piece_color = PIEZA | |
self.scale = scale | |
ActionSprite.__init__(self, parent=parent, x=x, y=y, width=w, height=h) | |
self._paintTiles() | |
def freeze(self): | |
for t in self.tiles: | |
t.frozen = 1 | |
def _paintTiles(self): | |
self.tiles = [] | |
scale = self.scale | |
for x,y in self.piece.tiles(): | |
if (x-1, y) not in self.piece.tiles(): | |
left = True | |
else: | |
left = False | |
if (x, y-1) not in self.piece.tiles(): | |
top = True | |
else: | |
top = False | |
a = ActionTile(self, x= x*scale, y= y*scale, width=scale, height=scale, color=self.piece_color, isLeft=left, isTop=top) | |
self.tiles += [a] | |
self.set_color(self.piece_color) | |
def _repaintTiles(self): | |
self._killTiles() | |
self._paintTiles() | |
def set_scale(self, scale): | |
self.scale = scale | |
self.dirty = True | |
self._repaintTiles() | |
def rotate(self): | |
self.piece.rotate() | |
self._repaintTiles() | |
def _killTiles(self): | |
for t in self.tiles: | |
t.kill() | |
def set_color(self, color): | |
for t in self.tiles: | |
t.color = color | |
def onEnterFrame(self): | |
total_time = pygame.time.get_ticks() - self.creation | |
elapsed = pygame.time.get_ticks() - self.last | |
if self.state == self.NORMAL: | |
if total_time > self.urgency: | |
tick = 200 | |
elif total_time > self.urgency*0.8: | |
tick = 400 | |
elif total_time > self.urgency*0.5: | |
tick = 800 | |
else: | |
tick = 0 | |
if tick and elapsed > tick: | |
# DO TICK | |
self.root.game.playBeep() | |
self.root.patience -= 1 | |
self.set_color(self.flash_color) | |
self.state = self.FLASHING | |
self.last = pygame.time.get_ticks() | |
self.dirty = True | |
elif self.state == self.FLASHING: | |
if elapsed > self.flash_duration: | |
self.set_color( self.piece_color) | |
self.dirty = True | |
self.state = self.NORMAL | |
self.last = pygame.time.get_ticks() | |
elif self.state == self.PLACING: | |
self.set_color( self.piece_color) | |
self.dirty = True | |
self.state = self.PLACED | |
self.last = pygame.time.get_ticks() | |
elif self.state == self.PLACED: | |
if self.life != 0 and elapsed > self.life: | |
#self.set_color( (1,255,255)) | |
self.dirty = True | |
self.grid.remove(self.piece) | |
self.state = self.DEAD | |
self.kill() | |
def place(self, where): | |
self.state = self.PLACING | |
self.grid = where | |
class SlotAS(ActionSprite): | |
bg_color = (255,255,255,255) | |
def init(self): | |
#self.image = None | |
#self.imagen_original = None | |
#self.imagen_original = pygame.Surface( (10,1)) | |
self.piece = None | |
def add_piece(self, piece, urgency, life): | |
sz = self.width/max(piece.getSize()) | |
if PIECE_RESIZE: | |
sz = self.width/max(self.size) | |
self.piece = PieceAS(self, piece, 0, 0, sz, urgency, life) | |
def empty(self): | |
return (self.piece is None) | |
if not PIECE_RESIZE: | |
def inside(self, x, y): | |
if self.piece.inside(x, y): | |
return True | |
return False | |
def take(self): | |
p = self.piece | |
self.piece = None | |
return p | |
class NextPieces(ActionSprite): | |
def init(self): | |
self.margin = 10 | |
self.slot_size = self.height - self.margin*2 | |
self.slots = [] | |
self.empty_slots = [] | |
self.imagen_original.fill( (102, 102, 204) ) | |
for i in range(int((self.width-self.margin)/(self.slot_size+self.margin))): | |
ny = self.margin | |
nx = self.margin+(self.margin+self.slot_size)*i | |
s = SlotAS(self, nx, ny, self.slot_size, self.slot_size) | |
self.empty_slots.append(s) | |
self.slots.append(s) | |
self.empty_slots.reverse() | |
self.last = 0 | |
def has_space(self): | |
return len(self.empty_slots)>0 | |
def empty_p(self): | |
return len(self.empty_slots)==len(self.slots) | |
def get_free(self): | |
return self.empty_slots.pop() | |
def pickup(self, x,y): | |
for s in self.slots: | |
if not s.empty(): | |
if s.inside(x,y): | |
return s | |
def release(self, slot): | |
slot.take() | |
self.empty_slots.append(slot) | |
class TextAS(ActionSprite): | |
def __init__(self, parent, sample_text, text_size, x, y, color=(1,1,1)): | |
self.font = pygame.font.Font(None, text_size) | |
self.font_size = text_size | |
self.text_color = color | |
self.orig_x = x | |
self.orig_y = y | |
ActionSprite.__init__(self, parent,x,y,1,1 ) | |
self.set_text(sample_text) | |
def get_coords(self): | |
return (self.orig_x,self.orig_y, | |
self.imagen_original.get_width(), | |
self.imagen_original.get_height()) | |
def set_text(self, text): | |
self.imagen_original = self.font.render(text, 1,self.text_color) | |
x,y, xz, yz = self.get_coords() | |
self.height = yz | |
self.width = xz | |
self.x = x | |
self.y = y | |
class CenteredTextMixin: | |
def get_coords(self): | |
return (self.orig_x-self.imagen_original.get_width()/2, | |
self.orig_y-self.imagen_original.get_height()/2, | |
self.imagen_original.get_width(), | |
self.imagen_original.get_height()) | |
class CenteredTextAS(CenteredTextMixin, TextAS): | |
pass | |
class PropertyTextAS(TextAS): | |
def __init__(self, parent, label, prop_name, text_size, x, y, color=(1,1,1)): | |
self.label = label | |
self.prop_name = prop_name | |
TextAS.__init__(self, parent, label, text_size, x,y,color) | |
self.last_value = None | |
def onEnterFrame(self): | |
val = getattr(self.root, self.prop_name) | |
if val != self.last_value: | |
self.set_text(self.label+str(val)) | |
self.last_value = val | |
class BaseLevel(Scene): | |
level_length = 150 | |
bg_color = (255,255,255) | |
FREE, PICKUP, DRAG = range(3) | |
grid_size = (15,10) | |
patience = 100 | |
def init(self, score=0): | |
self.game.seq.play(flyme,16) | |
self.state = self.FREE | |
self.score = score | |
self.over = None | |
self.level = "One" | |
#GRilla de pieza | |
self.memory = ASGrid(self, 5, 185, self.grid_size[0], self.grid_size[1]) | |
scale = self.memory.height / MAX_GRID_HEIGHT | |
self.memory.width /= scale | |
self.memory.height /= scale | |
nx = int((self.game.x_size-self.memory.width)/2) | |
ny = int((self.game.y_size*(3.0/4.0)-self.memory.height)/2)+self.game.y_size/4 | |
self.memory.x = nx | |
self.memory.y = ny | |
#Espacio de swap | |
#self.swap = ASGrid(self, 615, 195, SW_X, SW_Y, (22,122,223)) | |
# scale = self.swap.height / MAX_SWAP_WIDTH | |
#self.swap.width /= scale | |
#self.swap.height /= scale | |
self.timeleft = self.level_length | |
self.second_tick = pygame.time.get_ticks() | |
self.last = pygame.time.get_ticks() | |
self.next = NextPieces(self, | |
0, self.game.y_size/8, | |
self.game.x_size, self.game.y_size/8) | |
self.scoreas = PropertyTextAS(self, "Score: ","score", 30, 10,10, | |
color=(1,1,1)) | |
self.levelas = PropertyTextAS(self, "", "fullName", 30, 10,45, | |
color=(1,1,1)) | |
self.patienceas = PropertyTextAS(self, "Patience: ", "patience", | |
30, self.game.x_size/2,10, | |
color=(1,1,1)) | |
self.timeleftas = PropertyTextAS(self, "Time Left: ", "timeleft", | |
30, self.game.x_size/2,45, | |
color=(1,1,1)) | |
def event(self, evt): | |
if evt.type == pygame.MOUSEMOTION: | |
over = None | |
for w in [self.next, self.memory]:#, self.swap]: | |
if w.inside( *evt.pos ): | |
over = w | |
if over != self.over: | |
self.over = over | |
if self.state == self.PICKUP: | |
self.piece.piece_color=PIECE_COLOR | |
self.piece.set_color(self.piece.piece_color) | |
if over==self.next: | |
scale = over.slot_size/max(self.piece.piece.getSize()) | |
print('max: ',max(self.piece.piece.getSize())) | |
print('scale: ', scale) | |
elif over in ( self.memory ,):#, self.swap ): | |
scale = over.getTileSize() | |
self.piece.dragging = False | |
else: | |
self.piece.dragging = True | |
scale = 30 | |
self.piece.set_scale(scale) | |
if evt.type == pygame.KEYDOWN and evt.key == pygame.K_ESCAPE: | |
self.end(("lose", self.score)) | |
elif self.state == self.FREE: | |
if evt.type == pygame.MOUSEBUTTONDOWN and evt.button==1: | |
if self.next.inside( *evt.pos ): | |
self.slot = slot = self.next.pickup( *evt.pos ) | |
if slot is not None: | |
self.state = self.PICKUP | |
self.piece = slot.piece | |
#piece.set_scale( 30 ) | |
self.piece.dragging = True | |
elif self.memory.inside( *evt.pos ): | |
if MOVE_PLACED_PIECES: | |
(xm, ym), (x,y) = self.memory.getCoords() | |
if not self.memory.frozen( int(xm), int(ym) ): | |
piece = self.memory.as_piece_at( int(xm), int(ym) ) | |
if piece: | |
piece.set_color(PIECE_COLOR) | |
self.piece = piece | |
self.state = self.DRAG | |
self.memory.remove( piece.piece ) | |
elif self.state == self.DRAG: | |
if evt.type == pygame.KEYDOWN and evt.key == pygame.K_SPACE or evt.type == pygame.MOUSEBUTTONDOWN and evt.button==3: | |
self.piece.rotate() | |
elif evt.type == pygame.MOUSEMOTION and self.over == self.memory: | |
(xm, ym), (x,y) = self.memory.getCoords() | |
self.piece.x = -self.piece.parent._getDrawingX()+x | |
self.piece.y = -self.piece.parent._getDrawingY()+y | |
elif evt.type == pygame.MOUSEBUTTONDOWN and evt.button==1: | |
if self.over == self.memory: | |
(xm, ym), (x,y) = self.memory.getCoords() | |
try: | |
self.piece.set_color(self.piece.piece_color) | |
self.piece.piece_color=PIEZA | |
newscore = (self.memory.put( self.piece, (int(xm), int(ym)))) | |
if newscore!=0: | |
self.game.playBonus() | |
self.score += newscore | |
self.state = self.FREE | |
self.piece.place(self.memory) | |
self.piece = None | |
except GExp: | |
pass | |
elif self.state == self.PICKUP: | |
if evt.type == pygame.KEYDOWN and evt.key == pygame.K_SPACE or evt.type == pygame.MOUSEBUTTONDOWN and evt.button==3: | |
self.piece.rotate() | |
elif evt.type == pygame.MOUSEMOTION and self.over == self.memory: | |
(xm, ym), (x,y) = self.memory.getCoords() | |
self.piece.x = -self.piece.parent._getDrawingX()+x | |
self.piece.y = -self.piece.parent._getDrawingY()+y | |
elif evt.type == pygame.MOUSEBUTTONDOWN and evt.button==1: | |
# drop | |
if self.over == self.next: | |
self.piece.piece_color=PIEZA | |
self.piece.set_color(self.piece.piece_color) | |
self.piece.dragging = False | |
self.piece.x = 0 | |
self.piece.y = 0 | |
self.piece = None | |
self.slot = None | |
self.state = self.FREE | |
elif self.over == self.memory: | |
(xm, ym), (x,y) = self.memory.getCoords() | |
try: | |
self.piece.set_color(self.piece.piece_color) | |
self.piece.piece_color=PIEZA | |
newscore = (self.memory.put( self.piece, (int(xm), int(ym)))) | |
if newscore!=0: | |
self.game.playBonus() | |
self.score += newscore | |
self.state = self.FREE | |
self.piece.place(self.memory) | |
self.next.release(self.slot) | |
self.piece.dragging = False | |
self.piece = None | |
self.slot = None | |
except GExp: | |
pass | |
def loop(self): | |
if self.patience < 1: | |
self.end( ("lose", self.score) ) | |
if (self.add_piece_p() or | |
self.next.empty_p()): | |
if self.next.has_space(): | |
slot = self.next.get_free() | |
self.add_piece(slot) | |
if pygame.time.get_ticks()-self.second_tick > 1000: | |
self.timeleft -= 1 | |
self.second_tick = pygame.time.get_ticks() | |
if self.timeleft < 1: | |
self.end( ("win", self.score) ) | |
def add_piece_p(self): | |
return (pygame.time.get_ticks() - self.last > 1500) | |
def add_piece(self, slot): | |
self.last = pygame.time.get_ticks()+random.randint(0,2500) | |
xz = 3 | |
yz = 3 | |
pz = random.randint(1, int(xz*yz/2)) | |
slot.size=(xz,yz) | |
slot.add_piece(PieceString(mkpiece(xz, yz, pz)), random.gauss(5000, 10000), random.gauss(100000, 10000)) | |
name = "Sample Level" | |
class LevelGranny(BaseLevel): | |
name = "Granny using a Cray" | |
level_length = 30 | |
patience = 500 | |
grid_size = (20,10) | |
def add_piece(self, slot): | |
self.last = pygame.time.get_ticks()+random.randint(0,5000) | |
xz = 2 | |
yz = 2 | |
pz = random.randint(1, int(xz*yz/2)) | |
slot.size=(xz,yz) | |
slot.add_piece(PieceString(mkpiece(xz, yz, pz)), 11000, random.gauss(120000, 20000)) | |
class LevelIntermedio(LevelGranny): | |
name = "pw in your 486" | |
level_length = 50 | |
patience = 200 | |
def add_piece(self, slot): | |
self.last = pygame.time.get_ticks()+random.randint(0,5000) | |
xz = 3 | |
yz = 3 | |
pz = random.randint(1, int(xz*yz/2)) | |
slot.size=(xz,yz) | |
slot.add_piece(PieceString(mkpiece(xz, yz, pz)), 11000, random.gauss(120000, 20000)) | |
class LevelWindowsForWorkgroups(BaseLevel): | |
name = "WFW3.11 on an AMD64" | |
level_length = 120 | |
patience = 150 | |
grid_size = (15,10) | |
class LevelPrime95(BaseLevel): | |
name = "prime95 on your pda" | |
level_length = 150 | |
patience = 300 | |
grid_size = (20,10) | |
def add_piece_p(self): | |
return (pygame.time.get_ticks() - self.last > 1500) | |
def add_piece(self, slot): | |
self.last = pygame.time.get_ticks()+random.randint(0,1000) | |
xz = 4 | |
yz = 4 | |
pz = random.randint(1, int(xz*yz/2)) | |
slot.size=(xz,yz) | |
slot.add_piece(PieceString(mkpiece(xz, yz, pz)), 11000, random.gauss(120000, 20000)) | |
class LevelSpeccy(LevelPrime95): | |
name = "seti@home on a speccy" | |
level_length = 1200 | |
grid_size = (5,10) | |
patience = 300 | |
class Intro(Scene): | |
levels = [ | |
LevelGranny, | |
LevelIntermedio, | |
LevelWindowsForWorkgroups, | |
LevelPrime95, | |
LevelSpeccy, | |
] | |
def init(self): | |
self.game.seq.play(montypython,14) | |
self.mas = MondrianAS(self, 0,0,self.game.x_size, self.game.y_size) | |
self.title = CenteredTextAS(self.mas, | |
"Alocado Alocador!", 80, | |
self.game.x_size/2, self.game.y_size/4, color=(0,51,102)) | |
self.title = CenteredTextAS(self.mas, | |
"(crazy allocator)", 50, | |
self.game.x_size/2, (self.game.y_size/4)*1.5, color=(0,51,102)) | |
self.subtitle = CenteredTextAS(self.mas, | |
"escape to exit, any other key to play", 40, | |
self.game.x_size/2, (self.game.y_size/4)*3, color=(0,51,102)) | |
def paint(self): | |
self.game.screen.fill((0,255,0)) | |
def event(self, evt): | |
if evt.type == pygame.KEYDOWN and evt.key == pygame.K_ESCAPE: | |
self.end() | |
if evt.type == pygame.KEYDOWN and evt.key != pygame.K_ESCAPE: | |
score = 0 | |
result = None | |
for nLevel, level in enumerate(self.levels): | |
level.number = nLevel+1 | |
level.fullName = "%d) %s"%(nLevel+1, level.name) | |
self.runScene(LevelStarting(self.game, level.fullName)) | |
result, score = self.runScene(level(self.game, score)) | |
if result == "lose": | |
break | |
self.runScene(LevelComplete(self.game, level.name)) | |
if result == "lose": | |
self.runScene(Gameover(self.game, score)) | |
else: | |
self.runScene(Message(self.game, "You have cheated!", ateam)) | |
self.game.seq.play(montypython,14) | |
class Message(Scene): | |
def event(self, evt): | |
if evt.type == pygame.KEYDOWN: | |
self.end() | |
def init(self, message, melodia=silencio, bps=14): | |
self.game.seq.play(melodia, bps) | |
self.title = CenteredTextAS(self, | |
message, 80, | |
self.game.x_size/2, self.game.y_size/2, color=(0,102,204)) | |
class LevelStarting(Message): | |
def init(self, levelName): | |
Message.init(self, levelName) | |
self.subtitle = CenteredTextAS(self, getTip(), 30, | |
self.game.x_size/2, (self.game.y_size/4)*3, color=(0,102,204)) | |
class LevelComplete(Message): | |
def init(self, levelName): | |
Message.init(self, "Level Completed!") | |
self.title = CenteredTextAS(self, | |
levelName, 60, | |
self.game.x_size/2, self.game.y_size/4, color=(0,102,204)) | |
self.game.seq.play(ateam, 16) | |
class Gameover(Scene): | |
def event(self, evt): | |
if evt.type == pygame.KEYDOWN: | |
self.end() | |
def init(self, score): | |
self.game.seq.play(imperial, 16) | |
self.title = CenteredTextAS(self, | |
"Game Over", 80, | |
self.game.x_size/2, self.game.y_size/2, color=(0,51,102)) | |
self.score = CenteredTextAS(self, | |
"score: "+str(score), 50, | |
self.game.x_size/2, (self.game.y_size/4)*3, color=(0,51,102)) | |
if __name__ == "__main__": | |
g = Game(800, 600) | |
g.run( Intro(g) ) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment