The Let's Play Archive

EXAPUNKS

by Carbon dioxide

Part 27: Alliance Power and Light

Part 27 - Alliance Power and Light

=== Trash World Inbox ===

Quackles posted:

HACK*MATCH tip: You can swap while holding a block to change the order of blocks up to three deep in total. It can help making some buried 4's.
Yep, good tip. I guess I forgot to show that off.

GuavaMoment posted:

The only way I found to get 100000 hackmatch points in a reasonable timeframe was to download a lua file (I think) that played for you and ran it overnight. Essentially hacking the hacking game to win a different hacking game. I found it appropriate.
I like that. Perhaps I should hack the Phage EXAs in my hand to get better at controlling the game.


=== Alliance Power and Light - Streetsmarts GIS Database ===

Hmm.
This game isn't about hacking at all, is it?
They took a lot of dramatic license.




Well, all the votes were the same this time, that makes for easy counting.

I don't know how you'd make a game about real hacking.

Hacking is inherently about manipulating systems in ways the designers didn't intend...
Whereas a game is usually a set of possibilities within accepted bounds.
It seems difficult to reconcile.


Well, this got very meta, didn't it? Let's stop for a moment and think about how Zachtronics handles this. Basically, they created a programming language and they made a set of puzzles around it. It is a purposefully constrained language, which makes otherwise easy problems surprisingly difficult. As a professional software developer, it forces me to look at seemingly familiar things in a completely different light.

I'm sure Zach had no idea of some of the solutions we came up with either. Of course, for a game like this, you need to make some concessions, such as the test cases often not being completely realistic, or us being able to game them... but I have a feeling Zach is completely fine with the latter.

I think a sandbox made out of some basic rules, together with some cleverly designed puzzles that allow multiple solutions within the constraints of the sandbox rules, makes for very good and interesting puzzle game design. This game does it well. And Breath of the Wild's shrines were designed with a similar approach. It just works. As a counter example, I'm thinking Scribblenauts, which barely constrains the puzzle solutions. This allows most levels to be solved in a way that feels too cheap. At that point it might be better to drop the puzzle elements entirely and turn it into a building game such as Minecraft.

...Anyway, that's enough of me rambling about game design.



[Ghast] you never know what a guy who thinks he can make a buck will do.



We need to help Nivas out so we can get a new shipment of the Phage medicine.

This is something like a heist, isn't it.



Another clear vote.

It is a heist.

I didn't imagine such a major operation.
Not including you, there are three separate teams.
Whoever put this together has some serious resources.
I guess that's why it costs so much.
Don't worry, I'm working on the money part.
You just do your thing.


Sure.


OST: Leave No Trace

The assignment:
- Locate the two hosts with the specified hostnames (file 300), which correspond to the target power grid substations. When you've found them, cut the power by writing a value of 0 to #POWR.
- For more information see "Network Exploration: Geographic Information Systems" in the second issue of the zine.


This is the same GIS system we dealt with before, for the restaurant review assignment (Part 22). LINK 800 for north (top left), 801 for east, 802 for south and 803 for west.

However, this time I'll have to use the HOST command to find out the name of each host. It's not possible to test against a host name directly, you first need to load the value into some register with e.g. HOST X. Another complication is that we need to find two hosts. That'll mean some more register juggling.

That said, since the grid looks exactly the same, perhaps I can reuse some code from before. It was strongly optimized for that particular case and might not work as well here, but it's a start.

code:
LINK 800

REPL SOUTH
REPL NORTH
REPL EAST
JUMP POWERSWITCH

MARK SOUTH
LINK 802
REPL EAST
LINK 802
REPL EAST
REPL POWERSWITCH
LINK 800
JUMP POWERSWITCH

MARK NORTH
LINK 800
REPL EAST
LINK 800
REPL EAST
REPL POWERSWITCH
LINK 802
JUMP POWERSWITCH

MARK EAST
@REP 2
LINK 801
REPL POWERSWITCH
@END
LINK 801


MARK POWERSWITCH
NOOP
This is the low-cycle code I wrote for the restaurant review assignment, with all the file-parsing stuff stripped out. It gets an EXA to every grid space which then jumps to the POWERSWITCH mark.

