From e878717c3196d24e6f2dc3e5ab0ddd2c39122456 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 12:06:22 -0800 Subject: [PATCH 01/11] Better debug mouse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debug mouse is now its own module, so it can be separated from the hint system, since it is useful for more than just positioning hints. It now has the following enhancements: 1. Clock-based table cyclng now has a helper function (cycle) 2. Debug mouse color cycling is distinct from hint color cycling, so debug position readout remains legible 3. Debug position readout now stays on screen even when the cursor is near or past the edges 4. Debug cursor cycles between a mouse sprite specifically marking the exact pixel that is being sampled, an "X" for text character sizing, and a "□" for positioning the centered 3x3 characters often used as hint target markers 5. Map cell coordinates (in square brackets) are displayed in addition to pixel coordnates (in parentheses) Sprite 50 is now the mouse cursor. Color 15 is color cycling for debug readouts. Debug mouse features can be disabled by commenting out `add(real_modules, debugmouse)`. I've done a little bit of golfing but this is stiill a token expense. I'm going to write a crappy sprintf function to save tokens everywhere we're assembling strings from their component parts. --- chameleonic.p8 | 51 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index 6dca504..bc9028a 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -33,6 +33,11 @@ function gsv(s) return ret end +function cycle(tbl,period) + period = period or 1 + return tbl[t()%period*#tbl\period+1] +end + mnames={} function names(root) local n=mnames[root] @@ -1787,8 +1792,6 @@ function hints:init() end menuitem(1,"get hint",function() level.hintlevel+=1 end) menuitem(2,"hide hints",function() level.hintlevel=0 end) - -- debug mode: enable mouse - poke(0x5f2d,1) end function shdprint(txt,x,y,c) @@ -1796,16 +1799,10 @@ function shdprint(txt,x,y,c) print(txt,x,y,c) end -hintflicker={7,10,9,8,8,9,10,7} +hintflicker=split"7,10,9,8,8,9,10,7" function hints:draw2() pal() - local c=hintflicker[t()%1*#hintflicker\1+1] - -- debug mode: mouse coord display - if stat(34) != 0 then - local mousex, mousey = stat(32), stat(33) - print("x ("..mousex..", "..mousey..")",mousex,mousey,c) - end - + local c=cycle(hintflicker) for i,h in ipairs(self[level.ix]) do if (i > level.hintlevel) return @@ -1815,6 +1812,32 @@ function hints:draw2() end end +-->8 +-- debug mouse support + +debugmouse = {} + +-- comment this out to disable debug mode +add(real_modules, debugmouse) + +function debugmouse:init() + poke(0x5f2d,1) +end + +debugflicker=split"5,6,7,15,14,8,2,4,9,10,11,3,12,13" +debugchs = split" ,x, ,□" + +function debugmouse:draw3() + if (stat(34) == 0) return + pal(15,cycle(debugflicker,1.5)) + local x, y, c = stat(32), stat(33), cycle(debugchs,2) + if (c == " ") spr(50,x,y) + print(c,x,y,15) + local px, py = mid(0,x,89), mid(0, y > 111 and y - 12 or y + 6, 117) + print("("..x..", "..y..")\n["..(x\8)..", "..(y\8).."]",px,py,15) + pal() +end + __gfx__ 000030000000002200003000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeff1ff1ff1fffffff1ffffff1fffffff1dddddddd111111110005000000000000 003333300000332200333330eeffffffffffffffffffffeee5e555e55e555e5eff1ff1ffffffffffffffffffffffffffdddddddd111111110000500000000000 @@ -1840,10 +1863,10 @@ eeee0000cc04405500444400efeeee5e11111111e5eeeefeeeeeeeeeeeeeeeeeffffffffffffffff 0a000aa4441a91a1bbabbbbbeffeeeeeeeeeeeeeeeeeeffeff1ff1ff11111111ff1111ff00000000000000000000000000000000000000000000000000000000 00a0044449a110a1bbbbbbbbeeffffffffffffffffffffeeff1ff1ffffffffffffffffff00000000000000000000000000000000000000000000000000000000 000aa111991111103bbbbbb3eeeeeeeeeeeeeeeeeeeeeeeeff1ff1ffffffffffffffffff00000000000000000000000000000000000000000000000000000000 -00000000991000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111999999111111111 -00000000990000000000000000000000000000000000000000000000000000000000000000000000000000000000000019911991999999911999999119999999 -00000000990000000000000000000000000000000000000000000000000000000000000000000000000000000000000019977991999999911999999119999999 -00000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000019911991999117111991199111711999 +0000000099100000f765000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111999999111111111 +00000000990000007700000000000000000000000000000000000000000000000000000000000000000000000000000019911991999999911999999119999999 +00000000990000006060000000000000000000000000000000000000000000000000000000000000000000000000000019977991999999911999999119999999 +00000000090000005005000000000000000000000000000000000000000000000000000000000000000000000000000019911991999117111991199111711999 00000000aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000019911991999117111991199111711999 0000000077a000000000000000000000000000000000000000000000000000000000000000000000000000000000000019999991999999911997799119999999 00000007777a00000000000000000000000000000000000000000000000000000000000000000000000000000000000019999991999999911991199119999999 -- 2.34.1 From 3494c48e7425b36823266279b43dcde5fff2a1fa Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 12:33:16 -0800 Subject: [PATCH 02/11] implement fake sprintf this spends extra tokens to handle "invalid format character" to catch using a % where %% is intended. this is designed to grow with further format chars if needed; I have ideas for not-exactly-POSIX %d, %x, %h, %!, %#, %c, and possibly others but there is absolutely no reason to spend tokens on these things until we need them. (that said, existing debugging output might benefit from some of these other formats, but that debug code is commented out, so maybe nevert.) --- chameleonic.p8 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/chameleonic.p8 b/chameleonic.p8 index bc9028a..2522e0c 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -38,6 +38,29 @@ function cycle(tbl,period) return tbl[t()%period*#tbl\period+1] end +-- fake sprintf function +-- %% for literal "%" +-- %v for param + +function sprintf(fmt, ...) + local out, i = "", 1 + for s in all(split(fmt,"%")) do + local m = s[1] + if m == "%" then + out ..= "%" + else + local p = select(i,...) + i+=1 + if m == "v" then + out ..= select(i,...) + else + out ..= "(?!:"..m..":"..tostr(p)..")" + end + out ..=sub(s,2) + end + return out +end + mnames={} function names(root) local n=mnames[root] -- 2.34.1 From 93c154f8767e0a3a59ef562da8cc6314c236c0d1 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 12:37:11 -0800 Subject: [PATCH 03/11] fix sprintf and rename to fmt the "split on %" strategy makes parsing "%%" complicated, so the "actually literally %" placeholder is now "%~" rather than "%%". since thsi resembles a real sprintf even less now I renamed it to "fmt". also actually closes the `if m == "~"` block. (which was `if m == "%"` before this patch) --- chameleonic.p8 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index 2522e0c..cace9a2 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -39,14 +39,13 @@ function cycle(tbl,period) end -- fake sprintf function --- %% for literal "%" +-- %~ for literal "%" -- %v for param - -function sprintf(fmt, ...) +function fmt(f, ...) local out, i = "", 1 - for s in all(split(fmt,"%")) do + for s in all(split(f,"%")) do local m = s[1] - if m == "%" then + if m == "~" then out ..= "%" else local p = select(i,...) @@ -56,6 +55,7 @@ function sprintf(fmt, ...) else out ..= "(?!:"..m..":"..tostr(p)..")" end + end out ..=sub(s,2) end return out -- 2.34.1 From 2264349e72c752b70824a9e13a3873c50f9b9474 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 12:42:37 -0800 Subject: [PATCH 04/11] fix double-consume, add %! I discovered your tostring function for debugging, might as well make it reachable from fmt. I also realized I forgot to convert to using "p" when I introduced it so I fixed that --- chameleonic.p8 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index cace9a2..5e8ce5f 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -41,6 +41,8 @@ end -- fake sprintf function -- %~ for literal "%" -- %v for param +-- %! for tostring(param) +-- which dumps tables function fmt(f, ...) local out, i = "", 1 for s in all(split(f,"%")) do @@ -51,9 +53,11 @@ function fmt(f, ...) local p = select(i,...) i+=1 if m == "v" then - out ..= select(i,...) + out ..= p + elseif m == "!" then + out ..= tostring(p) else - out ..= "(?!:"..m..":"..tostr(p)..")" + out ..= "(?!:"..m..":"..tostring(p)..")" end end out ..=sub(s,2) -- 2.34.1 From 3516d2855e5010025844532d71ccf64d67ca0c98 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 12:50:35 -0800 Subject: [PATCH 05/11] fix section before first "%" oops, need to special-case the first part of the split list. amusingly, I don't need to special-case zero-length format strings because that will skip the entire loop and output "", which seems correct. (I am also not special-casing zero-length segments because `s[1] == nil` will go into the error handler and that seems fine. --- chameleonic.p8 | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index 5e8ce5f..ce2645e 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -44,23 +44,29 @@ end -- %! for tostring(param) -- which dumps tables function fmt(f, ...) - local out, i = "", 1 + local out, i = "", 0 for s in all(split(f,"%")) do - local m = s[1] - if m == "~" then - out ..= "%" + if i == 0 then + -- before first format directive + out ..= s + i = 1 else - local p = select(i,...) - i+=1 - if m == "v" then - out ..= p - elseif m == "!" then - out ..= tostring(p) + local m = s[1] + if m == "~" then + out ..= "%" else - out ..= "(?!:"..m..":"..tostring(p)..")" + local p = select(i,...) + i+=1 + if m == "v" then + out ..= p + elseif m == "!" then + out ..= tostring(p) + else + out ..= "(?!:"..m..":"..tostring(p)..")" + end end + out ..=sub(s,2) end - out ..=sub(s,2) end return out end -- 2.34.1 From e6c35dbedaa21ad4509e000d3a00fe8b3dd759c5 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 12:53:16 -0800 Subject: [PATCH 06/11] Use fmt on title screen. --- chameleonic.p8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index ce2645e..bc39554 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -302,7 +302,7 @@ function title:draw() print("pyrex",32,73,7) print("[nyeogmi]",62,73,7) print("kistaro",32,79,7) - local lvlstr = "⬅️ "..start_level.." ➡️" + local lvlstr = fmt("⬅️ %v ➡️",start_level) print(lvlstr,50,91,1) print(lvlstr,51,90,blinkcol) end -- 2.34.1 From f86e52d3bdf34dd6d7855d6a0fa379b903668e68 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 13:18:31 -0800 Subject: [PATCH 07/11] tostring golf this could be golfed further by rewriting the str..= line in terms of fmt, but the performance impact of inserting the extra `fmt` calls and parsing into the tostring recursion seems likely to be a problem. --- chameleonic.p8 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index bc39554..a9c387b 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -279,14 +279,12 @@ function kbd:release(i) end function tostring(any) - if type(any)=="table" then - local str = "{ " - for k,v in pairs(any) do - str=str..tostring(k).."->"..tostring(v).." " - end - return str.."}" + if (type(any)!="table") return tostr(any) + local str = "{ " + for k,v in pairs(any) do + str..=tostring(k).."->"..tostring(v).." " end - return tostr(any) + return str.."}" end -->8 -- 2.34.1 From 46f1339e197392e41f7d2ef5bc1f4761ba24e1a1 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 13:27:32 -0800 Subject: [PATCH 08/11] golf recollide_reanchor Uses fmt in recollide_reanchor. This has a performance impact in code that is already slow so this might need to be reverted; I think that should be part of a comprehensive optimization pass, however, and making it worse for now as part of a general code cleanup is probably better. --- chameleonic.p8 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index a9c387b..7f9102b 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -470,8 +470,7 @@ function level:recollide_reanchor() not self:mcoll(mx1,my0) and not self:mcoll(mx1,my1) ) then - local key="GEOM"..mx0..","..my0..","..dx..","..dy - anch_new[key]= { + anch_new[fmt("GEOM%v,%v,%v,%v",mx0,my0,dx,dy)]= { max(mx0,mx1),max(my0,my1),adx=-dx,ady=-dy } end @@ -479,10 +478,9 @@ function level:recollide_reanchor() end for _,cr in pairs(self._crates) do - local key="CRATE"..cr.id..","..dx..","..dy local mx0,my0=cr.mx,cr.my local mx1,my1=mx0+dx,my0+dy - anch_new[key]={ + anch_new[fmt("CRATE%v,%v,%v",cr.id,dx,dy)]={ max(mx0,mx1),max(my0,my1),adx=-dx,ady=-dy } end -- 2.34.1 From 3e2229be650a345d685de8afa158ea1e46a7b304 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 13:29:52 -0800 Subject: [PATCH 09/11] use fmt in a commented-out debug logging block --- chameleonic.p8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index 7f9102b..cdeca25 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -1088,7 +1088,7 @@ function rope:draw(artificial_px,artificial_py) if (anch.ady>0) y-=1 end rectfill(x-1,y-1,x+1,y+1,12) - print("ax="..n1.ax..",ay="..n1.ay,72,sy) + print(fmt("ax=%v,ay=%v",n1.ax,n1.ay),72,sy) sy+=7 local n0=n1.prev -- 2.34.1 From ce3fc83221e531c267259c5555dbcfd163ed3731 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 13:31:34 -0800 Subject: [PATCH 10/11] fmt in debugmouse:draw3. This is literally the reason I implemented fmt in the first place --- chameleonic.p8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index cdeca25..95b65e8 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -1863,7 +1863,7 @@ function debugmouse:draw3() if (c == " ") spr(50,x,y) print(c,x,y,15) local px, py = mid(0,x,89), mid(0, y > 111 and y - 12 or y + 6, 117) - print("("..x..", "..y..")\n["..(x\8)..", "..(y\8).."]",px,py,15) + print(fmt("(%v, %v)\n[%v, %v]",x,y,x\8,y\8),px,py,15) pal() end -- 2.34.1 From e028209adff0fb8f93871b38ec4f8e4718e535a5 Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Sun, 1 Jan 2023 14:11:11 -0800 Subject: [PATCH 11/11] assert on unrecognized directive saves four tokens and is more diagnostic. --- chameleonic.p8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chameleonic.p8 b/chameleonic.p8 index 95b65e8..30b30c6 100644 --- a/chameleonic.p8 +++ b/chameleonic.p8 @@ -62,7 +62,7 @@ function fmt(f, ...) elseif m == "!" then out ..= tostring(p) else - out ..= "(?!:"..m..":"..tostring(p)..")" + assert(false, tostr(m).."is not a formatting directive") end end out ..=sub(s,2) -- 2.34.1