2020/NOV/30
風が秋めいてきた今日この頃に、遠い昔の記憶。 コンピュータクラブの学園祭展示の準備に追われたあの頃。
テテリス に続き、 8ビットCPUのパソコンで、 キャラクタ端末で動作する「パックマンもどき」をC言語で書いてました。
頑張って思い出して、Pythonで書いてみました。
例によってクロージャ多用なソースになってます。
まだまだ動きが怪しいので、ぼちぼち改良してみます。
スマホでページを開いて、動画の画面コピーをとり、 画質を調整してみました。
キャラクタ端末で、エスケープシーケンスを使って、 「もどき」な画面なのに、とってもそれらしい感じです。
ページを 簡易なおれおれマークダウン 2019秋の使用例 の形式で書き直してみたついでに、追加してみました。
お写真
$ chmod +x pac.py $ tar xzf pac_data.tgz $ ./pac.py
v2.patch
diff -ur v1/kon.py v2/kon.py
--- v1/kon.py Fri Oct 6 01:40:24 2017
+++ v2/kon.py Fri Oct 6 22:00:00 2017
@@ -68,6 +68,8 @@
e.v = init_v
return lambda v='get': e.v if v == 'get' else setattr(e, 'v', init_v if v == 'reset' else v)
+cond_wrap = lambda cond_f, targ_f: ( lambda *arg: targ_f(*arg) if cond_f() else None )
+
def rlock(rl=None):
if not rl:
rl = threading.RLock()
@@ -77,18 +79,21 @@
e.unlock = rl.release
return e
-def lock_wrap(f, rl=None):
+def lock_wrap(f, rl=None, cond_f=None):
if not rl:
rl = rlock()
e = extends(rl)
+ e.cond_f = cond_f if cond_f else lambda: True
def wrap_f(*args):
rl.lock()
- r = f(*args)
+ r = f(*args) if e.cond_f() else None
rl.unlock()
return r
e.f = wrap_f
return e
+updiv = lambda a, b: (a + b - 1) / b
+
hz_to_sec = lambda hz: 1.0 / hz if hz > 0 else 0
sec_to_hz = lambda sec: 1.0 / sec if sec > 0 else 0
@@ -131,11 +136,19 @@
e.cancel = cancel
return e
-def th_loop(f, args=[], hz=0, sta=True):
+def evt():
+ ev = threading.Event()
+ e = extends(ev)
+ e.v = ''
+ e.set = lambda v: ( set(e, 'v', v), ev.set() )[-1]
+ e.get = lambda: e.v if ev.is_set() else ''
+ return e
+
+def th_loop(f, args=[], hz=0, run=True):
e = Empty()
e.hz = hz
- e.run = sta
- ev = threading.Event()
+ e.run = run
+ ev = evt()
def loop():
while not ev.wait( hz_to_sec(e.hz) ):
# sec == 0 when hz == 0
@@ -143,21 +156,24 @@
f( *args )
th = threading.Thread( target=loop )
th.daemon = True
+
e.stop = lambda: set(e, 'run', False)
e.start = lambda: set(e, 'run', True)
- e.kill = ev.set
+ e.kill = lambda: ev.set('kill')
e.join = th.join
e.kill_join = lambda: ( e.kill(), e.join() )[-1]
+
th.start()
return e
-def flicker(hz=1.0, f=None, args=[], sta=False):
+def flicker(hz=1.0, f=None, args=[], run=False):
def th_f():
set(e, 'v', not e.v)
if has(e, 'f'):
e.f( *e.args )
- e = extends( th_loop(th_f, [], hz*2, sta) )
+ #e = extends( th_loop(th_f, [], hz*2, run) )
+ e = extends( th_loop(th_f, [], hz, run) )
e.v = False
e.get = lambda: e.v
e.f = f
@@ -189,7 +205,8 @@
DIRS = ( U, D, L, R ) = 'udlr'
bak_dir = lambda d: { U: D, D: U, L: R, R: L }.get(d)
-step_to = lambda x, y, d: { U: (x, y-1), D: (x, y+1), L: (x-1, y), R: (x+1, y) }.get( d, (x, y) )
+dir_to_xy = lambda d: { U: (0, -1), D: (0, 1), L: (-1, 0), R: (1, 0) }.get(d, (0, 0) )
+step_to = lambda x, y, d: ( lambda (dx, dy): (x+dx, y+dy) )( dir_to_xy(d) )
def keydir(tmout=None):
ctl = lambda s: chr( 1 + ord(s) - ord('a') )
@@ -227,7 +244,7 @@
if v in lst:
out( esc( '{}m'.format( 30 + lst.index(v) ) ) )
-def show(x, y, s, col, r):
+def show_inner(x, y, s, col, r, flush_f):
loc(x, y)
rev(r)
nx = x + len(s)
@@ -236,9 +253,13 @@
else:
color(col)
out(s)
+ if flush_f:
+ flush()
return nx
-lock_show = lock_wrap( show )
+lock_show = lock_wrap( show_inner )
+
+show = lambda x, y, s, col, r, flush_f=False: lock_show.f(x, y, s, col, r, flush_f)
def sum_show_lst(lst):
# lst = [ (s, col, r), (s, col, r) ... ]
@@ -253,7 +274,18 @@
split_show_lst = lambda lst: sum( map( lambda (s, col, r): map( lambda c: (c, col, r), s ), lst ), [] )
-lock_shows = lambda x, y, lst: reduce( lambda x, (s, col, r): lock_show.f(x, y, s, col, r), sum_show_lst(lst), x )
+show_lst_len = lambda lst: sum( map( lambda (s, col, r): len(s), lst ) )
+
+def fit_show_lsts(show_lsts):
+ ns = map( show_lst_len, show_lsts )
+ max_n = max(ns)
+ return map( lambda (lst, n): sum_show_lst( lst + [ (' ', '', False) ] * (max_n - n) ), zip( show_lsts, ns ) )
+
+def shows(x, y, lst, flush_f=False):
+ x = reduce( lambda x, (s, col, r): show(x, y, s, col, r), sum_show_lst(lst), x )
+ if flush_f:
+ flush()
+ return x
def over_show_lst(l, h):
get_col = lambda (s, col, r): col
@@ -277,14 +309,26 @@
w += 1
return w
+def bin_search(s, e, f, v):
+ sv = f(s)
+ ev = f(e)
+ while e - s > 0:
+ m = (s + e) / 2
+ mv = f(m)
+ (s, e, sv, ev) = (s, m, sv, mv) if mv < v else (m, e, mv, ev)
+ return s
+
loop_xy = lambda w, h, f: sum( map( lambda y: map( lambda x: f(x, y), range(w) ), range(h) ), [] )
+loop_xywh = lambda x, y, w, h, f: loop_xy( w, h, lambda dx, dy: f(x+dx, y+dy) )
-lst_xy = lambda w ,h: loop_xy( w, h, lambda x, y: (x, y) )
+lst_xy = lambda w, h: loop_xy( w, h, lambda x, y: (x, y) )
+lst_xywh = lambda x, y, w, h: loop_xywh( x, y, w, h, lambda x, y: (x, y) )
chk_xy = lambda x, y, w, h: x in range(w) and y in range(h)
+chk_xywh = lambda x, y, sx, sy, w, h: chk_xy(x-sx, y-sy)
-into_x = lambda x, iw, ow: max( min( ow - iw, x ), 0 )
-into_xy = lambda x, y, iw, ih, ow, oh: ( into_x(x, iw, ow), into_x(y, ih, oh) )
+into_x = lambda x, w, ow: max( min( ow - w, x ), 0 )
+into_xy = lambda x, y, w, h, ow, oh: ( into_x(x, w, ow), into_x(y, h, oh) )
def arr_xy_new(w, h, v):
e = Empty()
@@ -306,7 +350,8 @@
arr = arr_xy_new(w, h, 0)
e = extends(arr)
e.get = lambda x, y, bit: arr.get(x, y, 0) & pat(bit)
- e.set = lambda x, y, bit, bv: arr.set( x, y, chg( arr.get(x, y), bit, bv ) )
+ e.set_ = lambda x, y, bit, bv: arr.set( x, y, chg( arr.get(x, y), bit, bv ) )
+ e.set = lock_wrap( e.set_ ).f
e.clear = lambda: arr.clear(0)
e.gets = lambda x, y: filter( lambda bit: e.get(x, y, bit), range( bit_w( arr.get(x, y, 0) ) ) )
return e
@@ -325,8 +370,19 @@
arr_bit_c = arr_xy_bit_c_new(w, h, bit_cs)
e = extends(arr_bit_c)
+ e.xy_to_view = xy_to_view
- def update(x, y):
+ def view_to_wh(vw, vh):
+ (w, h) = e.size()
+ (sx, sy) = xy_to_view(0, 0)
+ (ex, ey) = xy_to_view(w, h)
+ (vw_, vh_) = (ex-sx, ey-sy)
+ return ( updiv(vw * w, vw_), updiv(vh * h, vh_) )
+ e.view_to_wh = view_to_wh
+
+ def update_arg(x, y):
+ if not e.chk_xy(x, y):
+ return
cs = []
if update_border != (0,0):
(bw, bh) = update_border
@@ -342,9 +398,35 @@
show_lst = trans_to_spc_show_lst(show_lst) if show_lst else [ (' ', '', False) ]
(x, y) = xy_to_view(x, y)
- lock_shows(x, y, show_lst)
+ return (x, y, show_lst)
+ def update(x, y, f=shows, flush_f=False):
+ f( *update_arg(x, y) )
+ if flush_f:
+ flush()
e.update = update
+ e.update_xys = lambda xys, f=shows, flush_f=False: map( lambda (x, y): e.update(x, y, f, flush_f), xys )
+ e.update_area = lambda x, y, w, h, f=shows, flush_f=False: e.update_xys( lst_xywh(x, y, w, h), f, flush_f )
+ e.update_line = lambda x, y, w, f=shows, flush_f=False: e.update_area(x, y, w, 1, f, flush_f)
+
+ e.get_w = lambda vw: view_to_wh( vw, 0 )[0]
+ e.show_lst_wh = lambda show_lst: ( e.get_w( show_lst_len(show_lst) ), 1 )
+
+ def shows_(x, y, show_lst, xcen=False, restore=False, flush_f=False):
+ (w, h) = e.show_lst_wh(show_lst)
+ if xcen:
+ x -= (w - 1) / 2
+ (ow, oh) = e.size()
+ (x, y) = into_xy(x, y, w, h, ow, oh)
+
+ if restore:
+ e.update_area(x, y, w, h)
+ else:
+ (vx, vy) = xy_to_view(x, y)
+ shows( vx, vy, show_lst )
+ if flush_f:
+ flush()
+ e.shows = shows_
return e
def rbuf(fname):
diff -ur v1/mon_ret.txt v2/mon_ret.txt
--- v1/mon_ret.txt Sat Sep 30 00:25:44 2017
+++ v2/mon_ret.txt Fri Oct 6 22:00:00 2017
@@ -2,6 +2,7 @@
#dllrdllrd#dlrrdlrrd#
#d###d###d#d###d###d#
#d###d###d#d###d###d#
+#d###d###d#d###d###d#
#rrrrrrdlllrrdllllll#
#d###d#d#####d#d###d#
#rrrrd#rrd#dll#dllll#
diff -ur v1/pac.py v2/pac.py
--- v1/pac.py Fri Oct 6 01:40:20 2017
+++ v2/pac.py Fri Oct 6 22:00:00 2017
@@ -3,7 +3,6 @@
import sys
import os
import threading
-import random
import kon
from kon import dbg, DIRS, U, D, L, R, flush, has, set, get
@@ -14,10 +13,6 @@
MONS = 'MRCY'
MOVES = 'P' + MONS
-def pdot_update():
- map( lambda (x, y): show_update(x, y), pac_buf.pos('O') )
- flush()
-
def stat_dic(c):
d = {}
if c == 'P':
@@ -45,7 +40,7 @@
'rl': kon.rlock()
}
elif c == 'O':
- d = { 'flick': kon.flicker( 2.0, pdot_update, sta=True ) }
+ d = { 'flick': kon.flicker( 2.0, lambda: arr.update_xys( pac_buf.pos('O'), flush_f=True ), run=True ) }
return d
stat_cs = MOVES + 'O'
@@ -54,14 +49,14 @@
stat_gets = lambda cs: map( stat_get, cs )
c_stat_gets = lambda cs: zip( cs, stat_gets(cs) )
-def pac_show(c):
+def pac_show(c, x, y):
(s, col, r) = ('()', 'yellow', True)
(x, y) = stat_get(c).pos
if (x + y) % 2:
s = { L: '>)', R: '(<', U: '(/', D: '/)' }.get( stat_get(c).dir )
return (s, col, r)
-def mon_show(c):
+def mon_show(c, x, y):
col = { 'M': 'magenta', 'R': 'red', 'C': 'cyan', 'Y': 'white' }.get(c)
d = {
'run': ( 'oo', col, True ),
@@ -75,7 +70,17 @@
mode += '_' + str( stat_get(c).flick.get() )
return d.get(mode if mode in d else 'run')
-bit_cs = MONS + 'PO.=#'
+def blk_show(c, x, y):
+ k = filter( lambda d: pac_buf.get( *kon.step_to(x, y, d) ) == c, DIRS ) # 'udlr'
+ s = '=='
+ d = {
+ ( 'ud', 'u', 'd', 'udl', 'udr' ): '||',
+ ( 'ul', 'dl' ): '= ',
+ ( 'ur', 'dr' ): ' =',
+ ( 'udlr', ): ' ',
+ }
+ s = dict( sum( map( lambda (ks, v): map( lambda k: (k, v), ks ), d.items() ), [] ) ).get(k, s)
+ return (s, 'blue', False)
show_inf = {
'M': mon_show,
@@ -83,15 +88,15 @@
'C': mon_show,
'Y': mon_show,
'P': pac_show,
- 'O': lambda c: ('O ', 'yellow', stat_get(c).flick.get()),
- '.': lambda c: ('. ', 'white', False),
- '=': lambda c: ('==', 'yellow', False),
- '#': lambda c: (' ', 'blue', True),
+ 'O': lambda c, x, y: ('O ', 'yellow', stat_get(c).flick.get()),
+ '.': lambda c, x, y: ('. ', 'white', False),
+ '=': lambda c, x, y: ('==', 'yellow', False),
+ '#': blk_show,
}
SPC = (' ', '', False)
TRANS = (' ', 'trans', False)
-get_show_inf = lambda c: show_inf.get(c)(c) if c in show_inf else SPC
+get_show_inf = lambda c, x, y: show_inf.get(c)(c, x, y) if c in show_inf else SPC
def mon_price_new():
e = kon.Empty()
@@ -110,10 +115,10 @@
stat = stat_get(c)
def update():
(x, y) = stat.pos
- show_update(x, y)
+ arr.update(x, y)
dx = stat.dx
if dx:
- show_update( x + dx, y )
+ arr.update( x + dx, y )
flush()
mode = stat.mode
@@ -140,7 +145,7 @@
arr_xy_to_show_xy = lambda x, y: (x * 2, y + 1) # for aspect and score
def c_to_show_lst(c, x, y):
- inf = get_show_inf(c)
+ inf = get_show_inf(c, x, y)
stat = stat_get(c)
if c not in MOVES or stat.dx == 0:
@@ -155,6 +160,7 @@
return kon.split_show_lst( conn )[1:3]
(w, h) = pac_buf.size()
+bit_cs = MONS + 'PO.=#'
arr = kon.arr_xy_bit_c_show_new( w, h, bit_cs, c_to_show_lst, arr_xy_to_show_xy, (1,0) )
is_warp = lambda x, y, d: ( lambda wc: wc if wc in ('L', 'R') and wc.lower() == d else False )( warp_buf.get(x, y) )
@@ -186,79 +192,26 @@
next_ds = lambda x, y, c: filter( lambda d: is_step(x, y, c, d), DIRS )
-def show(x, y, s, col, r):
- if not game_ev.get():
- kon.lock_show.f(x, y, s, col, r)
-
-def shows(x, y, lst): # [ (s, col, r), ... ]
- def f( lst, (s, col, r) ):
- if lst:
- (s_, col_, r_) = lst[-1]
- if col_ == col and r_ == r:
- return lst[:-1] + [ (s_ + s, col_, r_) ]
- return lst + [ (s, col, r) ]
- lst = reduce( f, lst, [] )
-
- def f_show( x, (s, col, r) ):
- show(x, y, s, col, r)
- return x + len(s)
- reduce( f_show, lst, x )
-
-def show_update(x, y):
- if not game_ev.get():
- arr.update(x, y)
-
-def show_update_line(x, y, xlen):
- map( lambda dx: show_update(x + dx, y), range(xlen) )
- flush()
-
-def line_msg_pause(x, y, s, col, r, sec, x_cen=True):
- xlen = ( len(s) + 1 ) / 2 # for aspect
- if x_cen:
- x -= (xlen - 1) / 2
- (w, h) = pac_buf.size()
- y = min( max(y, 0), h - 1 )
- x = min( max(x, 0), w - 1 - xlen )
-
- (x_, y_) = arr_xy_to_show_xy(x, y)
-
+def line_msg_pause(x, y, s, col, r, sec, xcen=True):
lock_move.lock()
- show(x_, y_, s, col, r)
- flush()
+ show_lst = [ (s, col, r) ]
+ arr.shows(x, y, show_lst, xcen, flush_f=True)
kon.sleep(sec)
- show_update_line(x, y, xlen)
+ arr.shows(x, y, show_lst, xcen, restore=True, flush_f=True)
lock_move.unlock()
-def show_anime(x, y, lst, hz, restore=True, n=1):
- (ss, cols, rs) = zip( *lst )
- xlen = max( map( lambda s: ( len(s) + 1 ) / 2, ss ) ) # for aspect
-
- (x_, y_) = arr_xy_to_show_xy(x, y)
-
+def show_anime(x, y, lsts, hz, restore=True, n=1):
lock_move.lock()
+ lsts = kon.fit_show_lsts(lsts)
for i in range(n):
- for (s, col, r) in lst:
- show(x_, y_, s, col, r)
- flush()
+ for lst in lsts:
+ arr.shows(x, y, lst, flush_f=True)
kon.sleep_hz(hz)
- if restore:
- show_update_line(x, y, xlen)
+ if restore and lsts:
+ arr.shows(x, y, lsts[0], flush_f=True)
lock_move.unlock()
-def game_ev_new():
- e = kon.Empty()
- e.ev = ev = threading.Event()
- e.v = ''
- e.wait = ev.wait
- e.clear = ev.clear
- def set(v):
- e.v = v
- ev.set()
- e.set = set
- e.get = lambda: e.v if ev.is_set() else ''
- return e
-
-game_ev = game_ev_new()
+game_ev = kon.evt()
def meet_chk(x, y):
if not arr.get(x, y, 'P'):
@@ -270,17 +223,18 @@
mode = mon_mode(c)
if mode in ('weak', 'blink'):
ss = [ '. ', 'o ', 'O ', '<>', '()', '^^' ]
- lst = map( lambda s: (s, 'yellow', True), ss )
- show_anime(x, y, lst, 8.0, restore=False)
+ lsts = map( lambda s: [ (s, 'yellow', True) ], ss )
+ show_anime(x, y, lsts, 8.0, restore=False)
add = mon_price.get() * 200
mon_price.twice()
score(add)
line_msg_pause(x, y-1, str(add), '', False, 1.0)
mon_mode(c, 'ret')
elif mode != 'ret' and not NO_DIE:
- ss = [ '()', '||', ')(', '--', '__', ' ' ]
- lst = map( lambda s: (s, 'yellow', True), ss ) + [ SPC ]
- show_anime(x, y, lst, 3.0)
+ ss = [ '()', '||', ')(', '><', '--', '><', '--', '><', '--', '__', ' ' ]
+ lsts = map( lambda s: [ (s, 'yellow', True) ], ss )
+ lsts.append( [ SPC ] )
+ show_anime(x, y, lsts, 5.0, restore=False)
v = 'over' if spare(-1) == 'over' else 'die'
game_ev.set(v)
@@ -300,20 +254,19 @@
dx = -dx
stat = stat_get(c)
stat.dx = dx
- show_update(px, py)
- show_update(nx, ny)
+ arr.update(px, py)
+ arr.update(nx, ny)
def late_update():
stat.dx = 0
- show_update(px, py)
- show_update(nx, ny)
- flush()
+ arr.update(px, py)
+ arr.update(nx, ny, flush_f=True)
sec = kon.hz_to_sec( get_hz(c, nx, ny) * 2 )
stat.late_tmr.start( late_update, [], sec )
else:
- show_update(px, py)
- show_update(nx, ny)
+ arr.update(px, py)
+ arr.update(nx, ny)
flush()
meet_chk(nx, ny)
@@ -349,16 +302,15 @@
if stat_get('P').dot <= 0:
c = '#'
pos = pac_buf.pos(c)
- pos = map( lambda (x, y): arr_xy_to_show_xy(x, y), pos )
- for i in range(6):
- (s, col, r) = get_show_inf(c) if i % 2 else ('==', 'white', False)
- for (x, y) in pos:
- show(x, y, s, col, r)
- flush()
- kon.sleep_hz(6)
- game_ev.set('clear')
-rand_sel = lambda lst: lst[ random.randrange( len(lst) ) ]
+ def shows(x, y, lst):
+ lst = map( lambda (s, col, r): (s, col, r) if flick.get() else ('==', 'white', False), lst )
+ kon.shows(x, y, lst)
+
+ flick = kon.flicker( 3.0, arr.update_xys, [ pos, shows ], True )
+ kon.sleep(1.0)
+ flick.kill_join()
+ game_ev.set('clear')
kdir = kon.gval('')
@@ -383,6 +335,24 @@
lock_move.f(px, py, nx, ny, c)
try_eat(nx, ny)
+def sel_mon_way(c, x, y, ds):
+ def rand(n):
+ v = sum( sum( map( lambda c: list( stat_get(c).pos ), MOVES ), [] ) )
+ return ( v / 4 ) % n
+ rand_sel = lambda lst: lst[ rand( len(lst) ) ]
+
+ (tx, ty) = stat_get('P').pos
+ xd = R if tx - x > 0 else L
+ yd = D if ty - y > 0 else U
+ rd = rand_sel(ds)
+
+ return {
+ 'M': lambda: yd if yd in ds else rd,
+ 'R': lambda: xd if xd in ds else yd if yd in ds else rd,
+ 'C': lambda: xd if xd in ds else rd,
+ 'Y': lambda: rd,
+ }.get(c)()
+
def th_mon(c):
stat = stat_get(c)
(px, py) = stat.pos
@@ -396,7 +366,7 @@
else:
ds_ = filter( lambda d: d != kon.bak_dir(pd), ds )
ds = ds_ if ds_ else ds
- d = rand_sel(ds)
+ d = ds[0] if len(ds) == 1 else sel_mon_way(c, px, py, ds)
(nx, ny) = step_to(px, py, d)
stat.dir = d
@@ -417,7 +387,7 @@
def f(add=0):
e.v += add
(dx, s) = (0, lb) if add == 0 else ( len(lb), str(e.v) )
- show(x + dx, y, s, col, r)
+ kon.show(x + dx, y, s, col, r, flush_f=True)
return f
score = score_new()
@@ -426,14 +396,14 @@
(w, h) = pac_buf.size()
(x, y) = arr_xy_to_show_xy(0, h)
c = 'P'
- (s, col, r) = get_show_inf(c)
+ (s, col, r) = ('()', 'yellow', True)
e = kon.Empty()
e.v = v
def draw(on, i):
(s_, col_, r_) = (s, col, r) if on else SPC
x_ = x + i * 3
if x_ >= 0:
- show( x_, y, s_, col_, r_ )
+ kon.show( x_, y, s_, col_, r_, flush_f=True )
def f(add=0):
if add == 0:
map( lambda i: draw(True, i), range(e.v) )
@@ -453,13 +423,15 @@
spare = spare_new(2)
def work():
+ kon.lock_show.cond_f = lambda: not game_ev.get()
+
def init_map():
(w, h) = pac_buf.size()
arr.clear()
def f(x, y):
c = pac_buf.get(x, y)
arr.set(x, y, c, True)
- show_update(x, y)
+ arr.update(x, y)
kon.loop_xy(w, h, f)
flush()
@@ -509,11 +481,9 @@
for (c, stat) in c_stat_gets(MOVES):
(x, y) = stat.pos
- d = stat.dir
arr.set(x, y, c, False)
- show_update(x, y)
- map( lambda d: show_update( *step_to( x, y, d ) ), DIRS )
- flush()
+ xys = [(x, y)] + map( lambda d: step_to(x, y, d), DIRS )
+ arr.update_xys( xys, flush_f=True )
if v == 'die':
init_stat()
diff -ur v1/pac.txt v2/pac.txt
--- v1/pac.txt Thu Oct 5 17:10:14 2017
+++ v2/pac.txt Fri Oct 6 22:00:00 2017
@@ -1,5 +1,6 @@
#####################
#.........#.........#
+#.###.###.#.###.###.#
#O###.###.#.###.###O#
#.###.###.#.###.###.#
#...................#
Only in v1: pac_data.tgz
diff -ur v1/warp.txt v2/warp.txt
--- v1/warp.txt Sat Sep 30 00:24:20 2017
+++ v2/warp.txt Fri Oct 6 22:00:00 2017
@@ -2,6 +2,7 @@
# # #
# ### ### # ### ### #
# ### ### # ### ### #
+# ### ### # ### ### #
# #
# ### #u#####u# ### #
# # # # #
$ cat v2.patch | patch -p1 $ chmod +x pac.py $ ./pac.py
v3.patch
diff -urN v2/kon.py v3/kon.py
--- v2/kon.py 2017-10-06 22:00:00.000000000 +0900
+++ v3/kon.py 2017-10-17 03:15:30.000000000 +0900
@@ -84,9 +84,11 @@
rl = rlock()
e = extends(rl)
e.cond_f = cond_f if cond_f else lambda: True
+ e.en = True
+ chk = lambda: e.cond_f() and e.en
def wrap_f(*args):
rl.lock()
- r = f(*args) if e.cond_f() else None
+ r = f(*args) if chk() else None
rl.unlock()
return r
e.f = wrap_f
@@ -148,37 +150,52 @@
e = Empty()
e.hz = hz
e.run = run
- ev = evt()
+ kill_ev = threading.Event()
def loop():
- while not ev.wait( hz_to_sec(e.hz) ):
- # sec == 0 when hz == 0
+ while not kill_ev.is_set():
if e.run:
f( *args )
+ kill_ev.wait( hz_to_sec(e.hz) ) # sec == 0 when hz == 0
+
th = threading.Thread( target=loop )
th.daemon = True
-
e.stop = lambda: set(e, 'run', False)
e.start = lambda: set(e, 'run', True)
- e.kill = lambda: ev.set('kill')
+ e.kill = lambda: kill_ev.set()
e.join = th.join
e.kill_join = lambda: ( e.kill(), e.join() )[-1]
+ e.set_hz = lambda hz: set(e, 'hz', hz)
+ e.get_hz = lambda: e.hz
th.start()
return e
-def flicker(hz=1.0, f=None, args=[], run=False):
+def counter(n, hz=1.0, f=None, run=False, repeat=True):
+ ev = threading.Event()
def th_f():
- set(e, 'v', not e.v)
- if has(e, 'f'):
- e.f( *e.args )
-
- #e = extends( th_loop(th_f, [], hz*2, run) )
- e = extends( th_loop(th_f, [], hz, run) )
- e.v = False
- e.get = lambda: e.v
+ e.i = (e.i + 1) % n if e.i != None else 0
+ if e.f:
+ e.f()
+ if not repeat and e.i == n - 1:
+ e.stop()
+ ev.set()
+ th = th_loop(th_f, [], hz, False)
+ e = extends(th)
e.f = f
- e.args = args
- e.set_hz = lambda hz: set(e, 'hz', hz*2)
+ e.i = None
+ e.get = lambda: e.i if e.i != None else 0
+ e.wait = ev.wait # for no repeat
+ e.set_f = lambda f: set(e, 'f', f)
+ e.start = lambda: ( set(e, 'i', None), th.start() )[-1]
+ e.restart = lambda: ( e.stop(), e.start() )[-1]
+ if run:
+ e.start()
+ return e
+
+def slider(lst, hz=1.0, f=None, run=False, repeat=True):
+ ctr = counter( len(lst), hz, f, run, repeat )
+ e = extends(ctr)
+ e.get = lambda: lst[ ctr.get() ]
return e
def term_raw(sigint=True):
@@ -226,7 +243,7 @@
buf += getkey(tmout)
return ''
-cls = lambda : out( esc('2J') )
+clr = lambda : out( esc('2J') )
loc = lambda x, y: out( esc( '{};{}H'.format(y+1, x+1) ) )
rev = lambda v: out( esc( '7m' if v else '0m' ) )
cursor = lambda v: out( esc_ex(25, v) )
@@ -261,6 +278,8 @@
show = lambda x, y, s, col, r, flush_f=False: lock_show.f(x, y, s, col, r, flush_f)
+mk_slst = lambda s, col='', r=False: [ (s, col, r) ]
+
def sum_show_lst(lst):
# lst = [ (s, col, r), (s, col, r) ... ]
@@ -270,7 +289,7 @@
a = (s, col, r) = lst[0]
lst = sum_show_lst( lst[1:] )
(s_, col_, r_) = lst[0]
- return [ (s + s_, col, r) ] + lst[1:] if col == col_ and r == r_ else [a] + lst
+ return mk_slst(s + s_, col, r) + lst[1:] if col == col_ and r == r_ else [a] + lst
split_show_lst = lambda lst: sum( map( lambda (s, col, r): map( lambda c: (c, col, r), s ), lst ), [] )
@@ -279,7 +298,7 @@
def fit_show_lsts(show_lsts):
ns = map( show_lst_len, show_lsts )
max_n = max(ns)
- return map( lambda (lst, n): sum_show_lst( lst + [ (' ', '', False) ] * (max_n - n) ), zip( show_lsts, ns ) )
+ return map( lambda (lst, n): sum_show_lst( lst + mk_slst(' ') * (max_n - n) ), zip( show_lsts, ns ) )
def shows(x, y, lst, flush_f=False):
x = reduce( lambda x, (s, col, r): show(x, y, s, col, r), sum_show_lst(lst), x )
@@ -290,11 +309,10 @@
def over_show_lst(l, h):
get_col = lambda (s, col, r): col
f = lambda l, h: l if get_col(h) == 'trans' else h
-
l = split_show_lst(l)
h = split_show_lst(h)
n = max( len(l), len(h) )
- apd = [ (' ', 'trans', False) ] * n
+ apd = mk_slst(' ', 'trans') * n
l = ( l + apd )[:n]
h = ( h + apd )[:n]
o = map( lambda (l, h): f(l, h), zip(l, h) )
@@ -325,11 +343,13 @@
lst_xywh = lambda x, y, w, h: loop_xywh( x, y, w, h, lambda x, y: (x, y) )
chk_xy = lambda x, y, w, h: x in range(w) and y in range(h)
-chk_xywh = lambda x, y, sx, sy, w, h: chk_xy(x-sx, y-sy)
+chk_xywh = lambda x, y, sx, sy, w, h: chk_xy(x-sx, y-sy, w, h)
into_x = lambda x, w, ow: max( min( ow - w, x ), 0 )
into_xy = lambda x, y, w, h, ow, oh: ( into_x(x, w, ow), into_x(y, h, oh) )
+cen_xywh = lambda x, y, w, h: (x + w/2, y + h/2)
+
def arr_xy_new(w, h, v):
e = Empty()
e.data = data = map( lambda _: [ v ] * w, range(h) )
@@ -337,39 +357,53 @@
e.chk_xy = lambda x, y: chk_xy(x, y, w, h)
e.get = lambda x, y, v=None: data[y][x] if e.chk_xy(x, y) else v
e.set = lambda x, y, c: set( data[y], x, c ) if e.chk_xy(x, y) else None
- e.clear = lambda c: loop_xy( w, h, lambda x, y: e.set(x, y, c) )
- def pos(c):
- lst = filter( lambda (x, y): e.get(x, y) == c, lst_xy(w, h) )
- return lst[0] if len(lst) == 1 else lst
- e.pos = pos
+ e.clear = lambda v: loop_xy( w, h, lambda x, y: e.set(x, y, v) )
+ e.poss = lambda v: filter( lambda (x, y): e.get(x, y) == v, lst_xy(w, h) )
+ e.pos = lambda v: next( iter( e.poss(v) ), (-1, -1) )
return e
def arr_xy_bit_new(w, h):
pat = lambda bit: 1 << bit if bit >= 0 else 0
chg = lambda v, bit, bv: v | pat(bit) if bv else v & ~pat(bit)
arr = arr_xy_new(w, h, 0)
+ pos_d = {}
+
+ def set_(x, y, bit, bv):
+ if not e.chk_xy(x, y):
+ return
+ arr.set(x, y, chg(arr.get(x, y), bit, bv) )
+
+ if bit not in pos_d:
+ pos_d[bit] = []
+ lst = pos_d.get(bit)
+ p = (x, y)
+ if bv and p not in lst:
+ lst.append(p)
+ if not bv and p in lst:
+ lst.remove(p)
e = extends(arr)
e.get = lambda x, y, bit: arr.get(x, y, 0) & pat(bit)
- e.set_ = lambda x, y, bit, bv: arr.set( x, y, chg( arr.get(x, y), bit, bv ) )
- e.set = lock_wrap( e.set_ ).f
+ e.set = lock_wrap( set_ ).f
e.clear = lambda: arr.clear(0)
e.gets = lambda x, y: filter( lambda bit: e.get(x, y, bit), range( bit_w( arr.get(x, y, 0) ) ) )
+ e.poss = lambda bit: pos_d.get(bit, [])
+ e.pos = lambda bit: next( iter( e.poss(bit) ), (-1, -1) )
return e
def arr_xy_bit_c_new(w, h, bit_cs):
- arr_bit = arr_xy_bit_new(w, h)
- e = extends(arr_bit)
- e.to_bit = to_bit = dict( zip( bit_cs, range( len(bit_cs) ) ) )
- e.get = lambda x, y, c: arr_bit.get( x, y, to_bit.get(c, -1) )
- e.set = lambda x, y, c, v: arr_bit.set( x ,y, to_bit.get(c, -1), v )
- e.gets = lambda x, y: map( lambda bit: bit_cs[bit], arr_bit.gets(x, y) )
+ arr = arr_xy_bit_new(w, h)
+ e = extends(arr)
+ e.to_bit = to_bit = lambda c: bit_cs.index(c) if c in bit_cs else -1
+ e.get = lambda x, y, c: arr.get( x, y, to_bit(c) )
+ e.set = lambda x, y, c, v: arr.set( x ,y, to_bit(c), v )
+ e.gets = lambda x, y: map( lambda bit: bit_cs[bit], arr.gets(x, y) )
+ e.poss = lambda c: arr.poss( to_bit(c) )
+ e.pos = lambda c: next( iter( e.poss(c) ), (-1, -1) )
return e
-def arr_xy_bit_c_show_new(w, h, bit_cs, c_to_show_lst, xy_to_view, update_border=(0,0)):
- # c_to_show_lst(c, x, y) return [ (s, col, r), (s, col, r) ... ]
-
- arr_bit_c = arr_xy_bit_c_new(w, h, bit_cs)
- e = extends(arr_bit_c)
+def arr_xy_bit_c_show_new(w, h, bit_cs, xy_to_view):
+ arr = arr_xy_bit_c_new(w, h, bit_cs)
+ e = extends(arr)
e.xy_to_view = xy_to_view
def view_to_wh(vw, vh):
@@ -380,53 +414,146 @@
return ( updiv(vw * w, vw_), updiv(vh * h, vh_) )
e.view_to_wh = view_to_wh
- def update_arg(x, y):
- if not e.chk_xy(x, y):
- return
- cs = []
- if update_border != (0,0):
- (bw, bh) = update_border
- xys = map( lambda (dx, dy): (x+dx-bw, y+dy-bh), lst_xy(bw*2+1, bh*2+1) )
- cs = sum( map( lambda (x, y): e.gets(x, y), xys ), [] )
- cs = reduce( lambda cs, c: cs if c in cs else cs + [c], cs, [] )
- cs.sort( key=lambda c: bit_cs.index(c) )
- else:
- cs = e.gets(x, y)
-
- show_lsts = map( lambda c: c_to_show_lst(c, x, y), cs )
- show_lst = reduce( over_show_lst, reversed( show_lsts ), [] )
- show_lst = trans_to_spc_show_lst(show_lst) if show_lst else [ (' ', '', False) ]
-
- (x, y) = xy_to_view(x, y)
- return (x, y, show_lst)
-
- def update(x, y, f=shows, flush_f=False):
- f( *update_arg(x, y) )
- if flush_f:
- flush()
- e.update = update
- e.update_xys = lambda xys, f=shows, flush_f=False: map( lambda (x, y): e.update(x, y, f, flush_f), xys )
- e.update_area = lambda x, y, w, h, f=shows, flush_f=False: e.update_xys( lst_xywh(x, y, w, h), f, flush_f )
- e.update_line = lambda x, y, w, f=shows, flush_f=False: e.update_area(x, y, w, 1, f, flush_f)
+ sdic = {}
+ e.get_sdic = lambda c: sdic.get( c, (None, None) )
+ e.set_sdic = lambda c, v: set(sdic, c, v)
+
+ def get_show_lst(c, x, y):
+ (t, o) = e.get_sdic(c)
+ if not o:
+ return mk_slst(' ')
+ if t == 'func':
+ return o(c, x, y)
+ if t == 'slider':
+ return o.get()
+ return o
+ e.get_show_lst = get_show_lst
e.get_w = lambda vw: view_to_wh( vw, 0 )[0]
e.show_lst_wh = lambda show_lst: ( e.get_w( show_lst_len(show_lst) ), 1 )
- def shows_(x, y, show_lst, xcen=False, restore=False, flush_f=False):
+ def show_lst_area(x, y, show_lst, xcen=False):
(w, h) = e.show_lst_wh(show_lst)
if xcen:
x -= (w - 1) / 2
(ow, oh) = e.size()
(x, y) = into_xy(x, y, w, h, ow, oh)
+ return (x, y, w, h)
+ e.show_lst_area = show_lst_area
- if restore:
- e.update_area(x, y, w, h)
- else:
- (vx, vy) = xy_to_view(x, y)
- shows( vx, vy, show_lst )
- if flush_f:
- flush()
+ def shows_(x, y, show_lst, xcen=False, flush_f=False):
+ (x, y, w, h) = e.show_lst_area(x, y, show_lst, xcen)
+ (vx, vy) = xy_to_view(x, y)
+ shows(vx, vy, show_lst, flush_f)
e.shows = shows_
+ e.flush = lambda flush_f=True: flush() if flush_f else None
+ return e
+
+def arr_xy_bit_c_update_new(w, h, bit_cs, xy_to_view, get_dx=None):
+ arr = arr_xy_bit_c_show_new(w, h, bit_cs, xy_to_view)
+ e = extends(arr)
+
+ def update(x, y, flush_f=False):
+ if not e.chk_xy(x, y):
+ return
+ lst = []
+ if get_dx:
+ for ix in (-1, 0, 1):
+ x_ = (x + ix + w) % w
+ cs = filter( lambda c: ix == 0 or get_dx(c) == -ix, e.gets(x_, y) )
+ lst += map( lambda c: ( c, x_, ix if ix else get_dx(c) ), cs )
+
+ TRANS = mk_slst(' ', 'trans')
+ shift = lambda lst, dx: split_show_lst( lst + TRANS if dx < 0 else TRANS + lst )[1:3] if dx else lst
+ lst = map( lambda (c, x_, dx): ( c, shift( e.get_show_lst(c, x_, y), dx ) ), lst )
+ else:
+ lst = map( lambda c: ( c, e.get_show_lst(c, x, y) ), e.gets(x, y) )
+
+ lst.sort( key=lambda (c, show_lst): e.to_bit(c) )
+ show_lsts = zip(*lst)[1] if lst else []
+ show_lst = reduce( over_show_lst, reversed( show_lsts ), [] )
+ show_lst = trans_to_spc_show_lst(show_lst) if show_lst else mk_slst(' ')
+ e.shows(x, y, show_lst, flush_f)
+
+ e.update = update
+ e.update_xys = lambda xys, flush_f=False: ( map( lambda (x, y): e.update(x, y), xys ), e.flush(flush_f) )[-1]
+ e.update_area = lambda x, y, w, h, flush_f=False: e.update_xys( lst_xywh(x, y, w, h), flush_f )
+ e.update_line = lambda x, y, w, flush_f=False: e.update_area(x, y, w, 1, flush_f)
+ e.update_all = lambda flush_f=False: e.update_area(0, 0, w, h, flush_f)
+
+ def update_c(c, flush_f=False):
+ dx = get_dx(c) if get_dx else 0
+ xys = e.poss(c)
+ #xys += map( lambda (x, y): (x+dx, y), xys ) if dx else []
+ if dx:
+ xys = xys + map( lambda (x, y): (x+dx, y), xys )
+ e.update_xys(xys, flush_f)
+ e.update_c = update_c
+
+ def set_sdic(c, v):
+ (t, o) = e.get_sdic(c)
+ if t == 'slider' and o:
+ o.kill_join()
+
+ arr.set_sdic(c, v)
+
+ (t, o) = e.get_sdic(c)
+ if t == 'slider' and o:
+ o.set_f( lambda: e.update_c(c, flush_f=True) )
+
+ e.update_c(c, flush_f=True)
+
+ e.set_sdic = set_sdic
+ return e
+
+def arr_xy_bit_c_move_new(w, h, bit_cs, xy_to_view):
+ dx_d = {}
+ get_dx = lambda c: dx_d.get(c, 0)
+ arr = arr_xy_bit_c_update_new(w, h, bit_cs, xy_to_view, get_dx)
+ e = extends(arr)
+ dir_d = {}
+
+ e.get_dir = lambda c: dir_d.get(c, '')
+ e.set_dir = lambda c, d: set(dir_d, c, d)
+
+ def move(c, d, hz=None):
+ (x, y) = e.pos(c)
+ if not e.chk_xy(x, y):
+ return
+
+ (nx, ny) = step_to(x, y, d)
+ (nx, ny) = ( (nx + w) % w, (ny + h) % h )
+ arr.set(x, y, c, False)
+ arr.set(nx, ny, c, True)
+ e.set_dir(c, d)
+
+ if hz:
+ dx_d[c] = { R: -1, L: 1 }.get(d, 0)
+
+ xys = [ (x, y), (nx, ny) ]
+ arr.update_xys(xys, flush_f=True)
+
+ if hz:
+ sec = hz_to_sec( hz * 2 )
+ tmr_f = lambda: ( set(dx_d, c, 0), arr.update_xys(xys, flush_f=True) )[-1]
+ timer_new(tmr_f, [], sec).start()
+ e.move = move
+
+ def set_(x, y, c, v=True, flush_f=False, d=''):
+ arr.set(x, y, c, v)
+ e.set_dir(c, d)
+ arr.update(x, y, flush_f)
+ e.set = set_
+
+ e.rm = lambda c, flush_f=False: map( lambda (x, y): e.set(x, y, c, False, flush_f), e.poss(c) )
+
+ def msg_pause(x, y, show_lst, sec, xcen=False):
+ e.shows(x, y, show_lst, xcen, flush_f=True)
+ sleep(sec)
+ (x, y, w, h) = e.show_lst_area(x, y, show_lst, xcen)
+ e.update_area(x, y, w, h, flush_f=True)
+ e.msg_pause = msg_pause
+
return e
def rbuf(fname):
diff -urN v2/pac.py v3/pac.py
--- v2/pac.py 2017-10-06 22:00:00.000000000 +0900
+++ v3/pac.py 2017-10-17 03:15:30.000000000 +0900
@@ -4,72 +4,25 @@
import os
import threading
import kon
-from kon import dbg, DIRS, U, D, L, R, flush, has, set, get
+from kon import dbg, DIRS, U, D, L, R, flush, has, set, get, mk_slst
NO_DIE = '-m' in sys.argv
-(pac_buf, mon_ret_buf, warp_buf) = map( kon.rbuf, ['pac.txt', 'mon_ret.txt', 'warp.txt'] )
+txts = map( lambda s: s + '.txt', [ 'pac', 'mon_ret', 'warp', 'pato' ] )
+(pac_buf, mon_ret_buf, warp_buf, pato_buf) = map(kon.rbuf, txts)
-MONS = 'MRCY'
+MONS = 'RCMY'
MOVES = 'P' + MONS
-def stat_dic(c):
- d = {}
- if c == 'P':
- d = {
- 'dir': L,
- 'pos': pac_buf.pos('P'),
- 'dx': 0,
- 'hz': 3.0,
- 'th': None,
- 'late_tmr': kon.timer_new(),
- 'dot': len( pac_buf.pos('.') + pac_buf.pos('O') ),
- }
- elif c in MONS:
- # mon mode 'cage' 'run' 'weak' 'blink' 'ret'
- d = {
- 'dir': U,
- 'pos': pac_buf.pos(c),
- 'dx': 0,
- 'hz': 4.0,
- 'th': None,
- 'late_tmr': kon.timer_new(),
- 'mode': 'cage' if c in 'CMY' else 'run',
- 'timer': kon.timer_new(),
- 'flick': kon.flicker(),
- 'rl': kon.rlock()
- }
- elif c == 'O':
- d = { 'flick': kon.flicker( 2.0, lambda: arr.update_xys( pac_buf.pos('O'), flush_f=True ), run=True ) }
- return d
-
-stat_cs = MOVES + 'O'
-stat_inf = dict( map( lambda c: ( c, kon.dic_to_cls( stat_dic(c) ) ), stat_cs ) )
+stat_inf = dict( map( lambda c: ( c, kon.Empty() ), MOVES ) )
stat_get = lambda c: stat_inf.get(c)
-stat_gets = lambda cs: map( stat_get, cs )
-c_stat_gets = lambda cs: zip( cs, stat_gets(cs) )
def pac_show(c, x, y):
(s, col, r) = ('()', 'yellow', True)
- (x, y) = stat_get(c).pos
if (x + y) % 2:
- s = { L: '>)', R: '(<', U: '(/', D: '/)' }.get( stat_get(c).dir )
- return (s, col, r)
+ s = { L: '>)', R: '(<', U: '(/', D: '/)' }.get( arr.get_dir(c), s )
+ return mk_slst(s, col, r)
-def mon_show(c, x, y):
- col = { 'M': 'magenta', 'R': 'red', 'C': 'cyan', 'Y': 'white' }.get(c)
- d = {
- 'run': ( 'oo', col, True ),
- 'weak': ( '><', 'blue', True ),
- 'blink_True': ( '><', 'blue', True ),
- 'blink_False': ( '--', 'white', True ),
- 'ret': ( 'oo', 'white', False ),
- }
- mode = mon_mode(c)
- if mode == 'blink':
- mode += '_' + str( stat_get(c).flick.get() )
- return d.get(mode if mode in d else 'run')
-
def blk_show(c, x, y):
k = filter( lambda d: pac_buf.get( *kon.step_to(x, y, d) ) == c, DIRS ) # 'udlr'
s = '=='
@@ -80,23 +33,9 @@
( 'udlr', ): ' ',
}
s = dict( sum( map( lambda (ks, v): map( lambda k: (k, v), ks ), d.items() ), [] ) ).get(k, s)
- return (s, 'blue', False)
-
-show_inf = {
- 'M': mon_show,
- 'R': mon_show,
- 'C': mon_show,
- 'Y': mon_show,
- 'P': pac_show,
- 'O': lambda c, x, y: ('O ', 'yellow', stat_get(c).flick.get()),
- '.': lambda c, x, y: ('. ', 'white', False),
- '=': lambda c, x, y: ('==', 'yellow', False),
- '#': blk_show,
-}
+ return mk_slst(s, 'blue', False)
SPC = (' ', '', False)
-TRANS = (' ', 'trans', False)
-get_show_inf = lambda c, x, y: show_inf.get(c)(c, x, y) if c in show_inf else SPC
def mon_price_new():
e = kon.Empty()
@@ -113,55 +52,36 @@
def mon_mode(c, v='get'):
stat = stat_get(c)
- def update():
- (x, y) = stat.pos
- arr.update(x, y)
- dx = stat.dx
- if dx:
- arr.update( x + dx, y )
- flush()
-
- mode = stat.mode
+ mode = stat.mode if has(stat, 'mode') else None
if v == 'get' or v == mode:
return mode
- if mode == 'blink':
- stat.flick.stop()
-
stat.mode = v
- update()
- if v == 'blink':
- stat.flick.f = update
- stat.flick.set_hz( stat.hz )
- stat.flick.start()
+ col = { 'M': 'magenta', 'R': 'red', 'C': 'cyan', 'Y': 'white' }.get(c)
+ blinks= [ mk_slst('><', 'blue', True), mk_slst('--', 'white', True) ]
+ d = {
+ 'cage': ( '', mk_slst('oo', col, True) ),
+ 'run': ( '', mk_slst('oo', col, True) ),
+ 'weak': ( '', mk_slst('><', 'blue', True) ),
+ 'blink': ( 'slider', kon.slider(blinks, stat.hz, None, True) ),
+ 'ret': ( '', mk_slst('oo', 'white', False) ),
+ }
+ arr.set_sdic( c, d.get(v) )
mon_price.check()
+ stat.th.set_hz( get_hz( c, *arr.pos(c) ) )
+
mon_hz_rate = { 'weak': 0.3, 'blink': 0.3, 'ret': 1.5 }
warp_rate = { '1': 0.8, '2': 0.6, '3': 0.4, '4': 0.3, 'L': 0.2, 'R': 0.2 }
arr_xy_to_show_xy = lambda x, y: (x * 2, y + 1) # for aspect and score
-def c_to_show_lst(c, x, y):
- inf = get_show_inf(c, x, y)
- stat = stat_get(c)
-
- if c not in MOVES or stat.dx == 0:
- return [ inf ] if arr.get(x, y, c) else [ TRANS ]
-
- (px, py) = stat.pos
- dx = stat.dx
- if x not in [ px, px + dx ] or y != py:
- return [ TRANS ]
-
- conn = [ inf, TRANS ] if (x == px) != (dx == 1) else [ TRANS, inf ]
- return kon.split_show_lst( conn )[1:3]
-
(w, h) = pac_buf.size()
-bit_cs = MONS + 'PO.=#'
-arr = kon.arr_xy_bit_c_show_new( w, h, bit_cs, c_to_show_lst, arr_xy_to_show_xy, (1,0) )
+bit_cs = MOVES + 'O.=#'
+arr = kon.arr_xy_bit_c_move_new( w, h, bit_cs, arr_xy_to_show_xy)
is_warp = lambda x, y, d: ( lambda wc: wc if wc in ('L', 'R') and wc.lower() == d else False )( warp_buf.get(x, y) )
@@ -184,32 +104,35 @@
(nx, ny) = step_to(px, py, d)
+ # gate chk
+ nc = pac_buf.get(nx, ny)
+ if c in MONS and mon_mode(c) == 'cage' and nc == '=' and MONS.index(c) > gate.get():
+ return False
+
v = one_way(nx, ny, d)
if v != None:
return v
- return pac_buf.get(nx, ny) not in (None, '#')
+ return nc != '#'
next_ds = lambda x, y, c: filter( lambda d: is_step(x, y, c, d), DIRS )
-def line_msg_pause(x, y, s, col, r, sec, xcen=True):
- lock_move.lock()
- show_lst = [ (s, col, r) ]
- arr.shows(x, y, show_lst, xcen, flush_f=True)
- kon.sleep(sec)
- arr.shows(x, y, show_lst, xcen, restore=True, flush_f=True)
- lock_move.unlock()
-
-def show_anime(x, y, lsts, hz, restore=True, n=1):
- lock_move.lock()
- lsts = kon.fit_show_lsts(lsts)
- for i in range(n):
- for lst in lsts:
- arr.shows(x, y, lst, flush_f=True)
- kon.sleep_hz(hz)
- if restore and lsts:
- arr.shows(x, y, lsts[0], flush_f=True)
- lock_move.unlock()
+def arr_msg_pause(show_lst, x=None, y=None, sec=1.0, xcen=True):
+ game_ev.set('stop')
+ (bx, by) = pac_buf.pos('B')
+ x = bx if x == None else x
+ y = by if y == None else y
+ arr.msg_pause(x, y, show_lst, sec, xcen)
+ game_ev.set('start')
+
+def pac_slider(slider):
+ game_ev.set('stop')
+ c = 'P'
+ bak = arr.get_sdic(c)
+ arr.set_sdic( c, ('slider', slider) )
+ slider.wait()
+ game_ev.set('start')
+ return bak
game_ev = kon.evt()
@@ -222,63 +145,63 @@
mode = mon_mode(c)
if mode in ('weak', 'blink'):
+ mov.en = False
ss = [ '. ', 'o ', 'O ', '<>', '()', '^^' ]
- lsts = map( lambda s: [ (s, 'yellow', True) ], ss )
- show_anime(x, y, lsts, 8.0, restore=False)
+ lsts = map( lambda s: mk_slst(s, 'yellow', True), ss )
+ bak = pac_slider( kon.slider(lsts, 8.0, None, True, repeat=False) )
add = mon_price.get() * 200
mon_price.twice()
+ arr_msg_pause( mk_slst( str(add) ), x, y-1, 1.0 )
score(add)
- line_msg_pause(x, y-1, str(add), '', False, 1.0)
mon_mode(c, 'ret')
+ arr.set_sdic('P', bak)
+ mov.en = True
+ break
elif mode != 'ret' and not NO_DIE:
+ mov.en = False
ss = [ '()', '||', ')(', '><', '--', '><', '--', '><', '--', '__', ' ' ]
- lsts = map( lambda s: [ (s, 'yellow', True) ], ss )
+ lsts = map( lambda s: mk_slst(s, 'yellow', True), ss )
lsts.append( [ SPC ] )
- show_anime(x, y, lsts, 5.0, restore=False)
+ bak = pac_slider( kon.slider(lsts, 5.0, None, True, repeat=False) )
v = 'over' if spare(-1) == 'over' else 'die'
game_ev.set(v)
+ arr.set_sdic('P', bak)
+ break
def get_hz(c, nx, ny):
hz = stat_get(c).hz
if c in MONS:
- hz *= mon_hz_rate.get( mon_mode(c), 1.0 )
- hz *= warp_rate.get( warp_buf.get(nx, ny), 1.0 )
+ mode = mon_mode(c)
+ hz *= mon_hz_rate.get(mode, 1.0)
+ if mode != 'ret':
+ hz *= warp_rate.get( warp_buf.get(nx, ny), 1.0 )
return hz
-def move(px, py, nx, ny, c):
- arr.set(px, py, c, False)
- arr.set(nx, ny, c, True)
-
- dx = nx - px
- if dx in (1, -1): # for warp
- dx = -dx
- stat = stat_get(c)
- stat.dx = dx
- arr.update(px, py)
- arr.update(nx, ny)
-
- def late_update():
- stat.dx = 0
- arr.update(px, py)
- arr.update(nx, ny, flush_f=True)
-
- sec = kon.hz_to_sec( get_hz(c, nx, ny) * 2 )
- stat.late_tmr.start( late_update, [], sec )
- else:
- arr.update(px, py)
- arr.update(nx, ny)
- flush()
-
- meet_chk(nx, ny)
+def move_new():
+ e = kon.Empty()
+ e.en = True
+ def f(c, d, hz):
+ if e.en:
+ arr.move(c, d, hz)
+ (x, y) = arr.pos(c)
+ meet_chk(x, y)
+ e.f = f
+ return e
+mov = move_new()
+move = mov.f
-lock_move = kon.lock_wrap( move )
+def short_sec(sec):
+ c = 'P'
+ hz = stat_get(c).hz
+ init_hz = 3.0
+ return sec * init_hz / hz
def mon_weak():
def tmr_f(c):
mode = mon_mode(c)
if mode == 'weak':
mon_mode(c, 'blink')
- stat_get(c).timer.start( tmr_f, [c], 5.0 )
+ stat_get(c).timer.start( tmr_f, [c], short_sec(3.0) )
elif mode == 'blink':
mon_mode(c, 'run')
@@ -286,8 +209,8 @@
if mon_mode(c) not in ('cage', 'ret'):
mon_mode(c, 'weak')
stat = stat_get(c)
- stat.dir = kon.bak_dir( stat.dir )
- stat.timer.start( tmr_f, [c], 15.0 )
+ arr.set_dir( c, kon.bak_dir( arr.get_dir(c) ) )
+ stat.timer.start( tmr_f, [c], short_sec(15.0) )
def try_eat(x, y):
c = '.' if arr.get(x, y, '.') else 'O' if arr.get(x, y, 'O') else ''
@@ -296,20 +219,18 @@
arr.set(x, y, c, False)
stat_get('P').dot -= 1
- score( 20 if c == 'O' else 5 )
+ score( 50 if c == 'O' else 10 )
if c == 'O':
mon_weak()
if stat_get('P').dot <= 0:
+ mov.en = False
c = '#'
- pos = pac_buf.pos(c)
-
- def shows(x, y, lst):
- lst = map( lambda (s, col, r): (s, col, r) if flick.get() else ('==', 'white', False), lst )
- kon.shows(x, y, lst)
-
- flick = kon.flicker( 3.0, arr.update_xys, [ pos, shows ], True )
- kon.sleep(1.0)
- flick.kill_join()
+ bak = arr.get_sdic(c)
+ lst = map( lambda col: mk_slst('==', col, False), ('white', 'blue') )
+ slider = kon.slider(lst, 4.0, None, True)
+ arr.set_sdic( c, ('slider', slider) )
+ kon.sleep(2.0)
+ arr.set_sdic(c, bak)
game_ev.set('clear')
kdir = kon.gval('')
@@ -321,8 +242,8 @@
def th_pac(c):
stat = stat_get(c)
- (px, py) = stat.pos
- pd = stat.dir
+ (px, py) = arr.pos(c)
+ pd = arr.get_dir(c)
ds = next_ds(px, py, c)
kd = kdir()
@@ -330,64 +251,96 @@
d = kd if kd and kd in ds else pd if pd in ds else ''
(nx, ny) = step_to(px, py, d)
if d:
- stat.dir = d
- stat.pos = (nx, ny)
- lock_move.f(px, py, nx, ny, c)
+ hz = get_hz(c, nx, ny)
+ move(c, d, hz)
try_eat(nx, ny)
-def sel_mon_way(c, x, y, ds):
- def rand(n):
- v = sum( sum( map( lambda c: list( stat_get(c).pos ), MOVES ), [] ) )
- return ( v / 4 ) % n
- rand_sel = lambda lst: lst[ rand( len(lst) ) ]
-
- (tx, ty) = stat_get('P').pos
- xd = R if tx - x > 0 else L
- yd = D if ty - y > 0 else U
+def rand(n):
+ v = sum( sum( map( lambda c: list( arr.pos(c) ), MOVES ), [] ) )
+ return ( v / 4 ) % n
+
+rand_sel = lambda lst: lst[ rand( len(lst) ) ]
+
+def ways(x, y, tx, ty, ds, rev=False):
+ (dx, dy) = (tx - x, ty - y)
+ xd = R if dx > 0 else L
+ yd = D if dy > 0 else U
+ if rev:
+ (xd, yd) = ( kon.bak_dir(xd), kon.bak_dir(yd) )
rd = rand_sel(ds)
+ ds_ = [ xd, yd, rd ] if abs(dx) > abs(dy) else [ yd, xd, rd ]
+ return next( ( d for d in ds_ if d in ds ), ds[0] )
- return {
- 'M': lambda: yd if yd in ds else rd,
- 'R': lambda: xd if xd in ds else yd if yd in ds else rd,
- 'C': lambda: xd if xd in ds else rd,
- 'Y': lambda: rd,
- }.get(c)()
+def sel_mon_way(c, x, y, ds):
+ mode = mon_mode(c)
+ if mode == 'ret':
+ return mon_ret_buf.get(x, y)
+
+ pd = arr.get_dir(c)
+ ds_ = filter( lambda d: d != kon.bak_dir(pd), ds )
+ ds = ds_ if ds_ else ds
+
+ (tx, ty) = arr.pos('P')
+
+ if mode in ('weak', 'blink'):
+ return ways(x, y, tx, ty, ds, rev=True)
+
+ if mode == 'run' and run_mode.get() == 'pato':
+ # MONS = 'RCMY'
+ (w2, h2) = (w/2, h/2)
+ area_d = {
+ 'R': (w2, 0, w2, h2),
+ 'C': (w2, h2, w2, h2),
+ 'M': (0, 0, w2, h2),
+ 'Y': (0, h2, w2, h2),
+ }
+ area = area_d.get(c)
+ d = pato_buf.get(x, y)
+ if kon.chk_xywh(x, y, *area) and d in DIRS:
+ return d
+ (ax, ay) = kon.cen_xywh(*area)
+ return ways(x, y, ax, ay, ds)
+
+ if c == 'R':
+ return ways(x, y, tx, ty, ds)
+ if c == 'C':
+ return ways(x, y, 2*x-tx, 2*y-ty, ds)
+ if c == 'M':
+ (dx, dy) = kon.dir_to_xy( arr.get_dir('P') )
+ return ways(x, y, tx + dx * 3, ty + dy * 3, ds)
+ return rand_sel(ds)
def th_mon(c):
stat = stat_get(c)
- (px, py) = stat.pos
- pd = stat.dir
- mode = mon_mode(c)
-
+ (px, py) = arr.pos(c)
ds = next_ds(px, py, c)
- d = ds[0]
- if mode == 'ret':
- d = mon_ret_buf.get(px, py)
- else:
- ds_ = filter( lambda d: d != kon.bak_dir(pd), ds )
- ds = ds_ if ds_ else ds
- d = ds[0] if len(ds) == 1 else sel_mon_way(c, px, py, ds)
+
+ d = sel_mon_way(c, px, py, ds)
(nx, ny) = step_to(px, py, d)
- stat.dir = d
- stat.pos = (nx, ny)
- lock_move.f(px, py, nx, ny, c)
+ hz = get_hz(c, nx, ny)
+ move(c, d, hz)
+ mode = mon_mode(c)
if mode == 'cage' and pac_buf.get(px, py) == '=':
mon_mode(c, 'run')
elif mode == 'ret' and mon_ret_buf.get(nx, ny) == ' ':
mon_mode(c, 'cage')
- stat.th.hz = get_hz(c, nx, ny)
-
def score_new():
(x, y, lb, col, r) = (0, 0, 'score ', 'white', False)
e = kon.Empty()
e.v = 0
+ def chk_1up(add):
+ t = 10000
+ if e.v >= t and e.v - add < t:
+ spare(1)
+ arr_msg_pause( mk_slst('1UP') )
def f(add=0):
e.v += add
(dx, s) = (0, lb) if add == 0 else ( len(lb), str(e.v) )
kon.show(x + dx, y, s, col, r, flush_f=True)
+ chk_1up(add)
return f
score = score_new()
@@ -422,76 +375,113 @@
spare = spare_new(2)
+gate = kon.counter(4)
+
+mon_turn = lambda: map( lambda c: arr.set_dir( c, kon.bak_dir( arr.get_dir(c) ) ), MONS )
+run_mode = kon.slider( ['pato', 'chase'], f=mon_turn )
+
def work():
- kon.lock_show.cond_f = lambda: not game_ev.get()
+ kon.clr()
+
+ dot_n = len( pac_buf.poss('.') + pac_buf.poss('O') )
def init_map():
(w, h) = pac_buf.size()
arr.clear()
def f(x, y):
c = pac_buf.get(x, y)
- arr.set(x, y, c, True)
- arr.update(x, y)
+ arr.set(x, y, c)
kon.loop_xy(w, h, f)
flush()
def init_stat(clear=False):
for c in MOVES:
- stat = stat_get(c)
- stat.dir = L if c == 'P' else U
- stat.pos = pac_buf.pos(c)
- stat.dx = 0
+ (x, y) = pac_buf.pos(c)
+ d = L if c == 'P' else U
+ arr.set(x, y, c, True, True, d)
+
if c in MONS:
- stat.mode = 'cage' if c in 'CMY' else 'run'
- stat.flick.stop()
+ mon_mode( c, 'cage' if c in 'CMY' else 'run' )
if clear:
+ stat = stat_get(c)
stat.hz *= 1.2
- stat.th.hz = stat.hz
+ stat.th.set_hz(stat.hz)
if c == 'P':
- stat.dot = len( pac_buf.pos('.') + pac_buf.pos('O') )
+ stat.dot = dot_n
+ mon_r_hz = stat_get('R').hz
+ gate.set_hz( mon_r_hz / 10.0 )
+ gate.restart()
+
+ run_mode.set_hz( mon_r_hz / 100.0 )
+ run_mode.restart()
+
+ lst = map( lambda r: mk_slst('O ', 'yellow', r), (False, True) )
+ arr.set_sdic( 'O', ( 'slider', kon.slider(lst, 2.0, None, True) ) )
+
+ arr.set_sdic( 'P', ('func', pac_show) )
+ arr.set_sdic( '#', ('func', blk_show) )
+ arr.set_sdic( '.', ( '', mk_slst('. ', 'white', False) ) )
+ arr.set_sdic( '=', ( '', mk_slst('==', 'yellow', False) ) )
kon.th_loop(th_key)
score()
spare()
- init_map()
- for (c, stat) in c_stat_gets(MOVES):
+ stat_get('P').dot = dot_n
+ map( lambda c: set( stat_get(c), 'hz', 3.0 if c == 'P' else 3.3 ), MOVES )
+ map( lambda c: set( stat_get(c), 'timer', kon.timer_new() ), MONS )
+
+ for c in MOVES:
+ stat = stat_get(c)
f = th_pac if c == 'P' else th_mon
- stat.th = kon.th_loop(f, [c], stat.hz, False)
+ stat.th = kon.th_loop(f, [c], stat.hz, run=False)
- run = True
- while run:
- (x, y) = pac_buf.pos('B')
- line_msg_pause(x, y, 'READY!', 'yellow', False, 1.0)
+ hdl_ready = lambda: arr_msg_pause( mk_slst('READY!', 'yellow'), *pac_buf.pos('B') )
+ hdl_start = lambda: map( lambda c: stat_get(c).th.start(), MOVES )
+ hdl_stop = lambda: map( lambda c: stat_get(c).th.stop(), MOVES )
+ hdl_timer_cancel = lambda: map( lambda c: stat_get(c).timer.cancel(), MONS )
+ hdl_rm = lambda: ( map( lambda c: arr.rm(c), MOVES ), arr.update_all(flush_f=True) )[-1]
- map( lambda stat: stat.th.start(), stat_gets(MOVES) )
+ init_map()
+ init_stat()
+ hdl_ready()
+ hdl_start()
+ while True:
while not game_ev.wait(1.0):
kon.sleep_hz(1.0) # for ^C
- for stat in stat_gets(MOVES):
- stat.th.stop()
- stat.late_tmr.cancel()
- if has(stat, 'timer'):
- stat.timer.cancel()
- kon.sleep(1.0)
-
v = game_ev.get()
- game_ev.clear()
-
- for (c, stat) in c_stat_gets(MOVES):
- (x, y) = stat.pos
- arr.set(x, y, c, False)
- xys = [(x, y)] + map( lambda d: step_to(x, y, d), DIRS )
- arr.update_xys( xys, flush_f=True )
-
- if v == 'die':
+ if v == 'start':
+ hdl_start()
+ elif v == 'stop':
+ hdl_stop()
+
+ elif v == 'die':
+ hdl_stop()
+ hdl_timer_cancel()
+ kon.sleep(2.0)
+ hdl_rm()
init_stat()
+ hdl_ready()
+ hdl_start()
+ mov.en = True
+
elif v == 'clear':
- init_stat(clear=True)
+ hdl_stop()
+ hdl_timer_cancel()
+ kon.sleep(2.0)
+ hdl_rm()
init_map()
+ init_stat(clear=True)
+ hdl_ready()
+ hdl_start()
+ mov.en = True
+
elif v == 'over':
- run = False
+ break
+
+ game_ev.clear()
if __name__ == "__main__":
kon.main( work, '[-bw] [-m]' )
diff -urN v2/pato.txt v3/pato.txt
--- v2/pato.txt 1970-01-01 09:00:00.000000000 +0900
+++ v3/pato.txt 2017-10-17 03:15:12.000000000 +0900
@@ -0,0 +1,23 @@
+#####################
+#dllll # rrrrd#
+#d###u### # ###u###d#
+#d###u### # ###u###d#
+#d###u### # ###u###d#
+#rrrru ullll#
+# ### # ##### # ### #
+# # # # #
+##### ### # ### #####
+ # # # #
+##### # ## ## # #####
+ # #
+##### # ##### # #####
+ # # # #
+##### # ##### # #####
+#rrrrd # dllll#
+#u###d### # ###d###u#
+#ull#d d#rru#
+###u#d# ##### #d#u###
+# ull# # #rru #
+# ####### # ####### #
+# #
+#####################
diff -urN v2/warp.txt v3/warp.txt
--- v2/warp.txt 2017-10-06 22:00:00.000000000 +0900
+++ v3/warp.txt 2017-10-17 03:15:12.000000000 +0900
@@ -4,9 +4,9 @@
# ### ### # ### ### #
# ### ### # ### ### #
# #
-# ### #u#####u# ### #
+# ### # ##### # ### #
# # # # #
-##### ### # ### #####
+##### ###d#d### #####
# # # #
##### # ##u## # #####
L4321 # # 1234R
@@ -14,7 +14,7 @@
# # # #
##### # ##### # #####
# # #
-# ### ### # ### ### #
+# ### ###d#d### ### #
# # # #
### # # ##### # # ###
# # # # #
$ cat v3.patch | patch -p1 $ chmod +x pac.py $ ./pac.py
昔の記憶で適当に作ってましたが、少し調べてみました。
v4.patch
diff -ur v3/pac.py v4/pac.py
--- v3/pac.py 2017-10-17 03:15:30.000000000 +0900
+++ v4/pac.py 2017-10-17 23:00:00.000000000 +0900
@@ -14,6 +14,8 @@
MONS = 'RCMY'
MOVES = 'P' + MONS
+dot_n = len( pac_buf.poss('.') + pac_buf.poss('O') )
+
stat_inf = dict( map( lambda c: ( c, kon.Empty() ), MOVES ) )
stat_get = lambda c: stat_inf.get(c)
@@ -71,16 +73,13 @@
mon_price.check()
- stat.th.set_hz( get_hz( c, *arr.pos(c) ) )
-
-
mon_hz_rate = { 'weak': 0.3, 'blink': 0.3, 'ret': 1.5 }
warp_rate = { '1': 0.8, '2': 0.6, '3': 0.4, '4': 0.3, 'L': 0.2, 'R': 0.2 }
arr_xy_to_show_xy = lambda x, y: (x * 2, y + 1) # for aspect and score
(w, h) = pac_buf.size()
-bit_cs = MOVES + 'O.=#'
+bit_cs = MOVES + 'O.=#B'
arr = kon.arr_xy_bit_c_move_new( w, h, bit_cs, arr_xy_to_show_xy)
is_warp = lambda x, y, d: ( lambda wc: wc if wc in ('L', 'R') and wc.lower() == d else False )( warp_buf.get(x, y) )
@@ -118,20 +117,20 @@
next_ds = lambda x, y, c: filter( lambda d: is_step(x, y, c, d), DIRS )
def arr_msg_pause(show_lst, x=None, y=None, sec=1.0, xcen=True):
- game_ev.set('stop')
+ ths_stop()
(bx, by) = pac_buf.pos('B')
x = bx if x == None else x
y = by if y == None else y
arr.msg_pause(x, y, show_lst, sec, xcen)
- game_ev.set('start')
+ ths_start()
def pac_slider(slider):
- game_ev.set('stop')
+ ths_stop()
c = 'P'
bak = arr.get_sdic(c)
arr.set_sdic( c, ('slider', slider) )
slider.wait()
- game_ev.set('start')
+ ths_start()
return bak
game_ev = kon.evt()
@@ -159,13 +158,8 @@
break
elif mode != 'ret' and not NO_DIE:
mov.en = False
- ss = [ '()', '||', ')(', '><', '--', '><', '--', '><', '--', '__', ' ' ]
- lsts = map( lambda s: mk_slst(s, 'yellow', True), ss )
- lsts.append( [ SPC ] )
- bak = pac_slider( kon.slider(lsts, 5.0, None, True, repeat=False) )
v = 'over' if spare(-1) == 'over' else 'die'
game_ev.set(v)
- arr.set_sdic('P', bak)
break
def get_hz(c, nx, ny):
@@ -212,25 +206,79 @@
arr.set_dir( c, kon.bak_dir( arr.get_dir(c) ) )
stat.timer.start( tmr_f, [c], short_sec(15.0) )
+round = kon.gval(1)
+
+def bonus_new():
+ c = 'B'
+ (x, y) = pac_buf.pos(c)
+
+ cherry = ( [ ('8', 'red', True), ('>', 'green', False) ], 100 )
+ strawberry = ( [ ('<', 'magenta', True), ('k', 'green', False) ], 300 )
+ orange = ( [ ('O', 'yellow', 'True'), ('-', 'green', False) ], 500 )
+ apple = ( [ ('()', 'red', True) ], 700 )
+ melon = ( [ ('<>', 'green', True) ], 1000 )
+ galaxyan = ( [ ('<', 'red', False), ('<', 'blue', False) ], 2000 )
+ bell =( [ ('.>', 'white', True) ], 3000 )
+ key = ( [ ('=', 'white', False), ('m', 'cyan', False) ], 5000 )
+
+ d = {
+ 1: cherry, 2: strawberry,
+ 3: orange, 4: orange,
+ 5: apple, 6: apple,
+ 7: melon, 8: melon,
+ 9: galaxyan, 10: galaxyan,
+ 11: bell, 12: bell,
+ }
+ get_inf = lambda: d.get( round(), key )
+ get_slst = lambda: get_inf()[0]
+
+ tmr = kon.timer_new()
+
+ e = kon.Empty()
+ e.eat_cnt = 0
+ e.get_v = lambda: get_inf()[1]
+
+ def hide():
+ tmr.cancel()
+ arr.rm(c, flush_f=True)
+ e.hide = hide
+ def show():
+ hide()
+ arr.set_sdic( c, ( '', get_slst() ) )
+ arr.set( x, y, c, flush_f=True )
+ sec = short_sec(15.0)
+ tmr.start( hide, [], sec )
+ e.show = show
+ def eat():
+ e.eat_cnt += 1
+ hide()
+ (vx, vy) = arr_xy_to_show_xy( *pac_buf.size() )
+ vx -= 3 * e.eat_cnt
+ kon.shows(vx, vy, get_slst(), flush_f=True)
+ e.eat = eat
+ return e
+
+bonus = bonus_new()
+
def try_eat(x, y):
- c = '.' if arr.get(x, y, '.') else 'O' if arr.get(x, y, 'O') else ''
- if not c:
+ lst = filter( lambda c: c in '.OB', arr.gets(x, y) )
+ if not lst:
return
- arr.set(x, y, c, False)
- stat_get('P').dot -= 1
+ c = lst[0]
+
+ if c in '.O':
+ arr.set(x, y, c, False)
+ stat_get('P').dot -= 1
+ else:
+ bonus.eat()
- score( 50 if c == 'O' else 10 )
+ score( 50 if c == 'O' else 10 if c == '.' else bonus.get_v() )
if c == 'O':
mon_weak()
+ if c in '.O' and dot_n - stat_get('P').dot in (70, 170):
+ bonus.show()
if stat_get('P').dot <= 0:
mov.en = False
- c = '#'
- bak = arr.get_sdic(c)
- lst = map( lambda col: mk_slst('==', col, False), ('white', 'blue') )
- slider = kon.slider(lst, 4.0, None, True)
- arr.set_sdic( c, ('slider', slider) )
- kon.sleep(2.0)
- arr.set_sdic(c, bak)
game_ev.set('clear')
kdir = kon.gval('')
@@ -311,7 +359,6 @@
return rand_sel(ds)
def th_mon(c):
- stat = stat_get(c)
(px, py) = arr.pos(c)
ds = next_ds(px, py, c)
@@ -327,6 +374,8 @@
elif mode == 'ret' and mon_ret_buf.get(nx, ny) == ' ':
mon_mode(c, 'cage')
+ stat_get(c).th.set_hz(hz)
+
def score_new():
(x, y, lb, col, r) = (0, 0, 'score ', 'white', False)
e = kon.Empty()
@@ -380,18 +429,43 @@
mon_turn = lambda: map( lambda c: arr.set_dir( c, kon.bak_dir( arr.get_dir(c) ) ), MONS )
run_mode = kon.slider( ['pato', 'chase'], f=mon_turn )
-def work():
+def init_once():
kon.clr()
- dot_n = len( pac_buf.poss('.') + pac_buf.poss('O') )
+ lst = map( lambda r: mk_slst('O ', 'yellow', r), (False, True) )
+ arr.set_sdic( 'O', ( 'slider', kon.slider(lst, 2.0, None, True) ) )
+
+ arr.set_sdic( 'P', ('func', pac_show) )
+ arr.set_sdic( '#', ('func', blk_show) )
+ arr.set_sdic( '.', ( '', mk_slst('. ', 'white', False) ) )
+ arr.set_sdic( '=', ( '', mk_slst('==', 'yellow', False) ) )
+
+ kon.th_loop(th_key)
+
+ score()
+ spare()
+
+ map( lambda c: set( stat_get(c), 'hz', 3.0 if c == 'P' else 3.3 ), MOVES )
+ map( lambda c: set( stat_get(c), 'timer', kon.timer_new() ), MONS )
+
+ for c in MOVES:
+ stat = stat_get(c)
+ f = th_pac if c == 'P' else th_mon
+ stat.th = kon.th_loop(f, [c], stat.hz, run=False)
+
+ths_start = lambda: map( lambda c: stat_get(c).th.start(), MOVES )
+ths_stop = lambda: map( lambda c: stat_get(c).th.stop(), MOVES )
+ths_timer_cancel = lambda: map( lambda c: stat_get(c).timer.cancel(), MONS )
+
+def work():
+ init_once()
def init_map():
- (w, h) = pac_buf.size()
arr.clear()
- def f(x, y):
- c = pac_buf.get(x, y)
- arr.set(x, y, c)
+ f = lambda x, y: arr.set( x, y, pac_buf.get(x, y) )
+ (w, h) = pac_buf.size()
kon.loop_xy(w, h, f)
+ arr.rm('B')
flush()
def init_stat(clear=False):
@@ -415,70 +489,59 @@
run_mode.set_hz( mon_r_hz / 100.0 )
run_mode.restart()
- lst = map( lambda r: mk_slst('O ', 'yellow', r), (False, True) )
- arr.set_sdic( 'O', ( 'slider', kon.slider(lst, 2.0, None, True) ) )
-
- arr.set_sdic( 'P', ('func', pac_show) )
- arr.set_sdic( '#', ('func', blk_show) )
- arr.set_sdic( '.', ( '', mk_slst('. ', 'white', False) ) )
- arr.set_sdic( '=', ( '', mk_slst('==', 'yellow', False) ) )
-
- kon.th_loop(th_key)
- score()
- spare()
-
stat_get('P').dot = dot_n
- map( lambda c: set( stat_get(c), 'hz', 3.0 if c == 'P' else 3.3 ), MOVES )
- map( lambda c: set( stat_get(c), 'timer', kon.timer_new() ), MONS )
-
- for c in MOVES:
- stat = stat_get(c)
- f = th_pac if c == 'P' else th_mon
- stat.th = kon.th_loop(f, [c], stat.hz, run=False)
- hdl_ready = lambda: arr_msg_pause( mk_slst('READY!', 'yellow'), *pac_buf.pos('B') )
- hdl_start = lambda: map( lambda c: stat_get(c).th.start(), MOVES )
- hdl_stop = lambda: map( lambda c: stat_get(c).th.stop(), MOVES )
- hdl_timer_cancel = lambda: map( lambda c: stat_get(c).timer.cancel(), MONS )
- hdl_rm = lambda: ( map( lambda c: arr.rm(c), MOVES ), arr.update_all(flush_f=True) )[-1]
+ def ready_go():
+ arr_msg_pause( mk_slst('READY!', 'yellow'), *pac_buf.pos('B') )
+ ths_start()
+ mov.en = True
+
+ def goal():
+ ths_stop()
+ ths_timer_cancel()
+ kon.sleep(2.0)
+ map( lambda c: arr.rm(c), MOVES )
+ bonus.hide()
+ arr.update_all(flush_f=True)
init_map()
init_stat()
- hdl_ready()
- hdl_start()
+ ready_go()
while True:
while not game_ev.wait(1.0):
kon.sleep_hz(1.0) # for ^C
v = game_ev.get()
- if v == 'start':
- hdl_start()
- elif v == 'stop':
- hdl_stop()
-
- elif v == 'die':
- hdl_stop()
- hdl_timer_cancel()
- kon.sleep(2.0)
- hdl_rm()
+ if v == 'die':
+ ss = [ '()', '||', ')(', '><', '--', '><', '--', '><', '--', '__', ' ' ]
+ lsts = map( lambda s: mk_slst(s, 'yellow', True), ss )
+ lsts.append( [ SPC ] )
+ bak = pac_slider( kon.slider(lsts, 5.0, None, True, repeat=False) )
+
+ goal()
init_stat()
- hdl_ready()
- hdl_start()
- mov.en = True
+ arr.set_sdic('P', bak)
+ ready_go()
elif v == 'clear':
- hdl_stop()
- hdl_timer_cancel()
- kon.sleep(2.0)
- hdl_rm()
+ c = '#'
+ bak = arr.get_sdic(c)
+ lst = map( lambda col: mk_slst('==', col, False), ('white', 'blue') )
+ slider = kon.slider(lst, 4.0, None, True)
+ arr.set_sdic( c, ('slider', slider) )
+ kon.sleep(3.0)
+ arr.set_sdic(c, bak)
+
+ goal()
+ round( round() + 1 )
init_map()
init_stat(clear=True)
- hdl_ready()
- hdl_start()
- mov.en = True
+ ready_go()
elif v == 'over':
+ (x, y) = pac_buf.pos('B')
+ arr_msg_pause( mk_slst('GAME OVER', 'red'), x, y, 2.0 )
break
game_ev.clear()
$ cat v4.patch | patch -p1 $ chmod +x pac.py $ ./pac.py
v5.patch
diff -ur v4/kon.py v5/kon.py
--- v4/kon.py 2017-10-17 23:00:00.000000000 +0900
+++ v5/kon.py 2017-10-19 23:00:00.000000000 +0900
@@ -6,13 +6,49 @@
import termios
import select
import threading
+import socket
def dbg(s, *arg):
sys.stderr.write(s.format(*arg) + os.linesep)
sys.stdout.flush()
-def out(s):
- sys.stdout.write(s)
+def get_arg(k):
+ # -k -k=xxx --k --k=xxx
+ for ds in ('-', '--'):
+ t = ds + k
+ if t in sys.argv:
+ return ''
+ t += '='
+ r = next( ( a[ len(t): ] for a in sys.argv if a.startwith(t) ), None )
+ if r != None:
+ return r
+ return None
+
+def get_host_port(s, host='localhost', port=12345):
+ if not s:
+ return (host, port)
+ if ':' in s:
+ (h, p) = s.split(':')
+ if h:
+ host = h
+ if p:
+ port = p
+ else:
+ if s.isdigit():
+ port = int(s)
+ else:
+ host = s
+ return (host, port)
+
+def out_new():
+ sock = None
+ s = get_arg('o')
+ if s != None:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect( get_host_port(s, port=55765) )
+ return lambda s: ( sock.sendall if sock else sys.stdout.write )(s)
+
+out = out_new()
def flush():
sys.stdout.flush()
diff -ur v4/pac.py v5/pac.py
--- v4/pac.py 2017-10-17 23:00:00.000000000 +0900
+++ v5/pac.py 2017-10-19 23:00:00.000000000 +0900
@@ -158,17 +158,20 @@
break
elif mode != 'ret' and not NO_DIE:
mov.en = False
- v = 'over' if spare(-1) == 'over' else 'die'
+ v = 'over' if spare(-1) == 'over' or is_remote else 'die'
game_ev.set(v)
break
-def get_hz(c, nx, ny):
+def get_hz(c, nx, ny, nd):
hz = stat_get(c).hz
if c in MONS:
mode = mon_mode(c)
hz *= mon_hz_rate.get(mode, 1.0)
if mode != 'ret':
hz *= warp_rate.get( warp_buf.get(nx, ny), 1.0 )
+ if c == 'P':
+ if nd != arr.get_dir(c):
+ hz *= 1.5
return hz
def move_new():
@@ -288,20 +291,36 @@
if d in DIRS and d != kdir():
kdir(d)
+is_remote = '-r' in sys.argv
+
+def pac_remote(pd, ds):
+ ds = filter( lambda d: d != kon.bak_dir(pd), ds )
+ if len(ds) == 1:
+ return ds[0]
+
+ d = sys.stdin.read(1)
+ if d not in ds:
+ sys.stdout.write('?')
+ sys.stdout.write(d)
+ flush()
+
def th_pac(c):
- stat = stat_get(c)
(px, py) = arr.pos(c)
pd = arr.get_dir(c)
-
ds = next_ds(px, py, c)
- kd = kdir()
+ d = ''
+ if is_remote:
+ d = pac_remote(pd, ds)
+ else:
+ kd = kdir()
+ d = kd if kd and kd in ds else pd if pd in ds else ''
- d = kd if kd and kd in ds else pd if pd in ds else ''
(nx, ny) = step_to(px, py, d)
if d:
- hz = get_hz(c, nx, ny)
+ hz = get_hz(c, nx, ny, d)
move(c, d, hz)
try_eat(nx, ny)
+ stat_get(c).th.set_hz(hz)
def rand(n):
v = sum( sum( map( lambda c: list( arr.pos(c) ), MOVES ), [] ) )
@@ -365,7 +384,7 @@
d = sel_mon_way(c, px, py, ds)
(nx, ny) = step_to(px, py, d)
- hz = get_hz(c, nx, ny)
+ hz = get_hz(c, nx, ny, d)
move(c, d, hz)
mode = mon_mode(c)
@@ -547,5 +566,5 @@
game_ev.clear()
if __name__ == "__main__":
- kon.main( work, '[-bw] [-m]' )
+ kon.main( work, '[-bw] [-m] [-o[=host:port]] [-r]' )
# EOF
$ cat v5.patch | patch -p1 $ chmod +x pac.py $ ./pac.py
「角を曲がるときはモンスターより速度が速くなる」と言う情報がありました。
そう言えば昔ゲーセンで、内側の迷路をクネクネ曲がって逃げてると、 うまく振り切れていた覚えがあります。
安易に「向きを変える瞬間だけ速度アップ」処理を追加してみました。
標準出力を他に使いたくなったので、出力先を別のホストのポートに飛ばせるようにしてみました。
-o=ホスト名:ポート番号 または --o=ホスト名:ポート番号 ホスト名を省略すると localhost ポート番号を省略すると 55765
で指定します。
「クリアパターン」を探すために、「リモートモード」なるものを追加してみました。
起動オプション -r でリモートモードになる事にします。
リモートモードでは、
リモートモードの時は、この用途で標準出力を使うので、-o も合わせて指定するようにします。
そして、「クリアパターン」を探すプログラム...
v6.patch
diff -urN v5/fuga.py v6/fuga.py
--- v5/fuga.py 1970-01-01 09:00:00.000000000 +0900
+++ v6/fuga.py 2018-02-21 13:09:19.000000000 +0900
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+import sys
+import time
+import random
+
+if __name__ == "__main__":
+
+ err = lambda s: sys.stderr.write(s+'\n')
+
+ while True:
+ s = sys.stdin.readline().strip()
+ err('get "{}"'.format(s))
+
+ i = random.randrange(len(s))
+ err('out "{}"'.format( s[i] ) )
+ print s[i]
+ sys.stdout.flush()
+# EOF
diff -urN v5/kon.py v6/kon.py
--- v5/kon.py 2017-10-19 23:00:00.000000000 +0900
+++ v6/kon.py 2018-02-21 13:09:19.000000000 +0900
@@ -19,7 +19,7 @@
if t in sys.argv:
return ''
t += '='
- r = next( ( a[ len(t): ] for a in sys.argv if a.startwith(t) ), None )
+ r = next( ( a[ len(t): ] for a in sys.argv if a.startswith(t) ), None )
if r != None:
return r
return None
@@ -32,7 +32,7 @@
if h:
host = h
if p:
- port = p
+ port = int(p)
else:
if s.isdigit():
port = int(s)
@@ -236,7 +236,11 @@
def term_raw(sigint=True):
fd = sys.stdin.fileno()
- a = termios.tcgetattr(fd)
+ try:
+ a = termios.tcgetattr(fd)
+ except:
+ return lambda : None
+
bak = a[:]
f = termios.ECHO | termios.ECHONL | termios.FLUSHO | termios.ICANON | termios.IEXTEN
if not sigint:
diff -urN v5/pac.py v6/pac.py
--- v5/pac.py 2017-10-19 23:00:00.000000000 +0900
+++ v6/pac.py 2018-02-21 13:09:19.000000000 +0900
@@ -298,11 +298,13 @@
if len(ds) == 1:
return ds[0]
- d = sys.stdin.read(1)
+ sys.stdout.write(ds + '\n')
+ flush()
+ d = sys.stdin.readline().strip()
if d not in ds:
sys.stdout.write('?')
- sys.stdout.write(d)
- flush()
+ d = ds[0]
+ return d
def th_pac(c):
(px, py) = arr.pos(c)
diff -urN v5/stdio.py v6/stdio.py
--- v5/stdio.py 1970-01-01 09:00:00.000000000 +0900
+++ v6/stdio.py 2018-02-21 12:28:53.000000000 +0900
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+import sys
+import subprocess
+
+#
+# ./stdio.py "./hoge.py 123" ./hoge.py
+#
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 3:
+ print 'Usage: {} "cmd1 prm .." "cmd2 prm .."'.format(sys.argv[0])
+ sys.exit(0)
+
+ cmd1 = sys.argv[1]
+ cmd2 = sys.argv[2]
+ cmd = 'rm -f fifo ; mkfifo fifo ; cat fifo | {} | {} > fifo'.format(cmd1, cmd2)
+ #print cmd
+
+ subprocess.call(cmd, shell=True)
+
+# EOF
随分間が空いて年も変わりましたが、少しだけ更新してみます。
リモートモードを試してみると、案の定バグを発見。 修正しつつ、仕様も少し変えました。
$ cat v6.patch | patch -p1
stdio.py と fuga.py を追加しました。
stdio.py は2つの引数を取り、2つのコマンドとして起動します。 その2つのコマンドの標準入出力を、互い違いに繋ぎます。
fuga.py はリモートモードの pac.py の相手をする、 プログラムの雛形です。 今はとりあえず、乱数で、でたらめなキー操作になってます。
まず表示用に別の端末から
other-term $ nc -l -k 55765
などと netcat で 55765 ポートで待ち受けておいて
$ ./stdio.py "./pac.py -o -r" ./fuga.py
として、pac.py と fuga.py の標準入出力を相互に繋いだ状態で起動します。
pac.py が岐路に差し掛かると、選択肢の候補を fuga.py に出力します。
fuga.py は受け取った候補からランダムに1つ選んで、pac.py に返答します。
pac.py は受け取った方向に進めようとします。
とりあえず動作確認だけなので、すぐGAME OVERです :-p)
v7.patch
diff -urN v6/kon.py v7/kon.py
--- v6/kon.py 2018-02-21 13:09:19.000000000 +0900
+++ v7/kon.py 2018-06-22 23:10:50.000000000 +0900
@@ -8,6 +8,14 @@
import threading
import socket
+map_lst = lambda f, lst: list( map( f, lst ) )
+map_up = lambda f, lst: map( lambda a: f(*a), lst )
+map_up_lst = lambda f, lst: list( map_up( f, lst ) )
+
+filter_lst = lambda f, lst: list( filter( f, lst ) )
+filter_up = lambda f, lst: filter( lambda a: f(*a), lst )
+filter_up_lst = lambda f, lst: list( filter_up(f, lst) )
+
def dbg(s, *arg):
sys.stderr.write(s.format(*arg) + os.linesep)
sys.stdout.flush()
@@ -46,7 +54,7 @@
if s != None:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect( get_host_port(s, port=55765) )
- return lambda s: ( sock.sendall if sock else sys.stdout.write )(s)
+ return lambda s: ( sock.sendall if sock else sys.stdout.write )( s.encode() )
out = out_new()
@@ -84,13 +92,13 @@
dic_to_cls( cls_to_dic(pcls), self )
def cls_to_dic(c):
- ks = filter( lambda k: not k.startswith('_'), dir(c) )
- return dict( map( lambda k: ( k, getattr(c, k) ), ks ) )
+ ks = filter_lst( lambda k: not k.startswith('_'), dir(c) )
+ return dict( map_lst( lambda k: ( k, getattr(c, k) ), ks ) )
def dic_to_cls(d, c=None):
if not c:
c = Empty()
- map( lambda (k, v): setattr(c, k, v), d.items() )
+ map_up_lst( lambda k, v: setattr(c, k, v), d.items() )
return c
def extends(pcls, c=None):
@@ -130,7 +138,7 @@
e.f = wrap_f
return e
-updiv = lambda a, b: (a + b - 1) / b
+updiv = lambda a, b: int( (a + b - 1) / b )
hz_to_sec = lambda hz: 1.0 / hz if hz > 0 else 0
sec_to_hz = lambda sec: 1.0 / sec if sec > 0 else 0
@@ -255,7 +263,8 @@
def getkey(tmout=None):
fd = sys.stdin.fileno()
- return os.read(fd, 1) if readable(fd, tmout) else ''
+ #return os.read(fd, 1) if readable(fd, tmout) else ''
+ return os.read(fd, 1).decode() if readable(fd, tmout) else ''
esc = lambda s: chr(0x1b) + '[' + s
esc_ex = lambda d, v: esc( '?{}{}'.format(d, 'h' if v else 'l' ) )
@@ -263,7 +272,7 @@
DIRS = ( U, D, L, R ) = 'udlr'
bak_dir = lambda d: { U: D, D: U, L: R, R: L }.get(d)
dir_to_xy = lambda d: { U: (0, -1), D: (0, 1), L: (-1, 0), R: (1, 0) }.get(d, (0, 0) )
-step_to = lambda x, y, d: ( lambda (dx, dy): (x+dx, y+dy) )( dir_to_xy(d) )
+step_to = lambda x, y, d: ( lambda dx, dy: (x+dx, y+dy) )( *dir_to_xy(d) )
def keydir(tmout=None):
ctl = lambda s: chr( 1 + ord(s) - ord('a') )
@@ -272,12 +281,12 @@
[ ctl('p'), ctl('n'), ctl('b'), ctl('f') ], # emacs
[ 'k', 'j', 'h', 'l' ], # vi
]
- d = dict( sum( map( lambda k4: zip(k4, DIRS), lst ), [] ) )
+ d = dict( sum( map_lst( lambda k4: list( zip(k4, DIRS) ), lst ), [] ) )
d.update({ ctl('a'): L, ctl('e'): R}) # emacs
d.update({ '\n': U, '\t': 'U', ' ': 'U' })
keys = d.keys()
buf = getkey(tmout)
- while buf and any( map( lambda k: k.startswith(buf), keys ) ):
+ while buf and any( map_lst( lambda k: k.startswith(buf), keys ) ):
if buf in keys:
return d.get(buf)
buf += getkey(tmout)
@@ -331,23 +340,25 @@
(s_, col_, r_) = lst[0]
return mk_slst(s + s_, col, r) + lst[1:] if col == col_ and r == r_ else [a] + lst
-split_show_lst = lambda lst: sum( map( lambda (s, col, r): map( lambda c: (c, col, r), s ), lst ), [] )
+split_show_lst = lambda lst: sum( map_up_lst( lambda s, col, r: map_lst( lambda c: (c, col, r), s ), lst ), [] )
-show_lst_len = lambda lst: sum( map( lambda (s, col, r): len(s), lst ) )
+show_lst_len = lambda lst: sum( map_up_lst( lambda s, col, r: len(s), lst ) )
def fit_show_lsts(show_lsts):
- ns = map( show_lst_len, show_lsts )
+ ns = map_lst( show_lst_len, show_lsts )
max_n = max(ns)
- return map( lambda (lst, n): sum_show_lst( lst + mk_slst(' ') * (max_n - n) ), zip( show_lsts, ns ) )
+ return map_up_lst( lambda lst, n: sum_show_lst( lst + mk_slst(' ') * (max_n - n) ), zip( show_lsts, ns ) )
def shows(x, y, lst, flush_f=False):
- x = reduce( lambda x, (s, col, r): show(x, y, s, col, r), sum_show_lst(lst), x )
+ #x = reduce( lambda x, s_col_r: show(x, y, *s_col_r), sum_show_lst(lst), x )
+ for (s, col, r) in sum_show_lst(lst):
+ x = show(x, y, s, col, r)
if flush_f:
flush()
return x
def over_show_lst(l, h):
- get_col = lambda (s, col, r): col
+ get_col = lambda s_col_r: s_col_r[1]
f = lambda l, h: l if get_col(h) == 'trans' else h
l = split_show_lst(l)
h = split_show_lst(h)
@@ -355,10 +366,10 @@
apd = mk_slst(' ', 'trans') * n
l = ( l + apd )[:n]
h = ( h + apd )[:n]
- o = map( lambda (l, h): f(l, h), zip(l, h) )
+ o = map_up_lst( lambda l, h: f(l, h), zip(l, h) )
return sum_show_lst(o)
-trans_to_spc_show_lst = lambda lst: map( lambda (s, col, r): (' ' * len(s), '', False) if col == 'trans' else (s, col, r), lst )
+trans_to_spc_show_lst = lambda lst: map_up_lst( lambda s, col, r: (' ' * len(s), '', False) if col == 'trans' else (s, col, r), lst )
def bit_w(v): # only positive value
w = 0
@@ -371,12 +382,12 @@
sv = f(s)
ev = f(e)
while e - s > 0:
- m = (s + e) / 2
+ m = int( (s + e) / 2 )
mv = f(m)
(s, e, sv, ev) = (s, m, sv, mv) if mv < v else (m, e, mv, ev)
return s
-loop_xy = lambda w, h, f: sum( map( lambda y: map( lambda x: f(x, y), range(w) ), range(h) ), [] )
+loop_xy = lambda w, h, f: sum( map_lst( lambda y: map_lst( lambda x: f(x, y), range(w) ), range(h) ), [] )
loop_xywh = lambda x, y, w, h, f: loop_xy( w, h, lambda dx, dy: f(x+dx, y+dy) )
lst_xy = lambda w, h: loop_xy( w, h, lambda x, y: (x, y) )
@@ -388,17 +399,17 @@
into_x = lambda x, w, ow: max( min( ow - w, x ), 0 )
into_xy = lambda x, y, w, h, ow, oh: ( into_x(x, w, ow), into_x(y, h, oh) )
-cen_xywh = lambda x, y, w, h: (x + w/2, y + h/2)
+cen_xywh = lambda x, y, w, h: ( x + int(w/2), y + int(h/2) )
def arr_xy_new(w, h, v):
e = Empty()
- e.data = data = map( lambda _: [ v ] * w, range(h) )
+ e.data = data = map_lst( lambda _: [ v ] * w, range(h) )
e.size = lambda: (w, h)
e.chk_xy = lambda x, y: chk_xy(x, y, w, h)
e.get = lambda x, y, v=None: data[y][x] if e.chk_xy(x, y) else v
e.set = lambda x, y, c: set( data[y], x, c ) if e.chk_xy(x, y) else None
e.clear = lambda v: loop_xy( w, h, lambda x, y: e.set(x, y, v) )
- e.poss = lambda v: filter( lambda (x, y): e.get(x, y) == v, lst_xy(w, h) )
+ e.poss = lambda v: filter_up_lst( lambda x, y: e.get(x, y) == v, lst_xy(w, h) )
e.pos = lambda v: next( iter( e.poss(v) ), (-1, -1) )
return e
@@ -425,7 +436,7 @@
e.get = lambda x, y, bit: arr.get(x, y, 0) & pat(bit)
e.set = lock_wrap( set_ ).f
e.clear = lambda: arr.clear(0)
- e.gets = lambda x, y: filter( lambda bit: e.get(x, y, bit), range( bit_w( arr.get(x, y, 0) ) ) )
+ e.gets = lambda x, y: filter_lst( lambda bit: e.get(x, y, bit), range( bit_w( arr.get(x, y, 0) ) ) )
e.poss = lambda bit: pos_d.get(bit, [])
e.pos = lambda bit: next( iter( e.poss(bit) ), (-1, -1) )
return e
@@ -436,7 +447,7 @@
e.to_bit = to_bit = lambda c: bit_cs.index(c) if c in bit_cs else -1
e.get = lambda x, y, c: arr.get( x, y, to_bit(c) )
e.set = lambda x, y, c, v: arr.set( x ,y, to_bit(c), v )
- e.gets = lambda x, y: map( lambda bit: bit_cs[bit], arr.gets(x, y) )
+ e.gets = lambda x, y: map_lst( lambda bit: bit_cs[bit], arr.gets(x, y) )
e.poss = lambda c: arr.poss( to_bit(c) )
e.pos = lambda c: next( iter( e.poss(c) ), (-1, -1) )
return e
@@ -475,7 +486,7 @@
def show_lst_area(x, y, show_lst, xcen=False):
(w, h) = e.show_lst_wh(show_lst)
if xcen:
- x -= (w - 1) / 2
+ x -= int( (w - 1) / 2 )
(ow, oh) = e.size()
(x, y) = into_xy(x, y, w, h, ow, oh)
return (x, y, w, h)
@@ -500,23 +511,28 @@
if get_dx:
for ix in (-1, 0, 1):
x_ = (x + ix + w) % w
- cs = filter( lambda c: ix == 0 or get_dx(c) == -ix, e.gets(x_, y) )
- lst += map( lambda c: ( c, x_, ix if ix else get_dx(c) ), cs )
+ cs = filter_lst( lambda c: ix == 0 or get_dx(c) == -ix, e.gets(x_, y) )
+ lst += map_lst( lambda c: ( c, x_, ix if ix else get_dx(c) ), cs )
TRANS = mk_slst(' ', 'trans')
shift = lambda lst, dx: split_show_lst( lst + TRANS if dx < 0 else TRANS + lst )[1:3] if dx else lst
- lst = map( lambda (c, x_, dx): ( c, shift( e.get_show_lst(c, x_, y), dx ) ), lst )
+ lst = map_up_lst( lambda c, x_, dx: ( c, shift( e.get_show_lst(c, x_, y), dx ) ), lst )
else:
- lst = map( lambda c: ( c, e.get_show_lst(c, x, y) ), e.gets(x, y) )
+ lst = map_lst( lambda c: ( c, e.get_show_lst(c, x, y) ), e.gets(x, y) )
+
+ lst.sort( key=lambda c_show_lst: e.to_bit( c_show_lst[0] ) )
+ show_lsts = list( zip(*lst) )[1] if lst else []
+
+ #show_lst = reduce( over_show_lst, reversed( show_lsts ), [] )
+ show_lst = []
+ for a in reversed( show_lsts ):
+ show_lst = over_show_lst( show_lst, a )
- lst.sort( key=lambda (c, show_lst): e.to_bit(c) )
- show_lsts = zip(*lst)[1] if lst else []
- show_lst = reduce( over_show_lst, reversed( show_lsts ), [] )
show_lst = trans_to_spc_show_lst(show_lst) if show_lst else mk_slst(' ')
e.shows(x, y, show_lst, flush_f)
e.update = update
- e.update_xys = lambda xys, flush_f=False: ( map( lambda (x, y): e.update(x, y), xys ), e.flush(flush_f) )[-1]
+ e.update_xys = lambda xys, flush_f=False: ( map_up_lst( lambda x, y: e.update(x, y), xys ), e.flush(flush_f) )[-1]
e.update_area = lambda x, y, w, h, flush_f=False: e.update_xys( lst_xywh(x, y, w, h), flush_f )
e.update_line = lambda x, y, w, flush_f=False: e.update_area(x, y, w, 1, flush_f)
e.update_all = lambda flush_f=False: e.update_area(0, 0, w, h, flush_f)
@@ -524,9 +540,9 @@
def update_c(c, flush_f=False):
dx = get_dx(c) if get_dx else 0
xys = e.poss(c)
- #xys += map( lambda (x, y): (x+dx, y), xys ) if dx else []
+ #xys += map_lst( lambda (x, y): (x+dx, y), xys ) if dx else []
if dx:
- xys = xys + map( lambda (x, y): (x+dx, y), xys )
+ xys = xys + map_up_lst( lambda x, y: (x+dx, y), xys )
e.update_xys(xys, flush_f)
e.update_c = update_c
@@ -585,7 +601,7 @@
arr.update(x, y, flush_f)
e.set = set_
- e.rm = lambda c, flush_f=False: map( lambda (x, y): e.set(x, y, c, False, flush_f), e.poss(c) )
+ e.rm = lambda c, flush_f=False: map_up_lst( lambda x, y: e.set(x, y, c, False, flush_f), e.poss(c) )
def msg_pause(x, y, show_lst, sec, xcen=False):
e.shows(x, y, show_lst, xcen, flush_f=True)
@@ -601,17 +617,17 @@
with open(fname, 'r') as f:
buf = f.read().strip().split( os.linesep )
h = len(buf)
- w = max( map(len, buf) )
- buf = map( lambda s: s + ' ' * ( w - len(s) ), buf ) # fill
+ w = max( map_lst(len, buf) )
+ buf = map_lst( lambda s: s + ' ' * ( w - len(s) ), buf ) # fill
arr = arr_xy_new(w, h, ' ')
- e = extends(arr)
+ e = extends(arr, None)
loop_xy( w, h, lambda x, y: arr.set( x, y, buf[y][x] ) )
return e
def main(f, help_msg):
if '-h' in sys.argv:
- print 'Usage: {} {}'.format( sys.argv[0], help_msg )
+ print( 'Usage: {} {}'.format( sys.argv[0], help_msg ) )
sys.exit(0)
try:
restore = term_raw()
diff -urN v6/pac.py v7/pac.py
--- v6/pac.py 2018-02-21 13:09:19.000000000 +0900
+++ v7/pac.py 2018-06-22 23:10:50.000000000 +0900
@@ -8,15 +8,15 @@
NO_DIE = '-m' in sys.argv
-txts = map( lambda s: s + '.txt', [ 'pac', 'mon_ret', 'warp', 'pato' ] )
-(pac_buf, mon_ret_buf, warp_buf, pato_buf) = map(kon.rbuf, txts)
+txts = kon.map_lst( lambda s: s + '.txt', [ 'pac', 'mon_ret', 'warp', 'pato' ] )
+(pac_buf, mon_ret_buf, warp_buf, pato_buf) = kon.map_lst(kon.rbuf, txts)
MONS = 'RCMY'
MOVES = 'P' + MONS
dot_n = len( pac_buf.poss('.') + pac_buf.poss('O') )
-stat_inf = dict( map( lambda c: ( c, kon.Empty() ), MOVES ) )
+stat_inf = dict( kon.map_lst( lambda c: ( c, kon.Empty() ), MOVES ) )
stat_get = lambda c: stat_inf.get(c)
def pac_show(c, x, y):
@@ -26,7 +26,8 @@
return mk_slst(s, col, r)
def blk_show(c, x, y):
- k = filter( lambda d: pac_buf.get( *kon.step_to(x, y, d) ) == c, DIRS ) # 'udlr'
+ k = kon.filter_lst( lambda d: pac_buf.get( *kon.step_to(x, y, d) ) == c, DIRS ) # 'udlr'
+ k = ''.join(k)
s = '=='
d = {
( 'ud', 'u', 'd', 'udl', 'udr' ): '||',
@@ -34,7 +35,7 @@
( 'ur', 'dr' ): ' =',
( 'udlr', ): ' ',
}
- s = dict( sum( map( lambda (ks, v): map( lambda k: (k, v), ks ), d.items() ), [] ) ).get(k, s)
+ s = dict( sum( kon.map_up_lst( lambda ks, v: kon.map_lst( lambda k: (k, v), ks ), d.items() ), [] ) ).get(k, s)
return mk_slst(s, 'blue', False)
SPC = (' ', '', False)
@@ -44,7 +45,7 @@
e.v = 1
e.get = lambda: e.v
def check():
- if not filter( lambda c: mon_mode(c) in ('weak', 'blink'), MONS ):
+ if not kon.filter_lst( lambda c: mon_mode(c) in ('weak', 'blink'), MONS ):
e.v = 1
e.check = check
e.twice = lambda: set( e, 'v', e.v * 2 )
@@ -114,7 +115,7 @@
return nc != '#'
-next_ds = lambda x, y, c: filter( lambda d: is_step(x, y, c, d), DIRS )
+next_ds = lambda x, y, c: kon.filter_lst( lambda d: is_step(x, y, c, d), DIRS )
def arr_msg_pause(show_lst, x=None, y=None, sec=1.0, xcen=True):
ths_stop()
@@ -146,7 +147,7 @@
if mode in ('weak', 'blink'):
mov.en = False
ss = [ '. ', 'o ', 'O ', '<>', '()', '^^' ]
- lsts = map( lambda s: mk_slst(s, 'yellow', True), ss )
+ lsts = kon.map_lst( lambda s: mk_slst(s, 'yellow', True), ss )
bak = pac_slider( kon.slider(lsts, 8.0, None, True, repeat=False) )
add = mon_price.get() * 200
mon_price.twice()
@@ -264,7 +265,7 @@
bonus = bonus_new()
def try_eat(x, y):
- lst = filter( lambda c: c in '.OB', arr.gets(x, y) )
+ lst = kon.filter_lst( lambda c: c in '.OB', arr.gets(x, y) )
if not lst:
return
c = lst[0]
@@ -294,7 +295,7 @@
is_remote = '-r' in sys.argv
def pac_remote(pd, ds):
- ds = filter( lambda d: d != kon.bak_dir(pd), ds )
+ ds = kon.filter_lst( lambda d: d != kon.bak_dir(pd), ds )
if len(ds) == 1:
return ds[0]
@@ -325,8 +326,8 @@
stat_get(c).th.set_hz(hz)
def rand(n):
- v = sum( sum( map( lambda c: list( arr.pos(c) ), MOVES ), [] ) )
- return ( v / 4 ) % n
+ v = sum( sum( kon.map_lst( lambda c: list( arr.pos(c) ), MOVES ), [] ) )
+ return ( int( v / 4 ) ) % n
rand_sel = lambda lst: lst[ rand( len(lst) ) ]
@@ -346,7 +347,7 @@
return mon_ret_buf.get(x, y)
pd = arr.get_dir(c)
- ds_ = filter( lambda d: d != kon.bak_dir(pd), ds )
+ ds_ = kon.filter_lst( lambda d: d != kon.bak_dir(pd), ds )
ds = ds_ if ds_ else ds
(tx, ty) = arr.pos('P')
@@ -356,7 +357,7 @@
if mode == 'run' and run_mode.get() == 'pato':
# MONS = 'RCMY'
- (w2, h2) = (w/2, h/2)
+ (w2, h2) = ( int(w/2), int(h/2) )
area_d = {
'R': (w2, 0, w2, h2),
'C': (w2, h2, w2, h2),
@@ -429,7 +430,7 @@
kon.show( x_, y, s_, col_, r_, flush_f=True )
def f(add=0):
if add == 0:
- map( lambda i: draw(True, i), range(e.v) )
+ kon.map_lst( lambda i: draw(True, i), range(e.v) )
return ''
while add > 0:
draw(True, e.v)
@@ -447,13 +448,13 @@
gate = kon.counter(4)
-mon_turn = lambda: map( lambda c: arr.set_dir( c, kon.bak_dir( arr.get_dir(c) ) ), MONS )
+mon_turn = lambda: kon.map_lst( lambda c: arr.set_dir( c, kon.bak_dir( arr.get_dir(c) ) ), MONS )
run_mode = kon.slider( ['pato', 'chase'], f=mon_turn )
def init_once():
kon.clr()
- lst = map( lambda r: mk_slst('O ', 'yellow', r), (False, True) )
+ lst = kon.map_lst( lambda r: mk_slst('O ', 'yellow', r), (False, True) )
arr.set_sdic( 'O', ( 'slider', kon.slider(lst, 2.0, None, True) ) )
arr.set_sdic( 'P', ('func', pac_show) )
@@ -466,17 +467,17 @@
score()
spare()
- map( lambda c: set( stat_get(c), 'hz', 3.0 if c == 'P' else 3.3 ), MOVES )
- map( lambda c: set( stat_get(c), 'timer', kon.timer_new() ), MONS )
+ kon.map_lst( lambda c: set( stat_get(c), 'hz', 3.0 if c == 'P' else 3.3 ), MOVES )
+ kon.map_lst( lambda c: set( stat_get(c), 'timer', kon.timer_new() ), MONS )
for c in MOVES:
stat = stat_get(c)
f = th_pac if c == 'P' else th_mon
stat.th = kon.th_loop(f, [c], stat.hz, run=False)
-ths_start = lambda: map( lambda c: stat_get(c).th.start(), MOVES )
-ths_stop = lambda: map( lambda c: stat_get(c).th.stop(), MOVES )
-ths_timer_cancel = lambda: map( lambda c: stat_get(c).timer.cancel(), MONS )
+ths_start = lambda: kon.map_lst( lambda c: stat_get(c).th.start(), MOVES )
+ths_stop = lambda: kon.map_lst( lambda c: stat_get(c).th.stop(), MOVES )
+ths_timer_cancel = lambda: kon.map_lst( lambda c: stat_get(c).timer.cancel(), MONS )
def work():
init_once()
@@ -521,7 +522,7 @@
ths_stop()
ths_timer_cancel()
kon.sleep(2.0)
- map( lambda c: arr.rm(c), MOVES )
+ kon.map_lst( lambda c: arr.rm(c), MOVES )
bonus.hide()
arr.update_all(flush_f=True)
@@ -536,7 +537,7 @@
v = game_ev.get()
if v == 'die':
ss = [ '()', '||', ')(', '><', '--', '><', '--', '><', '--', '__', ' ' ]
- lsts = map( lambda s: mk_slst(s, 'yellow', True), ss )
+ lsts = kon.map_lst( lambda s: mk_slst(s, 'yellow', True), ss )
lsts.append( [ SPC ] )
bak = pac_slider( kon.slider(lsts, 5.0, None, True, repeat=False) )
@@ -548,7 +549,7 @@
elif v == 'clear':
c = '#'
bak = arr.get_sdic(c)
- lst = map( lambda col: mk_slst('==', col, False), ('white', 'blue') )
+ lst = kon.map_lst( lambda col: mk_slst('==', col, False), ('white', 'blue') )
slider = kon.slider(lst, 4.0, None, True)
arr.set_sdic( c, ('slider', slider) )
kon.sleep(3.0)
レイトレーシング 2018春 で、手持ちの環境のpythonのデフォルトのバージョンを 3 に上げてしまいました。
レイトレーシング 2018春 の パックマンもどき で、使いたいので python3 対応しておきます。
$ cat v7.patch | patch -p1
v8.patch
diff -ur v7/kon.py v8/kon.py
--- v7/kon.py 2018-06-22 23:10:50.000000000 +0900
+++ v8/kon.py 2020-11-30 00:09:27.000000000 +0900
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import sys
+import six
import os
import time
import termios
@@ -8,6 +9,8 @@
import threading
import socket
+get_stdout_buffer = lambda : sys.stdout if six.PY2 else sys.stdout.buffer
+
map_lst = lambda f, lst: list( map( f, lst ) )
map_up = lambda f, lst: map( lambda a: f(*a), lst )
map_up_lst = lambda f, lst: list( map_up( f, lst ) )
@@ -54,7 +57,7 @@
if s != None:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect( get_host_port(s, port=55765) )
- return lambda s: ( sock.sendall if sock else sys.stdout.write )( s.encode() )
+ return lambda s: ( sock.sendall if sock else get_stdout_buffer().write )( s.encode() )
out = out_new()
久しぶりに ./pac.py として起動してみたら、python3でひっかかってました。
安易なパッチですが修正しておきます。
$ cat v8.patch | patch -p1
「クロージャ多用なソース」ですが、 あまりに自己流な感じになってきたので少々説明。
そもそもの経緯は、 Pythonでグローバル変数に代入するときに global xxx が面倒なので、
def gval(v=None): keep = [ v ] def set(v): keep[0] = v return lambda v='get': keep[0] if v == 'get' else set(v)
を用意した所から始まります。
この関数で返るクロージャの関数を、 引数なしで実行すると、内部の値が返り、 引数を指定して実行すると、その値が内部に設定されます。
このようにクロージャの関数1つだけを返していて多機能を求めると、 引数にコマンド的なものを与えて、switch文のような関数になります。
gvalの例でも、値vの指定が'get'なら参照する機能。'get'以外なら設定する機能。 これはちょっと「かっちょ悪い...」
安易に逃げるならば、
def gval(v=None): keep = [ v ] def set(v): keep[0] = v return (lambda: keep[0], set) (foo_get, foo_set) = gval('bar') foo_set('hoge') print foo_get()
辞書で返すなら
def gval(v=None): keep = [ v ] def set(v): keep[0] = v return { 'get': lambda: keep[0], 'set': set } foo = gval('bar') foo.get('set')('hoge') print foo.get('get')()
あるいは
foo['set']('hoge') print foo['get']()
名前'get' や 'set'は、クラスのメソッドのように .get() や .set() にして使いたいところ...
そういえばPythonのクラスのインスタンスは、割りと何でもアリなはず。
例えば、教科書的な使い方だと
foo.py
class Foo:
def __init__(self, rate=0.3):
self.rate = rate
self.a = 0
self.b = 0
def get(self):
return (self.a, self.b)
def add(self, v):
if v <= 100:
self.a += v
elif v <= 200:
self.b += v
else:
t = int(v * self.rate)
self.a += t
self.b += v - t
return self.get()
class Empty:
pass
def gval(v=None):
keep = [ v ]
def set(v):
keep[0] = v
e = Empty()
e.get = lambda: keep[0]
e.set = set
return e
def foo_new(rate=0.3):
p = Empty()
p.a = 0
p.b = 0
e = Empty()
e.get = lambda: (p.a, p.b)
def add(v):
if v <= 100:
p.a += v
elif v <= 200:
p.b += v
else:
t = int(v * rate)
p.a += t
p.b += v - t
return e.get()
e.add = add
return e
def cls_to_dic(c):
ks = filter( lambda k: not k.startswith('_'), dir(c) )
return dict( map( lambda k: ( k, getattr(c, k) ), ks ) )
def dic_to_cls(d, c=None):
if not c:
c = Empty()
map( lambda (k, v): setattr(c, k, v), d.items() )
return c
def extends(pcls, c=None):
if not c:
c = Empty()
dic_to_cls( cls_to_dic(pcls), c )
return c
def bar_new(rate=0.3):
foo = foo_new(rate)
e = extends(foo)
e.vs = [402, 229, 338, 48, 80, 448]
def show():
print e.get()
e.show = show
return e
def hoge_new(rate=0.3):
bar = bar_new(rate)
e = extends(bar)
def get(name=None):
(a, b) = r = bar.get()
return a if name == 'a' else b if name == 'b' else [ a, b ]
e.get = get
return e
的なクラス。
add(v)で追加する売上が、 100円以下ならaさんの取分。 100円超えて200円以下ならbさんの取分。 200円超えてるものは、3:7 で配分。
$ python >>> from foo import Foo >>> from random import randint >>> vs = map( lambda i: randint(10,500), range(6) ) >>> vs [402, 229, 338, 48, 80, 448]
半年の売上がこうならば aさんbさんの持ち分の推移は
>>> foo = Foo() >>> map( foo.add, vs ) [(120, 282), (188, 443), (289, 680), (337, 680), (417, 680), (551, 994)]
もうちょっとaさんの配分を増やして 4:6 にして試すなら
>>> bar = Foo(0.4) >>> map( bar.add, vs ) [(160, 242), (251, 380), (386, 583), (434, 583), (514, 583), (693, 852)]
クラスのアトリビュート a, b な訳ですが、 これは悪魔でクラスインスタンスで「共通の」アトリビュート。
>>> foo.hoge = 123 >>> bar.plus3 = lambda v: v+3
各インスタンスに個別に勝手にアトリビュートを追加できます。
>>> foo.hoge 123 >>> bar.plus3(7) 10
.xxx じゃなくて 'xxx' な名前でも使えて
>>> hasattr(foo, 'hoge') True >>> setattr(foo, 'hoge', 999) >>> getattr(foo, 'hoge') 999 >>> foo.hoge 999
もちろん各インスタンス「共通の」アトリビュートに対しても名前で
>>> getattr(bar, 'get')() (693, 852) >>> bar.get() (693, 852)
問題なく何でもアリです。 アトリビュート .xxx は辞書で実装されてるのでしょうね。
ならば、 クロージャで辞書を返すように、 空クラスのインスタンスにアトリビュートを追加して返せば、 辞書のように使える?
class Empty: pass
を用意しておいて
def gval(v=None): keep = [ v ] def set(v): keep[0] = v e = Empty() e.get = lambda: keep[0] e.set = set return e >>> foo = gval('hoge') >>> foo.get() 'hoge' >>> foo.set('fuga') >>> foo.get() 'fuga'
gval()はクロージャを返すのでクラスみたいなものですが、 classそのものは、複数のクロージャをまとめて返すためだけに使って、 受け取った側で .xxx() でメソッドとして呼び出すようにしてます。
例えば先の配分クラスを書くならば、
def foo_new(rate=0.3): p = Empty() p.a = 0 p.b = 0 e = Empty() e.get = lambda: (p.a, p.b) def add(v): if v <= 100: p.a += v elif v <= 200: p.b += v else: t = int(v * rate) p.a += t p.b += v - t return e.get() e.add = add return e
この関数そのものはクラスじゃないので、self. は出てきません。
引数の rate や、使ってませんがローカル変数の値も、 この関数を実行したときの環境として内部に保持されます。
クロージャ関数 add() や get() の中からは、 引数やローカル変数の値を変更しようとすると、例の global 問題があります。
なので、値を変更するけど関数の内部だけに留めたい a, b は、 空クラスのインスタンス p にぶら下げてます。
外に公開するメソッド get(), add() は、 空クラスのインスタンス e にぶら下げて return e で返してます。
>>> from foo import foo_new >>> vs [402, 229, 338, 48, 80, 448] >>> foo = foo_new() >>> map( foo.add, vs ) [(120, 282), (188, 443), (289, 680), (337, 680), (417, 680), (551, 994)] >>> bar = foo_new(0.4) >>> map( bar.add, vs ) [(160, 242), (251, 380), (386, 583), (434, 583), (514, 583), (693, 852)]
ほれ。同様に動きます。
まぁ元々Pythonのクラスのアトリビュートは丸見えで、 多少隠蔽できるようにしたところで、アレなので、
def foo_new(rate=0.3): e = Empty() e.a = 0 e.b = 0 e.get = lambda: (e.a, e.b) def add(v): if v <= 100: e.a += v elif v <= 200: e.b += v else: t = int(v * rate) e.a += t e.b += v - t return e.get() e.add = add return e
な感じで、全部公開するように書いとります。
で、クラスもどきなので継承的な事も。
def cls_to_dic(c): ks = filter( lambda k: not k.startswith('_'), dir(c) ) return dict( map( lambda k: ( k, getattr(c, k) ), ks ) )
クラスのアトリビューとで '_' で始まるもの以外を、辞書に。
def dic_to_cls(d, c=None): if not c: c = Empty() map( lambda (k, v): setattr(c, k, v), d.items() ) return c
辞書を受け取って、クラスのアトリビュートに上書き。
def extends(pcls, c=None): if not c: c = Empty() dic_to_cls( cls_to_dic(pcls), c ) return c
親のクラスインスタンスの、アトリビュート全てを、 辞書を経由して、子供のクラスインスタンスのアトリビュートに上書き。
これで「継承もどき」です。
先の取分クラスもどきを継承して、 サンプルのデータと、表示機能だけ追加してみましょう。
def bar_new(rate=0.3): foo = foo_new(rate) e = extends(foo) e.vs = [402, 229, 338, 48, 80, 448] def show(): print e.get() e.show = show return e >>> from foo import bar_new >>> bar = bar_new() >>> bar.vs [402, 229, 338, 48, 80, 448] >>> map( bar.add, bar.vs ) [(120, 282), (188, 443), (289, 680), (337, 680), (417, 680), (551, 994)] >>> bar.show() (551, 994)
インタプリタで対話的に使うと、show()のありがた味ゼロですね。
親のメソッドは丸々 e にコピーされていて、 呼び出せば親の関数の中でクロージャ関数が起動します。
ただし、メソッド呼び出しせずに、値として扱うならば、 値はコピーされてるだけなので、 子供側で値を変更しても、親側には反映されないので要注意です。
例えば、親からコピーした get を上書きして書き換えるなら、
def hoge_new(rate=0.3): bar = bar_new(rate) e = extends(bar) def get(name=None): (a, b) = r = bar.get() return a if name == 'a' else b if name == 'b' else [ a, b ] e.get = get return e >>> from foo import hoge_new >>> hoge = hoge_new() >>> hoge.vs [402, 229, 338, 48, 80, 448] >>> map( hoge.add, hoge.vs ) [(120, 282), (188, 443), (289, 680), (337, 680), (417, 680), (551, 994)] >>> hoge.get() [551, 994] >>> hoge.get('a') 551 >>> hoge.get('b') 994
ただし、仮想関数テーブルもなにもなくて、単に上書きしてるだけなので
>>> hoge.show() (551, 994)
まぁ、そりゃそうです。「クラスもどき」という事で。
工事中