-
Notifications
You must be signed in to change notification settings - Fork 3
Smart Rewrite
We want to create a smart rule rewrite system leveraging Rascal's rewrite capabilities, so we want to do something smart using cases and rewrite.
Example:
[ > Player | Crate ] -> [ > Player | > Crate ]
becomes
case layer(moving("player"), stationary("crate")) => layer(moving("player"), moving("crate"))
This is the theory, but the practice is much more complex, how can we generate this? Do we use metaprogramming to write out all possible cases? Not to mention a dozen of other implementation questions, what is movement, how do we define where the player is going?
What about the elipsis? Do we generate every possible case? increpare calls a compiler that does it like that dumb (and they probably know what they're talking about). We would need to generate something like that for every possible vertical and horizontal height and since they can stretch forever that could be problematic.
The first problem to solve is that matches on the left side are repeated on the right side
So if we have a property to match A or B and it matches A, then the rewrite rule using that same property (A or B) on the right side should know that we matched A. So maybe we should use regular expressions instead, not as nifty but might be more logical.
The issue remains of movement, if we simply have a bunch of regex stuff, how do we determine movement?
Regex idea
[ Player | Crate ] -> [ Crate | Player ]
becomes
//W: Wall, P: Player, C: Crate
line = resolve_line(#.PC..#); //becomes Wall . "Player Crate . . Wall"
/player crate/i := line
With ellipsis
[ LavaGun | ... | Mortal ] -> [ LavaGun | ... | Corpse ]
// mortal = player or beast
/lavagun .* (player|beast)/i := line
but then what is movement? Do we use the same system as with the sound events, so
[ > Player | Crate ] -> [ > Player | > Crate ]
becomes
/moving_player crate/ := line
This is all theoretical, I haven't fully worked out how exactly the replacing would work in this case. if we label the arguments can we do that? Above example becomes
right = ("match0": "moving_player moving_crate")
if (/<match0:moving_player crate>/ := line) replaceFirst(line, match0, right["match0"]);
And then there is also the questions of horizontal/vertical matching, is it cheating if I just rotate the level?
Basically, I want to avoid creating a system exactly like PuzzleScript because, while it works, it is also complex if not complicated.
TL;DR: I have a lot of questions and very few answers...
PS. Funnily enough it seems that Puzzlescript's current implementation also makes use of meta programming, writing custom functions for rule matches: https://github.com/increpare/PuzzleScript/blob/2ba5ea9d699b9023cd1adc82dc21b33d70e755d7/src/js/engine.js#L1295
I am confusion
I have finally had time to talk with Riemer and we have come up with a solution. I had previously caught a brief glimpse of a rascal concept called list patterns and we think it may be the solution to our problem. This allows us to pattern match a list of pixel.
[ > Player | Crate ] -> [ > Player | > Crate ]
[*before, \moving_player("player", legend0, direction0), object("crate", legend1), *after]
->
before + [moving_player("player", legend0, direction0), moving_object("crate", legend1, direction0)] + after
The rule above matches to
[transparent("trans", "."), transparent("trans", "."), moving_player("player", "p", "left"), object("crate", "c"), transparent("trans", ".")]