Browse Source

Merge branch 'master' of blinkenbunt:gitrepos/blup3

feature/balanceutils
klonfish 7 years ago committed by klonfish
parent
commit
40a2a9e2c0
  1. 12
      blup/output.py
  2. 2
      miniplayer.py
  3. 28
      sd_to_hd.py
  4. 303
      ttrs.py
  5. 2
      writebml.py

12
blup/output.py

@ -331,10 +331,10 @@ class BLPOutput(Output): @@ -331,10 +331,10 @@ class BLPOutput(Output):
#
class BlinkenbuntHDOutput(Output):
moduleRegexDesc = 'bbunthd'
moduleRegex = '^bbunthd$'
moduleRegexDesc = 'bbunthd[:BRIGHTNESS]'
moduleRegex = '^bbunthd(:(?P<brightness>\d+))?$'
def __init__(self):
def __init__(self, brightness):
import neopixel
self.w = 22
self.h = 16
@ -342,20 +342,20 @@ class BlinkenbuntHDOutput(Output): @@ -342,20 +342,20 @@ class BlinkenbuntHDOutput(Output):
LED_PIN = 13
LED_FREQ_HZ = 800000
LED_DMA = 5
LED_BRIGHTNESS = 50
LED_INVERT = False
LED_PWM = 1
self.strip = neopixel.Adafruit_NeoPixel(
LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT,
LED_BRIGHTNESS, LED_PWM
brightness, LED_PWM
)
self.strip.begin()
self._color_cls = neopixel.Color
@classmethod
def fromRegexMatch(cls, regexMatch):
return cls()
b = int(regexMatch.groupdict().get('brightness', 50))
return cls(brightness=b)
def sendFrame(self, frame):
for y in range(self.h):

2
miniplayer.py

@ -104,7 +104,7 @@ class MiniPlayer(object): @@ -104,7 +104,7 @@ class MiniPlayer(object):
# play the animation in case it had been successfully loaded before
if currentAnim is not None:
if currentAnim.duration < self.loopTime:
count = self.loopTime / currentAnim.duration
count = self.loopTime // currentAnim.duration
else:
count = 1
player.play(currentAnim, self.__output, count=count)

28
sd_to_hd.py

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
#!/usr/bin/env python3
import blup.frame
import blup.animation
import writebml
import sys
if len(sys.argv) != 3:
print('usage: %s INFILE OUTFILE' % (sys.argv[0]), file=sys.stderr)
sys.exit(1)
infname = sys.argv[1]
outfname = sys.argv[2]
anim = blup.animation.load(infname)
dim = blup.frame.FrameDimension(22, 16, 256, 3)
newanim = blup.animation.Animation(dim)
for f in anim:
newf = blup.animation.AnimationFrame(dim, f.delay)
for x in range(f.dimension.width):
for y in range(f.dimension.height):
newf.setPixel(x + 2, y*2, tuple(map(lambda x: int((x/anim.dimension.depth)*dim.depth), f.getPixel(x, y))))
newf.setPixel(x + 2, y*2 + 1, tuple(map(lambda x: int((x/anim.dimension.depth)*dim.depth), f.getPixel(x, y))))
newanim.addFrame(newf)
writebml.writeBml(newanim, outfname)

