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# ### # # # # # #