People sent in some faster solutions but I prefer to start with this one because, since I wrote it myself, I understand exactly how it works.

Next I'll need to include some new code to switch off the right substations.

But... why stop there? Can't I just switch off everything? That should be enough of a distraction to pull off the heist, right?



I just replaced that NOOP at the bottom with a COPY 0 #POWR. It seems to be working, but there's a bit of an unforeseen side effect: cutting the power to a substation also takes the EXA host offline, making it untraversable and killing any EXAs that are chilling there.



It doesn't turn out to be a problem for us, since this optimized code from the previous assignment was written such that EXAs prioritize getting everywhere before they start messing around.

But "turn off everything" doesn't work - it fails the "Leave no trace" criterion.
However, it does net us the Steam achievement "BLACKOUT", description "Trigger an excessive service outage."

For testing if an EXA is in the right host, a sensible solution is to have a value from the file in T, then do HOST X and then TEST X T. As long as we don't need to test the same value twice that should work.

I can think of two ways to handle the second value. The first is by sending another full set of EXAs round, carrying the other value. That sounds complicated though, especially with hosts potentially turning off. The other way is an EXA staying home and sending the second value on M constantly. Let's try that.



XB grabs the file, sends the first value to M once, where XA can read it before it starts replicating. It then starts sending the second value. In POWERSWITCH, XA reads the HOST to X, compares it against the T value, and if it doesn't match, it compares against M. If it still doesn't match it can just die by divide by zero.

This code does turn off the right substations. But the problem is XB hangs forever, which means test cases never finish. Apparently I can't just disconnect my home computer when it's done.

Let's think about this one for a bit. How can we solve it?
- Because I put the X=T test first, only one of the EXAs doesn't test against M. With 20 grid tiles to check, that means XB will be asked for M 19 times. I could just build a countdown. The problem is that I can't store the countdown value in T because I have to test against it, and I can't put it in X because that's where I'm sending the value from (or I'd have to SEEK in the file which is slow). I guess I could use a second EXA for the countdown that just kills this one.

- Alternatively, I could have the EXA that reaches its tile last send a message back, and have XB listen to that with MRD or something.

But what if I do neither?

I have plenty of space left to just unroll the XB loop 19 times:
code:
;XA 

LINK 800
COPY M T

REPL SOUTH
REPL NORTH
REPL EAST
JUMP POWERSWITCH

MARK SOUTH
LINK 802
REPL EAST
LINK 802
REPL EAST
REPL POWERSWITCH
LINK 800
JUMP POWERSWITCH

MARK NORTH
LINK 800
REPL EAST
LINK 800
REPL EAST
REPL POWERSWITCH
LINK 802
JUMP POWERSWITCH

MARK EAST
@REP 2
LINK 801
REPL POWERSWITCH
@END
LINK 801


MARK POWERSWITCH
HOST X
TEST X = T
TJMP OFF
TEST X = M
DIVI 0 T T 
MARK OFF
COPY 0 #POWR

;XB

GRAB 300
COPY F M
COPY F X
@REP 19
COPY X M
@END
And that works.





Not a terrible first score of 50/58/22, but the top percentiles are 20, 22 and 20, so I certainly can do better.

Let's start with activity since that one is actually already solved.

Because my solution didn't require any KILL commands it's already quite good. But if you look at the gif, you'll see this code was originally optimized to reach the farthest grid squares first. In the SOUTHbound and NORTHbound chunks of codes it first travels to the end before jumping back to check the squares right next to the starting one. All I have to do is remove that old optimization.

code:
MARK SOUTH
LINK 802
REPL EAST
REPL POWERSWITCH
LINK 802
REPL EAST
JUMP POWERSWITCH

MARK NORTH
LINK 800
REPL EAST
REPL POWERSWITCH
LINK 800
REPL EAST
JUMP POWERSWITCH
That drops us to 49/56/20. Activity's done. The only way to get it lower is if we don't need to travel to every square, but since this is the top percentile I think the test cases cover all of them.

But wait... undoing an optimization made the cycle count lower? Ha.

That just goes to show that EXA optimizations are highly context specific. Premature optimization can lead you into a trap where the optimization doesn't fit the context anymore and it's too late to notice.

Anyway, let's look at the cycles some more. I feel the main slowdown comes from the fact that XB can only send a message on M every other cycle. There's a simple way to solve that: add another EXA.