303
ttrs.py

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
#!/usr/bin/env python3
import argparse
import sys
import socket
import struct
import time
@ -9,6 +11,7 @@ import collections @@ -9,6 +11,7 @@ import collections
import blup.frame
import blup.output
import random
import threading
class InvalidMoveError(Exception):
@ -183,146 +186,110 @@ class Playground(): @@ -183,146 +186,110 @@ class Playground():
continue
frame.setPixel(xpos + int(b.pos.x), ypos + int(b.pos.y), b.color)
PlayerEvent = enum.Enum('PlayerEvent', ['ROTATE', 'DROP', 'MOVE_LEFT',
'MOVE_RIGHT', 'QUIT'])
class TtrsPlayer():
def __init__(self, playground):
pass
def get_move(self, minopos):
return 0
def get_drop(self):
return False
def get_rotate(self):
return False
def get_event(self):
return None
def get_quit(self):
return False
class TestTtrsPlayer(TtrsPlayer):
def __init__(self, playground):
self.playground = playground
self.__move = 0
self.__drop = False
self.__rotate = False
self.__quit = False
self.__evt = None
import pygame
self.__pygame = pygame
self.screen = pygame.display.set_mode((100, 100))
pygame.display.update()
def __process_events(self):
self.controls = {
pygame.K_a: PlayerEvent.MOVE_LEFT,
pygame.K_d: PlayerEvent.MOVE_RIGHT,
pygame.K_w: PlayerEvent.ROTATE,
pygame.K_s: PlayerEvent.DROP,
pygame.K_ESCAPE: PlayerEvent.QUIT,
}
#self.controls = {
# pygame.K_LEFT: PlayerEvent.MOVE_LEFT,
# pygame.K_RIGHT: PlayerEvent.MOVE_RIGHT,
# pygame.K_UP: PlayerEvent.ROTATE,
# pygame.K_DOWN: PlayerEvent.DROP,
# pygame.K_ESCAPE: PlayerEvent.QUIT,
#}
def get_event(self):
pygame = self.__pygame
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
self.__move = -1
elif event.key == pygame.K_d:
self.__move = 1
elif event.key == pygame.K_w:
self.__rotate = True
elif event.key == pygame.K_s:
self.__drop = True
elif event.key == pygame.K_ESCAPE:
self.__quit = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_d:
self.__move = 0
elif event.key == pygame.K_w:
self.__rotate = False
elif event.key == pygame.K_s:
self.__drop = False
def get_move(self, minopos):
self.__process_events()
return self.__move
def get_drop(self):
self.__process_events()
return self.__drop
def get_rotate(self):
self.__process_events()
return self.__rotate
def get_quit(self):
self.__process_events()
return self.__quit
def reset_rotate(self):
pass
return self.controls.get(event.key, None)
return None
class BalanceTtrsPlayer(TtrsPlayer):
class BalanceTtrsPlayer(TtrsPlayer, threading.Thread):
def __init__(self, playground, addr, player_id):
self.playground = playground
self.player_id = player_id
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect(addr)
def __update_balance(self):
self.sock.send(b'a')
data = self.sock.recv(4)
p1x, p1y, p2x, p2y = struct.unpack('bbbb', data)
if self.player_id == 0:
self.xbal = p1x
self.ybal = p1y
elif self.player_id == 1:
self.xbal = p2x
self.ybal = p2y
def reset_rotate(self):
self.__rotate_reset = True
self.__rotate = False
def get_move(self, minopos):
self.__update_balance()
#if p1x > 40:
# self.__move = 1
#elif p1x < -40:
# self.__move = -1
#elif p1x > -20 and p1x < 20:
# self.__move = 0
threading.Thread.__init__(self, daemon=True)
self.start()
def run(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(addr)
self.running = True
while self.running:
sock.send(b'a')
data = sock.recv(4)
p0x, p0y, p2x, p2y = struct.unpack('bbbb', data)
if self.player_id == 0:
self.__calc_event(p0x, p0y)
elif self.player_id == 1:
self.__calc_event(p1x, p1y)
time.sleep(0.01)
def __calc_event(self, xbal, ybal):
if self.ybal > 50:
return PlayerEvent.ROTATE
MAX_Y_AMPLITUDE = 65
bal = self.xbal
normbal = (bal + MAX_Y_AMPLITUDE) / (2 * MAX_Y_AMPLITUDE)
px = round(normbal * (self.playground.width - 1))
print('player %d balance=%d pos=%d' % (self.player_id, bal, px))
if minopos.x > px:
return -1
return PlayerEvent.MOVE_LEFT
elif minopos.x < px:
return 1
else:
return 0
def get_drop(self):
self.__update_balance()
return (self.ybal < -50)
return PlayerEvent.MOVE_RIGHT
def get_rotate(self):
self.__update_balance()
if self.ybal > 50 and not self.__rotate_reset:
return True
elif self.ybal < 35:
self.__rotate_reset = False
return False
def get_quit(self):
self.__update_balance()
return (self.xbal == -128 or self.ybal == -128)
if self.ybal < -50:
return PlayerEvent.DROP
class TtrsGame():
def __init__(self, playground, player):
class TtrsGame(threading.Thread):
def __init__(self, playground, player, rnd=None):
self.playground = playground
self.player = player
if rnd is None:
self.rnd = random.Random()
else:
self.rnd = rnd
self.running = False
self.tick_callbacks = []
threading.Thread.__init__(self, daemon=True)
def add_tick_callback(self, cb):
self.tick_callbacks.append(cb)
def __call_callbacks(self):
for cb in self.tick_callbacks:
cb(self)
def run(self):
self.running = True
spawnpos = Point(self.playground.width // 2, -1)
@ -333,18 +300,24 @@ class TtrsGame(): @@ -333,18 +300,24 @@ class TtrsGame():
ticks = 0
lastfall = 0
lastmove = 0
dropping = False
top_row = { Point(x, -1) for x in range(self.playground.height) }
while self.running:
for cb in self.tick_callbacks:
cb()
self.__call_callbacks()
time.sleep(TICK_TIME)
ticks += 1
if self.player.get_quit():
evt = self.player.get_event()
if evt == PlayerEvent.QUIT:
self.running = False
break
if not self.playground.block_points.isdisjoint(top_row):
self.running = False
break
if mino is None:
newminocls = random.choice(Tetrimino.__subclasses__())
newminocls = self.rnd.choice(Tetrimino.__subclasses__())
mino = newminocls(self.playground, spawnpos)
self.playground.minos = {mino}
@ -366,13 +339,11 @@ class TtrsGame(): @@ -366,13 +339,11 @@ class TtrsGame():
for i in range(2):
for b in to_delete:
self.playground.blocks.add(b)
for cb in self.tick_callbacks:
cb()
self.__call_callbacks()
time.sleep(0.2)
for b in to_delete:
self.playground.blocks.remove(b)
for cb in self.tick_callbacks:
cb()
self.__call_callbacks()
time.sleep(0.2)
to_add = set()
@ -384,7 +355,7 @@ class TtrsGame(): @@ -384,7 +355,7 @@ class TtrsGame():
to_add.add(newb)
self.playground.blocks.update(to_add)
if ticks - lastfall >= FALL_INTERVAL or self.player.get_drop():
if ticks - lastfall >= FALL_INTERVAL or evt == PlayerEvent.DROP:
lastfall = ticks
try:
mino.move(Point(0, 1))
@ -394,60 +365,96 @@ class TtrsGame(): @@ -394,60 +365,96 @@ class TtrsGame():
self.playground.minos = set()
continue
move = self.player.get_move(mino.pos)
if ticks - lastmove >= MOVE_INTERVAL and move != 0:
lastmove = ticks
if ticks - lastmove >= MOVE_INTERVAL:
try:
mino.move(Point(move, 0))
if evt == PlayerEvent.MOVE_LEFT:
mino.move(Point(-1, 0))
lastmove = ticks
elif evt == PlayerEvent.MOVE_RIGHT:
mino.move(Point(1, 0))
lastmove = ticks
except InvalidMoveError:
pass
if self.player.get_rotate():
if evt == PlayerEvent.ROTATE:
try:
mino.rotate()
self.player.reset_rotate()
except InvalidMoveError:
pass
if __name__ == '__main__':
w = 22
h = 16
dim = blup.frame.FrameDimension(w, h, 256, 3)
frame = blup.frame.Frame(dim)
out = blup.output.getOutput('e3blp:blinkenbunt:2342')
pg = Playground(10, 16)
def repaint(pg):
pg.paint(frame, 0, 0)
out.sendFrame(frame)
time.sleep(0.5)
def repaint():
pg.paint(frame, 0, 0)
out.sendFrame(frame)
#player = TestTtrsPlayer(pg)
player = BalanceTtrsPlayer(pg, ('blinkenbunt', 4711), 0)
game = TtrsGame(pg, player)
game.add_tick_callback(repaint)
game.run()
#t = TetriL(pg, Point(2, 2))
#pg.minos.add(t)
#pg.paint(frame, 0, 0)
#out.sendFrame(frame)
#time.sleep(0.5)
#for i in range(10):
# t.rotate(ccw=(i>=5))
# pg.paint(frame, 0, 0)
# out.sendFrame(frame)
# time.sleep(0.1)
class GamePlaygroundPainter():
def __init__(self, output, dimension):
self.output = output
self.games = {}
self.frame = blup.frame.Frame(dimension)
bgcolor = (100, 100, 100)
for x in range(dimension.width):
for y in range(dimension.height):
self.frame.setPixel(x, y, bgcolor)
def add_game(self, game, xpos, ypos):
game.add_tick_callback(self.repaint)
self.games[game] = (xpos, ypos)
def repaint(self, game):
xpos, ypos = self.games[game]
game.playground.paint(self.frame, xpos, ypos)
self.output.sendFrame(self.frame)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Blinkenbunt Tetris!')
parser.add_argument('--players', dest='players', type=int, default=1,
help='number of players')
parser.add_argument('--pygame', dest='pygame', action='store_true',
help='use pygame as input')
parser.add_argument('--balance', dest='balance', type=str, nargs=1,
metavar='HOST:PORT', help='use balance input')
parser.add_argument('--out', dest='out', type=str, metavar='OUTPUT',
default='e3blp', help='blup output specification')
args = parser.parse_args()
if args.balance is None and not args.pygame:
print('please specify an input method', file=sys.stderr)
sys.exit(1)
if args.pygame and args.players == 2:
print('pygame input does only support one player', file=sys.stderr)
sys.exit(1)
w = 22
h = 16
out = blup.output.getOutput(args.out)
dim = blup.frame.FrameDimension(w, h, 256, 3)
painter = GamePlaygroundPainter(out, dim)
seed = random.random()
games = []
def start_game(player_id, xpos):
pg = Playground(10, 16)
if args.pygame:
player = TestTtrsPlayer(pg)
elif args.balance is not None:
host, port = args.balance.split(':')
player = BalanceTtrsPlayer(pg, (host, int(port)), player_id)
rnd = random.Random(seed)
game = TtrsGame(pg, player, rnd)
painter.add_game(game, xpos, 0)
game.start()
games.append(game)
if args.players == 1:
start_game(0, 6)
elif args.players == 2:
start_game(0, 0)
start_game(1, 12)
for game in games:
game.join()

2
writebml.py

@ -12,7 +12,7 @@ def writeBml(anim, filename): @@ -12,7 +12,7 @@ def writeBml(anim, filename):
root.attrib['channels'] = str(anim.dimension.channels)
header = ET.Element('header')
for (name, val) in anim.tags:
for (name, val) in anim.tags.items():
elem = ET.Element(name)
elem.text = str(val)
header.append(elem)

Loading…
Cancel
Save