code:
;XB

GRAB 300
COPY F M
COPY F X
REPL DOUBLETHEFUN
MARK DOUBLETHEFUN
@REP 10
COPY X M
@END
KILL
31/50/21. Since one of the EXAs sends an M message once too many, I just have the other one KILL it at that point.

What about the other method of sending two EXAs everywhere, each one holding a value from the file?

After some fiddling I came up with this code.
code:
;XA

LINK 800
REPL OTHER
MARK OTHER
COPY M X

REPL SOUTH
REPL NORTH
REPL EAST
JUMP POWERSWITCH

MARK SOUTH
LINK 802
REPL EAST
REPL POWERSWITCH
LINK 802
REPL EAST
JUMP POWERSWITCH

MARK NORTH
LINK 800
REPL EAST
REPL POWERSWITCH
LINK 800
REPL EAST
JUMP POWERSWITCH

MARK EAST
@REP 2
LINK 801
REPL POWERSWITCH
@END
LINK 801


MARK POWERSWITCH
HOST T
TEST X = T
DIVI 0 T T 
NOOP
NOOP
COPY 0 #POWR

;XB
GRAB 300
COPY F M
COPY F M
27/38/39.

Having a dedicated EXA to read the file is still slightly faster than having XA do that. The two NOOPs are unfortunate, but without that there are cases when the second EXA can't make it past a switched-off host in time.

I actually don't need those NOOPs for the EXAs that go second, so the next step is to selectively remove them.
The fastest way I found was duplicating almost all the code into XB.



25/67/40.

One thing that might speed up things more if to have both EXAs traverse the grid in different orders, so they block each other less. I tried some small things but nothing seemed to work so far, so if it's possible it's more subtle than what I did. It's also quite possible that the optimizations from the threads for the restaurant review assignment work here as well, but I'll leave that for you all to figure out.


Finally, for cycle count, the first thing to do is apply my low-cycle solution from the previous assignment, starting from the 38 solution above.
code:
;XA

LINK 800
REPL OTHER
MARK OTHER
COPY M X

JUMP START

MARK EAST
LINK 801
MARK START
REPL EAST
COPY 800 T
REPL NORTHSOUTH
REPL POWERSWITCH

COPY 802 T

MARK NORTHSOUTH
LINK T
REPL POWERSWITCH
JUMP NORTHSOUTH

MARK POWERSWITCH
HOST T
TEST X = T
DIVI 0 T T 
NOOP
NOOP
NOOP
NOOP
NOOP
COPY 0 #POWR

;XB

GRAB 300
COPY F M
COPY F M
The timing changed, requiring a bunch more NOOPs. 36/30/39, not as much improvement as I would've liked.

I can save a couple lines by loading something useful in T with the DIVI and then use a countdown loop.
code:
MARK POWERSWITCH
HOST T
TEST X = T
DIVI 3 T T 
MARK WAIT
SUBI T 1 T
TJMP WAIT
COPY 0 #POWR
37/28/39

Combining the EXAs won't help. Combining COPY F M and COPY M X means you still need two COPY to X commands total (one before and one after the REPL, because files aren't copied when you replicate an EXA). And you need an additional WIPE so the file doesn't end up in the grid.

The next obvious improvement would be to implement GuavaMoment's low cycle solution for Part 22. It won't quite work as-is, though. It depended on EXAs trying to grab files and them dying if the file was already taken. Without that, they fill up some hosts entirely and get stuck in a REPL command. I tried 'fixing' that by putting some KILL commands at the end but that just causes them to kill valid EXAs holding the other substation value. Putting it in the solution where XB just sends the second value over M many times doesn't work either, because the amount of times M is requested becomes variable.

So, I will stop here and wait to see how you got a better cycle count than 25 and a smaller size than 28.

Looks like the heist went flawlessly.
Congratulations, now a criminal cartel will sell the medication you helped steal back to you for not much less than the market price.
Oh well. At least they'll let you buy it from them.
Now that this is over with, I have a question.
Is theft morally acceptable in situations like this?




The first vote.

Next time, another hacker battle, this time against deadlock.

Onto the third of the tournament battles...
Is each match against a better programmer than the last?




Is it?