Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
GuavaMoment
Aug 13, 2006

YouTube dude

I've also got an 83 cycle solution now. Sending file 300 data over M saves a cycle from not having to wipe the file. I have a bunch of killer exas though and the solution is entirely dependent on exa ordering (which I found from trial and error) so the right exas get killed at the right times to save the last two cycles. It's clunky but it works.

Carbon dioxide posted:

Your suggestion is basically equivalent to the 10-line solution I show in my update, right?

Yes, whoops, I missed it. :P

Adbot
ADBOT LOVES YOU

silentsnack
Mar 19, 2009

Donald John Trump (born June 14, 1946) is the 45th and current President of the United States. Before entering politics, he was a businessman and television personality.

GuavaMoment posted:

I've also got an 83 cycle solution now. Sending file 300 data over M saves a cycle from not having to wipe the file. I have a bunch of killer exas though and the solution is entirely dependent on exa ordering (which I found from trial and error) so the right exas get killed at the right times to save the last two cycles. It's clunky but it works.

Another minor refinement is to combine two things I'd mentioned separately: we know file 300 has 27 entries and we need to COPY M #DATA on cycles [4,7,10,13...] so we need a COPY F M on [3,6,9,12...] since writing to M takes 2 cycles to complete, which lets us squeeze in some control logic instructions on [5,8,11,14...] and have XC loop/break smoothly so it kills XA at the right time and terminates on cycle 82
code:
;XC
GRAB 300
COPY 12 T
MARK LOOP
COPY F M    ;3...
SUBI T 1 T
COPY F M    ;...73
TJMP LOOP

COPY F M    ;75~76
COPY F M    ;77~79
KILL
COPY F M    ;81~82
Same cycles/activity but much smaller size with 83/23/28

silentsnack fucked around with this message at 20:42 on Jan 23, 2022

idhrendur
Aug 20, 2016

As they say, there are two hard things in computer science: cache invalidation, naming things, and off by one errors.

Why couldn't it?

Carbon dioxide
Oct 9, 2012

Part 11 - Лрикладной Семиотики


=== Trash World Inbox ===

Talisriel posted:

I did have another method to show for the achievement on Zebros:
code:
LINK 800
LINK 800
COPY 800 X
REPL PRINTER
ADDI 1 X X
REPL PRINTER
ADDI 1 X X
REPL PRINTER
ADDI 1 X X
REPL PRINTER
HALT
MARK PRINTER
LINK X
MARK WHEEE
COPY 9999 #COPY
JUMP WHEEE
Since the code is designed to go infinite we don't get evaluated, so it's harder to weigh efficiency, but I think this is the first time that we can meaningfully exploit LINKing to a Variable.
Yeah, so if you remember, this is for the TONER_LOW achievement you get by sending print jobs to #COPY constantly. Since LINKs use numbers like any other you can just create them with addition operators and everything.

Talisriel posted:

While I can't really contribute to the cause of optimization, I can contribute an alternate method. Weighing in at 357/20/1, I used the SWIZ function to retrieve my row/column data out of a single digit X:
code:
GRAB 300
LINK 800
MARK LOOP
SWIZ X 2 T
COPY T #DATA
SWIZ X 1 T
COPY T #DATA
COPY 0 T
COPY F #DATA
ADDI 1 X X
SWIZ X 1 T
TEST T = 9
FJMP NEOL
ADDI 1 X X
MARK NEOL
TEST EOF
TJMP CLEAR
JUMP LOOP
MARK CLEAR
WIPE
The original version of the code, up until I was copying it into this post, included a COPY 0 #CLRS line after the link to wipe the screen, but a quick check confirmed that Ember's file overwrites thoroughly enough that I didn't need it. You'll also note that I cheated not being able to run in base 8 with a test for when we got to the 9th slot, and added one to wrap to the next line (which I expect is where most of my extra cycles came from relative to your div/modi method).
Interesting solution I wouldn't have thought of. SWIZ X 1 T means: take the rightmost digit from X and store that to T. Replace the 1 with a 2 and it takes the second digit from the right. That almost works, but not quite, because a row has only 9 columns, so Talisriel had to add one more to X at the end of the row to bump it to 10, and so the second digit becomes the row count.

As you said, that'll cost a bit of time, but I can point out a couple other optimizations to your code:
code:
GRAB 300
LINK 800
MARK LOOP
SWIZ X 2 #DATA
SWIZ X 1 #DATA
COPY F #DATA
ADDI 1 X X
SWIZ X 1 T
TEST T = 9
FJMP NEOL
ADDI 1 X X
MARK NEOL
TEST EOF
TJMP CLEAR
JUMP LOOP
MARK CLEAR
WIPE
Since you need the result of the SWIZ operations only once, you can send it directly to #DATA instead of using T as an intermediate. I also removed the COPY 0 T since that value would be overwritten a couple lines later. 276/17/1

I think fiddling with the order of the tests and jumps could reduce the cycles further, but instead of trying to do that, let's look at what others came up with.

GuavaMoment posted:

You can have one exa feeding in the row data:
code:
LINK 800
MARK LOOP
DIVI X 9 #DATA
ADDI 1 X X
JUMP LOOP
One feeding in the column data:
code:
NOOP
LINK 800
MARK LOOP
MODI X 9 #DATA
ADDI 1 X X
JUMP LOOP
One feeding in data from the file
code:
GRAB 300
NOOP
LINK 800
MARK LOOP
COPY F #DATA
TEST EOF
FJMP LOOP
WIPE
and one to kill everything at the end
code:
NOOP
NOOP
NOOP
LINK 800
COPY 25 X
MARK LOOP
TEST X = 0
SUBI X 1 X
FJMP LOOP
KILL
KILL
86/30/6, still one cycle off top percentage though...
A very clean solution. Each EXA just has a simple loop, taking no more time than it has to, and very readable. I like it. The only quirk it uses is that the first KILL command happens just before the third EXA WIPEs the file. It just happens to kill another EXA first. I have no idea how that's decided by the game but if it works, it works.

Also, what do you mean, top percentage? Wait...





... gods do I feel silly now.
Somehow I managed to always glance over those particular options and I thought you couldn't see this except by guessing it from the histograms. :negative: .

Let's just pretend that never happened.

silentsnack posted:

If you're aiming for the theoretical minimum cycle count, you need your first #DATA input to be on cycle 2 (and then keep writing once every cycle. But as I later noticed we both ran into similar problems with getting the exit/cleanup down to 0 cycles)
code:
;XA
COPY 1 X
LINK 800
NOOP
MARK LOOP
REPL DO_THE_THING
ADDI X 1 X
JUMP LOOP

MARK DO_THE_THING
DIVI X 9 #DATA
MODI X 9 #DATA
COPY M #DATA

;XB
LINK 800
COPY 0 #DATA
COPY 0 #DATA
COPY M #DATA
COPY 38 T
MARK WAIT
SUBI T 1 T
TJMP WAIT
KILL
KILL

;XC
GRAB 300
MARK NOT_3
@REP 2
COPY F M
@END
JUMP NOT_3
84/26/4

This is about where the game starts throwing puzzles at you with enough complexity where it becomes more relevant that when an EXA tries to write to the M register, even if one is already waiting to receive, the sender still has to waste a cycle in the "I'm waiting to send!" state.

Also the @REP in XC needs to be any number that isn't 3 or 9 because if the loop trying to JUMP then XC doesn't crash until another cycle later when trying to arithmetic a nil due to EOF.
Nice. This one has faster cleanup at the end because you never move the file out of your host. XC will stop when it tries to read past the end of file. XB can start sending to #DATA as soon as possible because the first values are always zero anyway, giving XA plenty of time to set up its loop. It uses the parallelism trick of REPL-ing a new EXA while the previous #DATA cycle is still running.

silentsnack posted:

...also it occurs to me that it might be possible to make it even faster. Just gotta crash all EXAs on the same cycle #DATA is finished. The issue with the previous arrangement was being unable to kill XA before XA:26 wrote the last character, but that delay also required killing XA:27 which wasted a cycle.

code:
;XA
MARK LOOP
ADDI X 1 X
NOOP
REPL LOOP

LINK 800
DIVI X 9 #DATA
MODI X 9 #DATA
COPY M #DATA

;XB
LINK 800
COPY 0 #DATA
COPY 0 #DATA
COPY M #DATA

;XC
GRAB 300
@REP 26
COPY F M
@END
KILL
COPY F M
83/41/29

...which turns out to be an even cruder approach, forgoing loops in favor of recursion and bruteforce @REP spam
Ah, again XB handles the first cycle while XA sets itself up. XA lives in the home node where it clones itself constantly and goes into the network to copy to #DATA. That means no other travel is needed and XC, which needs to wait for each XA clone to pick up the M signal anyway, can use a well-timed KILL of XA in the home node, and that's all the clean-up necessary. XC'll just stop and it's not necessary to clean up anything in the home node.

Also, the gif for this one looks quite interesting.



I wish I could cover every small improvement y'all come up with but I feel my updates are getting long enough as they are and it's taking me a lot of time to make sense of each post, so I'm afraid I need to limit myself to those that actually improve the score or are especially interesting or novel. I appreciate every single of your suggestions though so please keep sending them in. If you're reading this from the LP Archive later and you want to know what you missed, go check the discussion in the LP Beach and SA LP threads.


=== Unknown Network 1 ===



I kinda like dead trees too. There's just something to having a real physical copy of some publication in your hands, you know.



Again, I have a choice of two assignments. I'll just do the top one today.

Can friendship exist without self-interest?



Another unanimous vote.

Why couldn't it?

There'd be no point if there weren't benefits to the parties involved?
But maybe it will make sense if I see this in the wild.
Anyway, there is a particular file I need you to locate here.
Don't concern yourself with whatever else you happen to see.
It's all obsolete.


You know, I feel you could go deep into philosophy with this train of thought. If you're friends with someone because spending time with them just makes you happy, does that count as "self-interest" of some sort?

Anyway, let's see what Ember wants from us in this unknown network.


New :siren: OST: Leave No Trace

What the hell is this network? My translator program says that text in the top says NSTU Department of Applied Semiotics, semiotics being the study of signs and symbols.

My assignment is:
- Find file 276 in the network and bring it back to your host.
- Note than an EXA cannot grab a file that is being held by another EXA.


That EXA in the far corner that's not controlled by us is holding a file. That's gotta be the file they're talking about. I guess, go over there, kill that EXA, and take the file home?



What does this mean and what do you want this for, Ember?

code:
LINK 800
LINK 801
LINK 801
LINK 801
KILL
GRAB 276
LINK -1
LINK -1
LINK -1
LINK -1
This is too simple, of course. It works for the initial test run, but the 'enemy EXA' is going to be in a different one of those 8 top-right hosts every test run.
At least bringing back the file is going to be the same every time, since all reverse LINK ids are -1.



This works better. At every step on the way the EXA has to choose which direction to go in. To make it go fast, I just REPL the EXA and have one go left and the other right. I reuse the initial LINK 800 in my little loop since I had it around anyway, and I keep a counter and TEST for it to see if I reached the final hosts and should start grabbing the file. The KILL command does nothing if there's no other EXA there, but GRABbing a non-existing file will cause the EXA to self-destruct. Only the EXA that finds the actual file will survive and will bring it home.





The top percentiles for this one are 15 / 15 / 27. So apparently we did the best we can activity-wise. How about the others?

The size is 16, so we just need to save a single line in this solution to be in the best percentile. What I can do is replace the four LINK -1 lines with this:
code:
MARK RETURN
LINK -1
JUMP RETURN
34/15/27.
That return loop never ends but that doesn't matter - the EXA will blow itself up in the home host once it tries to LINK to a non-existing -1.

For the cycle count, as always it's worth to look into unrolling the loops.

But that's easier said than done since the REPL itself introduces a kind of jump. I tried it anyway.

code:
LINK 800

REPL A
LINK 800
JUMP NEXTB

MARK A
LINK 801

MARK NEXTB

REPL B
LINK 800
JUMP NEXTC

MARK B
LINK 801

MARK NEXTC

REPL C
LINK 800
JUMP NEXTD

MARK C
LINK 801

MARK NEXTD

KILL
GRAB 276
LINK -1
LINK -1
LINK -1
LINK -1
This simply repeats the 800/801 choice three times. Each EXA that doesn't "choose" the REPL then has to jump to the next choice, ignoring the REPL's LINK instruction. It's quite ugly and it feels like we should be able to do (much) better, yet the new score is 18/25/27, which corresponds to that big peak to the left of the cycle histogram.

Shaving off those last three cycles is going to be tricky. Perhaps we can get rid of those unconditional jumps, but most of my ideas would require making more EXAs earlier and that wouldn't save any cycles because only one EXA can traverse any network link at a time.

I also attemped doing something where it tries to find the file after each step. But a GRAB on a non-existing file destroys the EXA, so you'd have to do a REPL first. A REPL blocks the EXA forever if there's no place for the clone (when there's an enemy EXA or even just a file sitting in the other square of the host). So that's not going to work. I'll leave this one to the thread.


Would you say you had friends?



And for the next assignment:

There's another file I want to grab.
They tried to wipe everything clean, but luckily, there's a set of backups.
Always keep a backup, right?




Two votes this time.

Carbon dioxide fucked around with this message at 14:58 on Jan 30, 2022

silentsnack
Mar 19, 2009

Donald John Trump (born June 14, 1946) is the 45th and current President of the United States. Before entering politics, he was a businessman and television personality.

1: depends on your definition of "friends"
2: depends on your definition of "always" :v:

Carbon dioxide posted:

Shaving off those last three cycles is going to be tricky. Perhaps we can get rid of those unconditional jumps, but most of my ideas would require making more EXAs earlier and that wouldn't save any cycles because only one EXA can traverse any network link at a time.

I also attemped doing something where it tries to find the file after each step. But a GRAB on a non-existing file destroys the EXA, so you'd have to do a REPL first. A REPL blocks the EXA forever if there's no place for the clone (when there's an enemy EXA or even just a file sitting in the other square of the host). So that's not going to work. I'll leave this one to the thread.


For the small solution, you can also use "link to a variable" and rearrange the code to fall through from the cloning operation to a different version of the clone, which eliminates the need for a JUMP/MARK pair in order to make both EXAs merge onto the same script.

code:
MARK LOOP
ADDI X 1 X
COPY 800 T
REPL FORK
COPY 801 T
MARK FORK
LINK T
DIVI X 4 T
FJMP LOOP

KILL
GRAB 276
MARK OUT
LINK -1
JUMP OUT
40/14/27



And as you mentioned, if you want the fastest solution for this puzzle you don't have any spare cycles for clever/elegant JUMP flow control, just weapons-grade spaghetti
code:
LINK 800
REPL 5
LINK 800
REPL 37
LINK 800
REPL 2468

LINK 800
KILL
GRAB 276
@REP 4
LINK -1
@END
HALT

MARK 2468
LINK 801
KILL
GRAB 276
@REP 4
LINK -1
@END
HALT

MARK 37
LINK 801
REPL 2468
[...]

MARK 5
LINK 801
[...]
15/46/27


edit: part of the challenge in this problem is the fact the target host has very limited room. So if we use the recursive self-replication trick we need some way to avoid forkbombing ourselves into an impassable traffic jam. In this case we know the destination is exactly 4 jumps away so we can just make the loop somehow end after 4 jumps, easily done by adding a count variable to the loop.

But here's a more general solution that would work in just almost any arbitrary-sized network (so long as there's no other traffic) but the code is bigger/slower because each clone cycle the main loop needs to spawn a separate process to handle the kill/grab/return routine, but the loop also needs to attempt to crash before it runs out of space to duplicate itself:
code:
MARK LOOP
COPY 800 T
REPL FORK
COPY 801 T
MARK FORK
REPL EXFIL
LINK T
LINK T
LINK -1
JUMP LOOP

MARK EXFIL
LINK T
KILL
GRAB 276
MARK OUT
LINK -1
JUMP OUT
less optimal at 44/17/63

silentsnack fucked around with this message at 02:55 on Jan 30, 2022

idhrendur
Aug 20, 2016

Sure I do
Right

NHO
Jun 25, 2013

НГТУ - Отдел Прикладной Семиотики
Typical soviet/russian university name abbreviation.
First letter is city, ГТУ is State Technological University. As in, owned by state, not located in state.

Carbon dioxide
Oct 9, 2012

Part 12 - UC Berkeley EECS


=== Trash World Inbox ===

silentsnack has some improvements for last week's puzzle.

silentsnack posted:

For the small solution, you can also use "link to a variable" and rearrange the code to fall through from the cloning operation to a different version of the clone, which eliminates the need for a JUMP/MARK pair in order to make both EXAs merge onto the same script.
code:
MARK LOOP
ADDI X 1 X
COPY 800 T
REPL FORK
COPY 801 T
MARK FORK
LINK T
DIVI X 4 T
FJMP LOOP

KILL
GRAB 276
MARK OUT
LINK -1
JUMP OUT
40/14/27
Reduces it to 14 from my 15. The trickiest part is getting the right way to rearrange the code, I guess.

silentsnack posted:

And as you mentioned, if you want the fastest solution for this puzzle you don't have any spare cycles for clever/elegant JUMP flow control, just weapons-grade spaghetti
code:
LINK 800
REPL 5
LINK 800
REPL 37
LINK 800
REPL 2468

LINK 800
KILL
GRAB 276
@REP 4
LINK -1
@END
HALT

MARK 2468
LINK 801
KILL
GRAB 276
@REP 4
LINK -1
@END
HALT

MARK 37
LINK 801
REPL 2468
[...]

MARK 5
LINK 801
[...]
15/46/27
Yep. The gaps in the code should basically handle each case manually, by LINKing to whatever side the REPL didn't handle yet. This way all unnecessary jumps are gone. By the way, using numeric MARK names doesn't make the code any easier to read.


=== UC Berkeley - Department of Electrical Engineering & Computer Sciences ===

Would you say you had friends?



Two votes for Sure I do.

Sure I do.

Yeah? Like Ghast? The EXAPUNKS?
But you never say anything to them.
Do friends not communicate back and forth?
Either way, this is good data for me.


I'm pretty sure it's TCP that communicates back and forth, lady.



I know real-life phreakers war-dialing business numbers sometimes found fresh dial tones... that would allow you to dial international numbers, billing the business for the costs.



Looks like Ember wants something from UC Berkeley. That's at least closer to home than whatever that Russian thing was.

There's another file I want to grab.
They tried to wipe everything clean, but luckily, there's a set of backups.
Always keep a backup, right?




Everyone who voted seems to agree.

Right.

You never know what's going to happen.
Data is more fragile than people think.


Make regular backups, folks.


OST: Leave No Trace

So, I got a bit curious and did some digging. The UC Berkeley department of EECS exists, and that logo is very similar to the style used on their official website - since around 2005ish. The web archive pages from before that look quite different. Bit of an anachronism, but I doubt Zachtronics expected anyone to dig this deep.

Our assignment:
- Locate the specified host (either tape-1, tape-2, or tape-3) and then locate the specified entry (ПАСЬЯНС) in the tape backup file in that host (file 200). Create a file in your host containing the entry's data.
- The names of the target host and entry are available in file 300.
- For more information see "Accessing Data in Legacy Storage Systems" in the first issue in the zine.


We also have a maximum size of 75 this time, quite a change from the 50 we've seen before.

All those files named 200 have a similar structure - a whole bunch of numbers and then some words and numbers.



Are those student grades?

Anyway, to the zine!



There's another page about hard drive arrays but that doesn't seem very relevant here.

Now, before I start you should notice there's no LINK ids back from most of those hosts. We can only travel counterclockwise. That's gonna be a bit limiting.

I could either start with two EXAs: one who stays home and communicates the info from 300 and one who goes find the data; or with one who does everything. I decided to go with the single EXA solution because it seems simpler - with two EXAs, how would you tell the home one it should switch from sending the TAPE number to sending the entry name?



Since it's a bit annoying to go back and forth in a file I decided to copy the TAPE number into X. It might save a cycle or two over the alternative.
It's not possible to TEST against the host name directly, I need to use the special HOST command to copy it into a register and TEST against that. Luckily I have T available for that.

Once the EXA tracks down the tape file, it copies the entry name to X, WIPEs the home file and GRABs the tape. Now to search for the entry.

Those zeroes just before the tape's index are probably padding, because all tapes are the same length. If that's true we can just SEEK straight to the start of the index and start searching from there. A SEEK 126 seems to do the trick.

After a bit of tinkering I settled on this:
code:
SEEK 124

MARK FINDENTRY
SEEK 2
TEST F = X
FJMP FINDENTRY
SEEK 2 is necessary for every cycle (to go to the next entry's name), and it's best to have it at the start to prevent some awkwardness when the EXA finds the right entry. Having the initial SEEK only go to 124 allows me to do this without too much overhead.



It makes sense to put the first value in T - I'm gonna need T for test results, and the first value contains the start position which I only need once anyway. The other value goes into X and the EXA can SEEK to the start position.

Now we run into a little problem - the EXA is going to have to copy a whole lot of data but it can only hold one file at once. I really don't see any other solution than introducing a second EXA and sending all the data over M.

I added this to XA:
code:
MARK SENDLOOP
COPY F M
SUBI X 1 X
TEST X = 0
FJMP SENDLOOP
It automatically stops when it's done.

And I made XB that simply does this:
code:
MAKE

MARK LOOP
COPY M F
JUMP LOOP
Getting close to a solution. The only problem is that XB never halts.

I could send XA home to KILL XB when it's done, but in situations like this I prefer using a special "end of transmission" packet. It might be slower, but we'll see.



Here's my first working solution. When XA is done it sends -9999 over M. If that's a valid entry in a tape file this won't work. I'll have to try and see.

XB now needs to use X as an intermediate register so it can TEST for -9999. Since I don't want to store -9999 in the file, the EXA should immediately exit the loop in that case. I can do that by, unintuitively, putting the COPY to F at the start of the next loop. To store the first entry correctly, there's an initial COPY from M before the loop. This assumes that we never get a zero-size entry but I think a zero-size entry wouldn't make sense anyway.



142/34/7.

Top percentile has 97/28/7. What can we do better?

First of all, the activity can't possibly be improved. We need 7 LINKs to get to tape 3, and sometimes we simply need to go there. Remember, to score a solution, it takes the worst-case scenario out of all the test runs.

Looking at cycles, there's a simple thing I missed in my initial solution: I don't need the TEST command to end the loops if I just set up the T register correctly.
code:
;XA

; LOAD INDEX AS BEFORE

SEEK -9999
SEEK T
COPY X T

MARK SENDLOOP
COPY F M
SUBI T 1 T
TJMP SENDLOOP

COPY 0 M

;XB

MAKE
COPY M T

MARK LOOP
COPY T F
COPY M T
TJMP LOOP
124/33/7. As it happens 0 isn't used as a valid number either so I can use that as the end-of-message packet. And I also used T for the for loop in XA now.

Next thing to look at is unrolling loops. There's no immediate obvious way to do this because every loop needs to check something which requires a TJMP/FJMP anyway. However, I can save many loops by making use of the fact there's a minimal data size - the file we're looking for is always at least 15 entries long. We really don't need to check if we're done before that.
code:
;XA

GRAB 300
COPY F X
LINK 800

MARK FINDTAPE
LINK 800
LINK 800

HOST T
TEST X = T
FJMP FINDTAPE

COPY F X
WIPE

GRAB 200

SEEK 124

MARK FINDENTRY
SEEK 2
TEST F = X
FJMP FINDENTRY

COPY F T
COPY F X

SEEK -9999
SEEK T
SUBI X 14 T

@REP 14
COPY F M
@END

MARK SENDLOOP
COPY F M
SUBI T 1 T
TJMP SENDLOOP

COPY 0 M

;XB
MAKE
@REP 14
COPY M F
@END

COPY M T

MARK LOOP
COPY T F
COPY M T
TJMP LOOP
96/61/7, cycle count already better than the top percentile somehow. But I still have some more ideas.

First, the earlier plan of using an EXA that stays home to send the data from the file so the 'main' EXA doesn't have to carry that file around.

I changed XA to LINK in the first cycle and read from M in the second cycle. It also reads from M when it would normally read the name of the data entry.
XB simply starts with GRAB 300; COPY F M; COPY F M; WIPE before it creates the new file. It had to wait anyway.

Result 95/63/7. I think the saved cycle comes from the fact that XA doesn't have to WIPE the file anymore. It isn't more because it now has to wait for XB's M.

We could perhaps fix that by having XA read from M later, but that would introduce other problems. No, I have a better idea: parallelism during the initial search:
code:
LINK 800
COPY M X

MARK FINDTAPE
LINK 800
LINK 800

REPL FINDTAPE

HOST T
TEST X = T
FJMP FINDENTRY

; TAPE HANDLING
This way, the new EXA is already LINKing to the next tape node while this one is still checking. I reuse the FINDENTRY mark here - the first command after it is a SEEK that requires the EXA to hold a file; so it quickly makes the EXA crash.

It's a good idea... but we have one problem. After the correct tape is found, the last REPL'd EXA just keeps going round and round, and if we allow it to keep going until the tape handling is done, it will pick up the tape file and cause trouble. We need to get rid of it.

Luckily we have plenty of spare lines of code and enough time while the other EXAs do their thing.





My final solution. XC basically waits in the host with file 243 for the number of cycles until XA makes a full circle. Just doing a couple KILLs then isn't quite enough, because XA tries to REPL and move on to another run around the block while the KILLs are happening and it's unpredictable whether the one that stays or the one that LINKs gets killed first. Instead I have XC itself REPL and sit there so that XA can't link, and it can be killed without a fuss.

This brings my best scores to 92 cycles, 33 size, and 7 activity. And that's where I'll stop. We know the size can definitely be improved, and perhaps the cycles can go even lower. Share your improvements.

Kind of a shame what happened here.
There was some interesting research going on.




Here's the vote for this update.

But first for something special...

.

.

.

.

.

.

Part 12.5 - ПАСЬЯНС

So that file that Ember made us get from UC Berkeley? Turns out it's a program I can run. Let's see what it is.




Ah, this old game.
It's just how I remember it...
A testbed for goal-seeking behaviors regulated by emotional reasoning.
Do you like to play games?



Eh, sometimes?

Picky, are we?
Well, this one's fun.



New :siren: OST: ПАСЬЯНС

A card game?



Ember made me go through all that for a game of Solitaire?

In fact, the Russian name directly translates to Solitaire. Like many other languages, they use the French name for the game, Patience.

Zachtronics always adds some sort of Solitaire bonus minigame to their games. In fact, their recent title NERTS! is entirely a Solitaire game, and an online competitive one at that. It's free on Steam.

There are three Steam achievements tied to this game: One for winning a round, one for winning 10 rounds and one for winning 100 rounds. Even though I wiped my save for this Let's Play, it still has my win count from the original save - I suppose it got that from Steam's achievement tracker.



The game isn't too hard, but it's good to stop and think before each move. It's easy to get yourself stuck. Also, make use of the free cell.



Getting some nice ordered stacks.



Stacks of four face cards on an empty spot are turned upside down and can't be moved again. Not that it matters - you can't move face cards anywhere except on other face cards of the same suit or an empty spot anyway.



I think I won?

If you ever need a break from hacking, this is a good choice.
It's mildly active, and not as taxing as putting together EXAs.
See how I am keeping your needs in mind.




And another vote.



Installing this game put a shortcut in my dock (to the right of Ember) so I can play it whenever I feel like it.

Carbon dioxide fucked around with this message at 20:07 on Dec 16, 2022

Carbon dioxide
Oct 9, 2012

Edit: merged with previous post for archival purposes

Carbon dioxide fucked around with this message at 20:07 on Dec 16, 2022

GuavaMoment
Aug 13, 2006

YouTube dude
My fastest solution is fundamentally identical to yours, I've just found a few cycles to squeeze out of some places, and I squoze one more cycle out from the seek 124 trick; I was previously seeking to the end and going backwards through the files. 89/70/7

code:

XA:

LINK 800
LINK 800
LINK 800
COPY M X
REPL TEST
LINK 800
LINK 800
REPL TEST
LINK 800
LINK 800
MARK TEST
HOST T
TEST X = T
FJMP TX
GRAB 200
SEEK 124
COPY M X
MARK SEARCH
SEEK 2
TEST F = X
FJMP SEARCH
COPY F X
COPY F T
COPY T M
SEEK -999
SEEK X
@REP 14
COPY F M
@END
SUBI T 14 T
MARK TX
COPY F M
SUBI T 1 T
TJMP TX


XB:

GRAB 300
COPY F M
COPY F M
DROP
MAKE
COPY M T
@REP 14
COPY M F
@END
SUBI T 14 T
MARK TX
COPY M F
SUBI T 1 T
TJMP TX

Carbon dioxide posted:

Part 12.5 - ПАСЬЯНС

Russian is difficult, but Cyrillic is rather easy when you're dealing with nouns or english loanwords, it only took me like a week of vacation immersion to pick up the letter substitutions.

П is the symbol for Pi, so is a P
A is A
C becomes S in Cyrillic
Ь can pretty much be ignored, it does some kind of modifier to the previous letter I don't understand?
Я can be replaced with "ya"
H becomes N

which makes this word PASYANS, and if you say that in a thick Russian accent you can see how it's supposed to be 'patience".

GuavaMoment fucked around with this message at 18:42 on Feb 5, 2022

silentsnack
Mar 19, 2009

Donald John Trump (born June 14, 1946) is the 45th and current President of the United States. Before entering politics, he was a businessman and television personality.

Carbon dioxide posted:

By the way, using numeric MARK names doesn't make the code any easier to read.
whups yeah that was just a crutch to make writing easier, using the scheme of the hosts already being labeled P-1000 through P-8000

GuavaMoment posted:

My fastest solution is fundamentally identical to yours, I've just found a few cycles to squeeze out of some places, and I squoze one more cycle out from the seek 124 trick; I was previously seeking to the end and going backwards through the files. 89/70/7

Files are at least 15 entries, but it's also possible to exploit the fact that they don't get much bigger, and that there are at most 7 files per tape. And you don't necessarily have to find the correct host since the filename is unique.

code:
;XA
LINK 800
LINK 800
LINK 800
COPY M X
REPL TAPE1
LINK 800
LINK 800
MARK TAPE2
LINK 800
LINK 800

MARK WHERE
GRAB 200; HOST = DGAF
SEEK 126
TEST X = F
@REP 6
TJMP WHICH
SEEK 2
TEST X = F
@END
DIVI T T T

MARK WHICH
COPY F X
COPY F T
REPL WHEN
SEEK -999
SEEK X
MARK WHAT
@REP 9 ; SIZE 15~18
COPY F M
@END
JUMP WHAT

; AWKWARD!
MARK TAPE1
REPL TAPE2
JUMP WHERE

MARK WHEN
COPY T M
MARK KILLSWITCH
SUBI T 1 T
TJMP KILLSWITCH
KILL

;XB
GRAB 300
VOID F
COPY F M
SEEK -2 ; RECYCLE F.300
SUBI M 1 T
REPL KILLSWITCH

MARK WRITE
COPY M F
JUMP WRITE

MARK KILLSWITCH
SUBI T 1 T
TJMP KILLSWITCH
NOOP
KILL
74/73/11

The REPL TAPE1 branch is because it takes the longest to reach TAPE3, so that one will be the limiting case and its EXA does as little else as possible. But the fact it's running a single codeblock and JUMP detours take more time, it required finding some place to wedge in between other operations.

For reducing size further, dividing by zero is an efficient way to crash an EXA. As is grabbing a nonexistent file.

code:
;XA
GRAB 300
COPY F X
COPY F X
WIPE
LINK 800

MARK WHERE
LINK 800
LINK 800
GRAB 200
REPL WHERE

MARK SEARCH
TEST X = F
FJMP SEARCH

COPY F X
COPY F T
SEEK -999
SEEK X

MARK WHAT
COPY F M
SUBI T 1 T
COPY T M
TJMP WHAT

;XB
MAKE
MARK WRITE
COPY M F
DIVI 1 M X
JUMP WRITE
420/27/9

also here's a vote for 'thanks' even if it's just a meaningless nicety. as for the other question, who *doesn't* have a weird history with berkeley's EECS department?

silentsnack fucked around with this message at 20:14 on Feb 5, 2022

idhrendur
Aug 20, 2016

What happened?
Thanks

GuavaMoment
Aug 13, 2006

YouTube dude

silentsnack posted:

And you don't necessarily have to find the correct host since the filename is unique.

Oh yeah, completely remove that part of the code and the files in the wrong host die on their own. That saves 4 cycles.

azsedcf
Jul 21, 2006

...a place of unlimited darkness.
"Where are the doors?" they asked nerviously.
Even my bellowing laughter couldn't fill this space.

Carbon dioxide posted:

Part 12 - UC Berkeley EECS


Are those student grades?


Can you pass/fail a entire class by editing file 243?

Carbon dioxide
Oct 9, 2012

Part 13 - Workhouse Work Management System


=== Trash World Inbox ===

Cloudmonkey98 posted:

No opinions on the questions today, and while I don't have a full code line since without the game its a bit hard for my layman brain to visualize it in my head, I DO have an idea for making a(slow) 1 Exa solution to bogarding our silly Solitaire game from the tapes instead of needing a receiving Exa.... or well I did until I remembered the Solitaire file is at least 15 entries of four digits, and our integer limit is 9999, I was considering the idea of using Multiplication to effectively add empty zeroes to the data number, and then Addition to slide the new numbers in, and then feed the numbers back onto the file somehow, using division to slice the leading digits off as remainders... yeah this wasn't the most well thought out solution but maybe it'll inspire someone else working 1 Exa plan...
A one EXA-solution is probably possible. The simplest way I can think of is create a new file, GRAB the tape file, COPY a value from the tape into a register, and use the other register to keep track of your location in the file. DROP it, GRAB the new file, write the value there, GRAB the tape again, SEEK to where you left off, and so on. You'd have to reread the length of the data you need to copy each time as well, since you don't have a register left for that. Which means bringing the name from file 300 along with you as well. It would end up being very slow, and since there isn't any reward for a low-EXA solution it's not something I focused on.

Cloudmonkey98 posted:

9999 integer limit feels wrong, I don't even DO programming and it feels wrong both for being Really Small for supposed super computer tech, and for being arbitrary instead of Rule of 2, 9999 is clean for RPGs, its wrong for programming
You're right. I think I said before I understand the decision from a game design point of view - if you're not familiar with computers powers of two feel really arbitrary, and it might be hard to explain to players who aren't familiar with it.

That said, what's "small" depends. Nowadays, with most CPUs being 64-bit, a register goes up to 2^64 or a 20-digit number in decimal. But not all that long ago, 8-bit systems were common (original Gameboy, NES, Atari...) and those only go up to 256 unsigned or 127 signed, and programmers made do. You can still work with larger numbers in those CPUs but it's a relatively slow multi-step process, so 256 is a very common limit for games from that era. I think in the time this game takes place in, 16-bit systems were still common, which go up to 65K. So I wouldn't call the 9999 maximum all that unrealistic.

GuavaMoment posted:

My fastest solution is fundamentally identical to yours, I've just found a few cycles to squeeze out of some places, and I squoze one more cycle out from the seek 124 trick; I was previously seeking to the end and going backwards through the files. 89/70/7
code:
XA:

LINK 800
LINK 800
LINK 800
COPY M X
REPL TEST
LINK 800
LINK 800
REPL TEST
LINK 800
LINK 800
MARK TEST
HOST T
TEST X = T
FJMP TX
GRAB 200
SEEK 124
COPY M X
MARK SEARCH
SEEK 2
TEST F = X
FJMP SEARCH
COPY F X
COPY F T
COPY T M
SEEK -999
SEEK X
@REP 14
COPY F M
@END
SUBI T 14 T
MARK TX
COPY F M
SUBI T 1 T
TJMP TX


XB:

GRAB 300
COPY F M
COPY F M
DROP
MAKE
COPY M T
@REP 14
COPY M F
@END
SUBI T 14 T
MARK TX
COPY M F
SUBI T 1 T
TJMP TX
Yeah, from a glance, some changes are unrolling the loop that initially finds the right file, and sending the file size to XB so it knows when it's done. You could save one additional cycle by replacing the COPY F T for the file size with SUBI F 14 T, and then you can remove the SUBI from XB, too.

silentsnack posted:

Files are at least 15 entries, but it's also possible to exploit the fact that they don't get much bigger, and that there are at most 7 files per tape. And you don't necessarily have to find the correct host since the filename is unique.
code:
;XA
LINK 800
LINK 800
LINK 800
COPY M X
REPL TAPE1
LINK 800
LINK 800
MARK TAPE2
LINK 800
LINK 800

MARK WHERE
GRAB 200; HOST = DGAF
SEEK 126
TEST X = F
@REP 6
TJMP WHICH
SEEK 2
TEST X = F
@END
DIVI T T T

MARK WHICH
COPY F X
COPY F T
REPL WHEN
SEEK -999
SEEK X
MARK WHAT
@REP 9 ; SIZE 15~18
COPY F M
@END
JUMP WHAT

; AWKWARD!
MARK TAPE1
REPL TAPE2
JUMP WHERE

MARK WHEN
COPY T M
MARK KILLSWITCH
SUBI T 1 T
TJMP KILLSWITCH
KILL

;XB
GRAB 300
VOID F
COPY F M
SEEK -2 ; RECYCLE F.300
SUBI M 1 T
REPL KILLSWITCH

MARK WRITE
COPY M F
JUMP WRITE

MARK KILLSWITCH
SUBI T 1 T
TJMP KILLSWITCH
NOOP
KILL
74/73/11

The REPL TAPE1 branch is because it takes the longest to reach TAPE3, so that one will be the limiting case and its EXA does as little else as possible. But the fact it's running a single codeblock and JUMP detours take more time, it required finding some place to wedge in between other operations.
Nice. Also uses the trick of having XA and XB have a separate countdown. It also saves cycles by putting those in REPL'd EXAs which run a KILL command at the end. And yeah, skipping the host check and just checking all files in parallel helps a lot too, as well as unrolling the filename search loop. The DIVI T T T is a nice trick here. It only triggers if a tape contains the maximum number of files. If T is zero (the last file isn't the one we're looking for), dividing by zero immediately crashes the EXA. If it is one, it continues and falls through into the data copying code. An interesting way to do a test and crash in a single cycle.

silentsnack posted:

For reducing size further, dividing by zero is an efficient way to crash an EXA. As is grabbing a nonexistent file.
code:
;XA
GRAB 300
COPY F X
COPY F X
WIPE
LINK 800

MARK WHERE
LINK 800
LINK 800
GRAB 200
REPL WHERE

MARK SEARCH
TEST X = F
FJMP SEARCH

COPY F X
COPY F T
SEEK -999
SEEK X

MARK WHAT
COPY F M
SUBI T 1 T
COPY T M
TJMP WHAT

;XB
MAKE
MARK WRITE
COPY M F
DIVI 1 M X
JUMP WRITE
420/27/9
Aha. Yeah, so it just REPLs endlessly looking for new files. I had trouble getting around that and had to use my ugly solution of having another EXA just blocking the path, but by grabbing file 200 first and then REPL'ing, instead if the file doesn't exist it just crashes itself. Other than that, this code scans the entire tape line by line for the name of the program. It does so for each file, and an EXA automatically crashes when it tries to read past the end of the file. Finally, by sending two values over M for each data value (the actual value and the T counter), XB knows when to stop using the DIVI by zero check. Although if we're going for low size count, replacing the last two lines in XB with COPY M T; TJMP WRITE works just as well.

azsedcf posted:

Can you pass/fail a entire class by editing file 243?
Well, maybe you can. But the game doesn't acknowledge this in any way, other than failing the "Leave no trace" rule.


=== Workhouse - Work Management System ===

Kind of a shame what happened here.
There was some interesting research going on.




I saw only the one vote this time, for 'what happened?'

What happened?

Oh, you know.
People get swapped around, priorities change...
Things don't work out for lots of reasons.




The second edition of the zine might turn out quite interesting. Glad I helped out Ghast.

If you ever need a break from hacking, this is a good choice.
It's mildly active, and not as taxing as putting together EXAs.
See how I am keeping your needs in mind.




Two votes for 'Thanks.'

Thanks

You're welcome.
Appreciating me will make things easier.
Let's continue.


... make what easier?



Anyway, Nivas is here. Let's hope they have some good stuff.



Special delivery.

Nivas hands me another pack of bootleg medication.

Whatever it is you're doing for money... it's working.
Makes me wish I had a line like that.
More control over my life...

I found out something interesting the other day.
You ever hear about these things called EXAs?
They're these little guys running around inside computers.
They make it all work. Banks, commerce, government... anything you can think of.
Funny, how it's all based on the same stuff on the inside.
Just something I've been thinking about lately.
Anyway, see you around.
Got a feeling I'll be making more deliveries.


"eksas"? Can't say I heard of them, Nivas.



Ain't nobody got time to play games. I need to get work done.



Hey, Workhouse, isn't that that stupid app I used a while back, where you enter data for some scraps?

How many receipts do you think a normal human being could enter per minute?
Assuming average conditions.




I guess that depends on how long they are.

I may have been too fast.
My estimates were based on incorrect assumptions.
Once again.
Guess we have to clear this up.


Ember, what have you done now... Let's go fix it then.


OST: Code and Registers

Hm, looks like we connected through a vulnerability in their SECURE host. Not very secure, is it?

The assignment:

- Locate EMBER-2's user file in the users host and overwrite it so that the sum of the values is the same but no individual value exceeds $75. All values, except for the last, must be the maximum value ($75). You will need to add additional values to accomplish this.
- EMBER-2's username is available in file 300.
- Note that the sum of the values in EMBER-2's account will always be less than $10,000.
- For more information see "Network Exploration: Workhouse" in the first issue of the zine.




Before we start let's take a peek at all the files first.



File 300 is in our home host and contains EMBER's username, 'NORMALHUMAN'.

File 199 in the secure host has a list of usernames and... are those passwords? Stored in plaintext? Crap, it's a good thing I used an unique password when I signed up. I can't believe companies still store passwords in plaintext, they should know better than that. If some malicious hacker were to get access they could try to get into other places with those passwords. Anyway, the third value is the user number.

Looks like files 213 to 246 are user files. They start with the user's full name (NORM STANDART for EMBER), then what I think is a birth date, and then the amount of dollars they made each day. This is what we're going to need to edit.

The last set of files contains jobs. A job id, then a bunch of numbers, and then a description. Looks like they're running the following jobs right now:
- Cronus Capital Markets. Receipt Data Entry. You will be shown images of receipts generated in the course of normal everyday business and will enter them digitally for bookkeeping and reimbursement purposes. Save a busy executive a minute or two!
- Managed Research Corp. Prior Art Search. You will comb over patent filings for potential examples of prior art in order to provide important information for patent litigation. Don't worry about understanding the technical terminology - any match is a good one!
- Heartland Bounty. Visual inspection of beef and pork. You will monitor a networked digital camera inside a meat processing facility, keeping a keen eye out for mishandling, spoiled or rotten products, and other issues. Make a contribution to food safety and public health!
- Pinpoint marketing. Identify duplicate database entries. You will browse a large database of corporate personnel records. Some of the entries are slightly modified duplicates created with the intent to defraud the corporation. Identify the duplicate entries and send them packing!
- Royal Aegis Waste Processing. Categorize Waste Objects. You will be shown images of various pieces of refuse as they are conveyed along a track at a waste processing facility. Categorize these objects as paper, glass, metal, or rubber. By helping to sort out trash, you make non-toxic water possible!


You know, I can't help but think the quality of some of these services has to suffer if you hand this work to underpaid internet randos.

That's all there's to see in the host. Those EXAs in the bottom right aren't reachable since the LINKs have no numbers.

Back to the assignment - we have to find EMBER's user file and update the amounts so the total is the same but it's spread over more days. The assignment is nice enough to state the sum will always be less than $10000, that means the whole thing fits in a register.



Starting simple, I read the username from file 300, then find it in 199. The SEEK 2 saves a couple cycles because there's no point checking against the password or file number, but it puts the cursor one past the file number once the EXA finds the right user. So I SEEK back one, store the ID, and LINK into the USERS host to GRAB EMBER's file.



And this is a working solution. The EXA copies the first number into X (to get rid of whatever was there before), then goes through a SUM loop where it adds the rest of the numbers. TEST EOF is necessary to prevent it from just crashing at the end. Then it goes back to the start of the file (SEEK 2 to get past the metadata) and keeps writing 75 until less than that is left in X, in which case it writes the remainder to the file and ends. Note that if you write to an existing position in the file it overwrites it, if you write to the end it appends, so this code works for both cases.

I went for less than 76 because otherwise, if the remainder is 0 the final COPY would write a trailing 0 into the file which might tell Workhouse that something is wrong (but it turns out this never comes up in the test set so either way is fine).



The top percentiles this time are 218, 27, and 2.

Getting the top percentile for size is easy enough. That SEEK 2 in the FINDUSER loop is not necessary at all, it just speeds up some cycles. If I remove it, the SEEK -2 has to be replaced with a SEEK 1. 531/27/2.

I wouldn't be surprised if it's possible to get an even smaller size but there's much bigger gains to be gotten in the cycle count.


Oops, I accidentally gave two EXAs the same name.

I dedided to start with a relatively small improvement by splitting up the EXAs and having them go to the right host immediately, then wait for instructions on M. 516/29/3.

Since there's always at least 10 days worth of data in the file, we can delay the slow EOF check and unroll part of that loop by putting @REP 8; ADDI F X X; @END above the SUM loop. 500/37/3.

But there's a much bigger improvement somewhere. How about this for the writing EXA:
code:
NOOP
LINK 800
LINK 799
GRAB M

SEEK 2
COPY F X

@REP 8
ADDI F X X
@END

MARK SUM
ADDI F X X
TEST EOF
FJMP SUM

SEEK -9999
SEEK 2

DIVI X 75 T

MARK OVERWRITE
COPY 75 F
SUBI T 1 T
TJMP OVERWRITE

MODI X 75 F
By dividing X by 75, we get how often 75 fits in X, and we can just put that in T and use a countdown. Saves a TEST instruction every cycle. For the end, just use the MODI function to get the remainder quickly.

Again we can unroll part of this loop. How much depends on the total amount of money EMBER made. From some testing it turns out that's always at least 60 times $75. This can be handled with @REP 60; COPY 75 F; @END; SUBI T 60 T. However, that doesn't fit in the 75-line limit for this level.

So, let's just run @REP 30 twice:
code:
NOOP
LINK 800
LINK 799
GRAB M

SEEK 2
COPY F X

@REP 8
ADDI F X X
@END

MARK SUM
ADDI F X X
TEST EOF
FJMP SUM

SEEK -9999
SEEK 2

MARK FILLFILE
@REP 30
COPY 75 F
@END
SUBI T 1 T
FJMP FILLFILE

DIVI X 75 T
SUBI T 60 T

MARK OVERWRITE
COPY 75 F
SUBI T 1 T
TJMP OVERWRITE

MODI X 75 F
Before entering FILLFILE, the EXA has T set to 1 (from the last EOF test). The first loop's SUBI makes it 0, false, and the second makes it -1, true. This is a quick way of going through the loop just twice without requiring extra setup of the T register. 275/71/3.

My next idea involved something we've seen in thread submissions quite a few times now: speeding up the overwrite loop by putting the countdown in a separate EXA that kills the first one when it's done. The issue is that after that the remainder still needs to be written. This works:
code:
; XA

GRAB 300
COPY F M

;XB

LINK 800
GRAB 199
COPY M X

MARK FINDUSER
TEST F = X
SEEK 2
FJMP FINDUSER

SEEK -1
COPY F M

SEEK -1
COPY F M

;XC

NOOP
LINK 800
LINK 799
GRAB M

SEEK 2
COPY F X

@REP 8
ADDI F X X
@END

MARK SUM
ADDI F X X
TEST EOF
FJMP SUM

SEEK -9999
SEEK 2

MARK FILLFILE
@REP 25
COPY 75 F
@END
SUBI T 1 T
FJMP FILLFILE

REPL KILLER

MARK OVERWRITE
COPY 75 F
JUMP OVERWRITE


MARK KILLER
DIVI X 75 T
SUBI T 52 T

MARK COUNTDOWN
SUBI T 1 T
TJMP COUNTDOWN

KILL
GRAB M
SEEK 9999
MODI X 75 F
After the FILLFILE unroll is done, XC replicates itself into a KILLER clone. Since that one's job, at first, is just to count down, it has plenty of time to calculate the starting value of T, as long as the number in SUBI T 52 T is adjusted so it starts at exactly the right cycle count. After the killer kills the EXA that writes 75, it can grab the file (XB has been waiting all that time to send the ID of the file just once more), and adds the remainder.

The only issue is I ran into size limit problems again. In this solution I solved that by reducing the unroll size in FILLFILE, but that slightly slower compared to not having to do that. 235/75/4.

I can get some of the complete unroll back by making FILLFILE loop thrice:
code:
COPY 3 T

MARK FILLFILE
@REP 19
COPY 75 F
@END
SUBI T 1 T
TJMP FILLFILE

COPY 75 F
and change the SUBI of the killer to 60. I had to go for @REP 19 instead of 20, because the countdown always runs at least once and for the test where there's exactly 61 * 75, it would start at zero and go into the negatives, getting stuck into an infinite loop. The limit where this still barely works is at 3 * 19 + 1 hardcoded 75s, hence the lone COPY 75 T to save one more cycle. 230/71/4.

And that's where I'll stop. The top percentile is 218 so let me know what further improvements are possible.


Just when I think I'm decent at pretending to be human, I find there's another parameter to add.



The first dialogue choice.

And next, the intro for the next assignment.

How much does money affect behavior?
A lot, right?


Carbon dioxide fucked around with this message at 16:56 on Feb 12, 2022

berryjon
May 30, 2011

I have an invasion to go to.
At least she's not a Hugh Mann. That person is very suspicious. After all, a normal person wouldn't use an easily guessable password.

I thought an AI would be faster
Yeah, a lot

Junpei
Oct 4, 2015
Probation
Can't post for 11 years!

berryjon posted:

I thought an AI would be faster
Yeah, a lot


going with these as well

idhrendur
Aug 20, 2016

How long have you pretended to be human
Yeah, a lot

GuavaMoment
Aug 13, 2006

YouTube dude

Carbon dioxide posted:

And that's where I'll stop. The top percentile is 218 so let me know what further improvements are possible.

My 216 solution is not elegant. Mostly identical to yours, but I run 21 lines of "Copy 75 F", until X < 2500, where I run 9 lines of "Copy 75 F" until X < 750, then keep alternating between copying 75 and testing every time until X is zero.

Next assignment: I do something very similar.

Your suggestion got UC Berkeley down to 84 cycles, thanks!

NGDBSS
Dec 30, 2009






idhrendur posted:

How long have you pretended to be human
Yeah, a lot

Seconding these.

Quackles
Aug 11, 2018

Pixels of Light.


How long have you pretended to be human?

And:
Some behaviors aren't affected by money...

silentsnack
Mar 19, 2009

Donald John Trump (born June 14, 1946) is the 45th and current President of the United States. Before entering politics, he was a businessman and television personality.

idhrendur posted:

How long have you pretended to be human
Yeah, a lot



Carbon dioxide posted:

let me know what further improvements are possible.

Looking at my solutions... I don't even remember writing this but aside from obviously being the product of trial and error it seems crude/unfinished? Maybe I'm just tired but I'm not seeing what it does all that differently, other than minor improvements like combining COPY F X and an ADDI X F X operation into ADDI F F X.
code:
;XA
GRAB 300
COPY F X
WIPE
LINK 800
GRAB 199
MARK FIND
TEST F = X
SEEK 2
FJMP FIND

SEEK -1
COPY F M

;XB
LINK 800
LINK 799
GRAB M
SEEK 2

ADDI F F X
@REP 7
ADDI X F X
@END
MARK ADD
ADDI X F X
TEST EOF
FJMP ADD

SEEK -999
SEEK 2
DIVI X 1800 T
MODI X 1800 X
MARK WRITE24
@REP 24
COPY 75 F
@END
SUBI T 1 T
TJMP WRITE24

DIVI X 225 T
FJMP END
MODI X 225 X
MARK WRITE3
SUBI T 1 T
@REP 3
COPY 75 F
@END
TJMP WRITE3

MARK END
TEST X > 75
FJMP BREAK
SUBI X 75 X
COPY 75 F
JUMP END

MARK BREAK
COPY X F
But somehow the stats are showing 195/75/3

Carbon dioxide
Oct 9, 2012

Part 14 - Equity First Bank


=== Trash World Inbox ===

GuavaMoment posted:

My 216 solution is not elegant. Mostly identical to yours, but I run 21 lines of "Copy 75 F", until X < 2500, where I run 9 lines of "Copy 75 F" until X < 750, then keep alternating between copying 75 and testing every time until X is zero.
Ah, yes, so basically repeating large chunks of writing 75s with only the occassional test and loop and then progressively smaller chunks and more common tests. Optimizing that is gonna be trial and error, depending on the specific puzzle input.

silentsnack posted:

Looking at my solutions... I don't even remember writing this but aside from obviously being the product of trial and error it seems crude/unfinished? Maybe I'm just tired but I'm not seeing what it does all that differently, other than minor improvements like combining COPY F X and an ADDI X F X operation into ADDI F F X.
code:
;XA
GRAB 300
COPY F X
WIPE
LINK 800
GRAB 199
MARK FIND
TEST F = X
SEEK 2
FJMP FIND

SEEK -1
COPY F M

;XB
LINK 800
LINK 799
GRAB M
SEEK 2

ADDI F F X
@REP 7
ADDI X F X
@END
MARK ADD
ADDI X F X
TEST EOF
FJMP ADD

SEEK -999
SEEK 2
DIVI X 1800 T
MODI X 1800 X
MARK WRITE24
@REP 24
COPY 75 F
@END
SUBI T 1 T
TJMP WRITE24

DIVI X 225 T
FJMP END
MODI X 225 X
MARK WRITE3
SUBI T 1 T
@REP 3
COPY 75 F
@END
TJMP WRITE3

MARK END
TEST X > 75
FJMP BREAK
SUBI X 75 X
COPY 75 F
JUMP END

MARK BREAK
COPY X F
But somehow the stats are showing 195/75/3
Those 1800 and 225 calculations do something similar to what GuavaMoment said, reducing the number of loops by testing for larger chunks. That together with the ADDI combination thing and perhaps some other improvements make it much faster, I think.


=== Equity First Bank ===

Just when I think I'm decent at pretending to be human, I find there's another parameter to add.



Two votes for "I thought an AI would be way faster", and five for the winning option.

How long have you pretended to be human?

Oh, pretty much from the start.
It's kind of a thing that I do.
Remember when I surprised you? That was a good one.
Let's continue.


Yeah, let's.





That sounds... chaotic.

How much does money affect behavior?
A lot, right?




Two votes for "Some behaviors aren't affected", five for the other choice.

Yeah, a lot.

I'm going to do an experiment involving wealth redistribution.
Sudden, random wealth redistribution.
This should be fun.



OST: Leave No Trace

The assignment:
- Dispense all available cash from all connected ATMs.
- For more information see "Network Exploration: Equity First Bank" in the first issue of the zine.


The max code size for this assignment is 50 lines.



Okay, so we don't really need to mess with the account files. Let's take a quick peek though.



It's basically as the zine says. Files have an account number and name and then a bunch of transactions. There's also a file 199 but that seems to just contain a list of the other file names. Nothing very exciting.



Messing around with the ATMs a bit I quickly learned two things: the #DISP register only accepts exactly 20 as input. You can't tell it to dispense $40 to make it spit out two bills at once. And if you tell it to dispense bills when the #CASH register is empty, the entire host will error out, which immediately fails the "Leave no trace" goal.

Also, the attached ATM hosts actually differ for each test case. The LINK ids are always between 800 and 806 inclusive but it's often not the complete set.

So, the first challenge is getting EXAs to all the ATMs. This code will work:



I can think of quite a few ways to do this, some a bit faster than others. For instance I could just make 7 EXAs and hardcode the different LINK instructions to 800 - 806. But since the IDs are sequential, using a REPL clone loop seems a bit more straightforward and probably makes the program smaller.
The problem is that I need to have a way to stop the loop, otherwise it keeps spawning new clones forever, and we can't leave any EXAs running around.

I decided to handle that with a cleanup EXA that just kills the cloning EXA after its timer runs out.

Next, dispensing cash from all the ATMs. Just to have something working I started with this naive solution:
code:
LINK 800
LINK 800 
LINK 800
REPL CLEANUP

COPY 799 X

MARK CLONE
ADDI 1 X X
REPL CLONE
LINK X

COPY #CASH T

MARK DISPLOOP
COPY 20 #DISP
SUBI T 1 T
TJMP DISPLOOP

HALT

MARK CLEANUP
COPY 7 T

MARK CLNLOOP
SUBI T 1 T
TJMP CLNLOOP
KILL
A very simple loop with a countdown so it knows when the ATM runs out of cash.

There's no loop unrolling or anything and there's huge amounts of bills so this is slow.



Very slow. In fact, this takes almost a full minute to run all 100 tests at fast forward speed.



However, it does work, as you can see from the crowd of people flocking around the ATM.

The top percentiles are 1072, 14, and 10.

Let's start with improving activity. Since it always counts the worst test, the activity is 10 if you need to get EXAs to all 7 ATMs and only move the one to the host just before the ATMs. So the only activity step that can be removed is the one KILL instruction.

Well, that's easy enough if we don't care about making the code even slower.
code:
LINK 800
LINK 800 
LINK 800

COPY 799 X

MARK CLONE
ADDI 1 X X
TEST X > 806
TJMP END
REPL CLONE
LINK X

COPY #CASH T

MARK DISPLOOP
COPY 20 #DISP
SUBI T 1 T
TJMP DISPLOOP

MARK END
I put the countdown in the CLONE loop so I can remove the cleanup EXA. Result: 3028/16/10.

That's quite nice, we also happen to be getting close to the top percentile in size. Only two more lines of code to get rid of.

The MARK END isn't actually required. We can TJMP from the CLONE loop to the DISPLOOP mark... it'll then try to COPY to #DISP which doesn't exist in that host and it'll crash. That's 15 LoC.
Also, the COPY from #CASH and the countdown in T can be combined into a single line by just testing #CASH directly each round.



3027/14/10

Let's go back to the initial solution and see if we can speed it up. With a max size of 50, we don't have much spare room for unrolling loops but we can do at least some.

code:
LINK 800
LINK 800 
LINK 800

COPY 799 X

MARK CLONE
ADDI 1 X X
TEST X > 806
TJMP DISPLOOP
REPL CLONE
LINK X

MARK 33LP
@REP 33
COPY 20 #DISP
@END

TEST #CASH > 33
TJMP 33LP

MARK DISPLOOP
COPY 20 #DISP
TEST #CASH = 0
FJMP DISPLOOP
I started from the low-size solution since it fits some more unrolling. Simple enough: if there's still more than 33 bills left, spit out 33, otherwise count them one by one. 1145/50/10. Much faster already. Also, turns out that combining this with the cleanup EXA solution drops the cycle count to 1144, even though there's only space for 27 unrolls.

From that solution we can drop it to 1125/50/11, using this code:
code:
LINK 800
LINK 800 
LINK 800
REPL CLEANUP

COPY 799 X

MARK CLONE
ADDI 1 X X
REPL CLONE
LINK X

MARK 28LP
@REP 28
COPY 20 #DISP
@END

TEST #CASH > 28
TJMP 28LP

MARK DISPLOOP
COPY 20 #DISP
DIVI X #CASH X
JUMP DISPLOOP


MARK CLEANUP
COPY 7 T

MARK CLNLOOP
SUBI T 1 T
TJMP CLNLOOP
KILL
The main change is that I got rid of the HALT instruction by stopping the loop using a divide by zero crash. This lets me bump the unroll to 28 which is enough to save a bunch more cycles.

And because increasing the size of the unroll is so important, I should focus on that, regardless of anything else.

For instance, replacing the cleanup code with the much uglier
code:
MARK CLEANUP
SUBI X 1 X
TEST X < -6
FJMP CLEANUP
KILL
saves a line of code, allowing one more COPY in the unroll, dropping the cycles from 1125 to 1122.

Finally, I found one more minor improvement, but it's a bit of a weird one.
code:
LINK 800
LINK 800 
LINK 800
REPL CLEANUP

COPY 799 X

MARK CLONE
ADDI 1 X X
REPL CLONE
LINK X

MARK 29LP
@REP 29
COPY 20 #DISP
@END

DIVI 28 #CASH T
FJMP 29LP

MARK DISPLOOP
COPY 20 #DISP
DIVI X #CASH X
JUMP DISPLOOP


MARK CLEANUP
SUBI X 1 X
TEST X < -6
FJMP CLEANUP
KILL
1120/50/11

The DIVI 28 #CASH T line speeds up things slightly because it acts as a three-way test.
If #CASH is 29 or greater, the result will be 0, causing FJMP to jump back into the unroll and dispense 29 more bills.
If #CASH is smaller than 29 but greater than 0, the result is (rounded) 1, so it won't jump and continue to the DISPLOOP.
And if it's exactly zero, the EXA immediately crashes with a divide by zero error. This means that it doesn't even have to go into the DISPLOOP once if the amount of bills is a multiple of 29, which happens in some slow test, saving two cycles.

1120 is still almost 50 cycles away from the top percentile. I'm still missing a significant improvement somewhere. I was thinking about making a smaller unrolled loop after the big one - to more quickly deal with the remaining bills. But since that takes cycles from the large unrolled loop, that seems to make things slower overall. Perhaps there's a very specific combination that makes it faster but I haven't found it.

Alternatively I'd look into running the DISPLOOP code in parallel, but I'm not sure how to do that. There's no place for an extra EXA in the ATM hosts, so no other EXA can come in to kill the dispenser EXA. And communicating via M would be hard too - there's only one global M register for all EXAs, and waiting for a kill signal on M isn't any faster than an EXA handling that by itself.

So, let me know what I'm missing.

Well, that caused a bit of chaos.
But not as much as I hoped.
I wonder why.




And next time, more body hacking to slow down the Phage.

So you're going to be hacking your own heart.

GuavaMoment
Aug 13, 2006

YouTube dude
So first off you can get a 12 line, 10 activity solution with this by combining some tricks:

code:
LINK 800
LINK 800
LINK 800
COPY 807 X
MARK CLONE
MODI -1 X X
REPL CLONE
LINK X
MARK CASHGET2
COPY 20 #DISP
DIVI 999 #CASH X
JUMP CASHGET2
Yeah, you create 807 exas, but it works! MODI -1 0 X kills the exa.

For getting things fast, you need lots of loop unrolling, so I populate the exas differently that doesn't need a killer. It's a tiny bit slower to do that task but saves a bunch of lines, making things overall faster. Why giant loops of 21 and 8? No idea, ask me years ago when I did this by trial and error until it worked. Why do I test for #CASH > 29 even at a time when I know it's not? No idea, but it's faster! 1102/50/10

code:
LINK 800
LINK 800
LINK 800
COPY 806 X

MARK CLONE
REPL CASHGET
SUBI X 1 X
TEST X = 800
FJMP CLONE

MARK CASHGET
LINK X

MARK SPILL
@REP 21
COPY 20 #DISP
@END
MARK TENS
@REP 8
COPY 20 #DISP
@END
TEST #CASH > 29
TJMP SPILL
TEST #CASH > 8
TJMP TENS

MARK CASHGET2
COPY 20 #DISP
DIVI 999 #CASH X
JUMP CASHGET2

Junpei
Oct 4, 2015
Probation
Can't post for 11 years!
Not A Big Distraction and I'm a little scared.

Quackles
Aug 11, 2018

Pixels of Light.


Here's my desultory best effort, with loop unrolling in a similar way:

code:
@REP 3
LINK 800 ;LES GO
@END

COPY 800 X
MARK REPLICATE
REPL GOLINK
ADDI X 1 X
TEST X < 806
TJMP REPLICATE
MARK GOLINK
LINK X

MARK KICKOUT
COPY 20 #DISP
MODI #CASH 32 T
TJMP KICKOUT

MARK KICKTEN
@REP 32
COPY 20 #DISP
@END
COPY #CASH T
TJMP KICKTEN
1146/50/10.

It also occurs to me that by not using Steam (I disagree with its DRM), I've saved myself a lot of hair loss. The metrics on my copy of the game show the histogram graphs, but not the percentiles or anyone I know.

So I'm only really going against the general public and myself.

Moto42
Jul 14, 2006

:dukedog:
This got me to install this and get going again. Thanks for doing this LP.

Really enjoying seeing other people's takes on these cases, and trying to impliment y'all's thoughts into my own code.

My second crack at the bank is as follows, weighing in at 1149/50/10.

code:
NOTE GOTO HALLWAY
LINK 800
LINK 800
LINK 800

NOTE CLONING
COPY 806 T
@REP 6
REPL JACKPOT
SUBI T 1 T
@END

MARK JACKPOT
LINK T

MARK 25ATATIME
@REP 25
COPY 20 #DISP
@END
TEST #CASH > 25
TJMP 25ATATIME

MARK REMAINDER
DIVI 1 #CASH T
COPY 20 #DISP
JUMP REMAINDER
Ok, so job one, goto the hallway, nothing fancy

Then making the clones. My thinking is, if you can make the the first just fall-through to the code all the clones run, you can skip killing it, or counting clones.
Then it's all just loop unrolling and brute-forcing the remainder

GuavaMoment: "807 EXAs"
That's an interesting way of handling the problem. Limiting the EXA population is extra work, and I haven't thought about eliminating until now.
Your MODI -1 X X is brilliant.

I got curious. Is starting with 7 EXAs faster, or will they just get stuck in a log-jam on the way to the hallway and waste cycles?
So, I edited my "Goto hallway" and "cloning" sections to just this, changing the final line to it's target host and made 7 of them.
code:
LINK 800
LINK 800
LINK 800
LINK 806


The result weighs in a 252 lines of code, takes 1134 cycles, and has an activity of 28.

So, yea, it is faster to start with 7 EXAs, but each one can only have 7 lines of code.

Moto42 fucked around with this message at 03:21 on Feb 22, 2022

Carbon dioxide
Oct 9, 2012

Part 15 - Mitsuzen HDI-10 - Heart


=== Trash World Inbox ===

GuavaMoment posted:

So first off you can get a 12 line, 10 activity solution with this by combining some tricks:
code:
LINK 800
LINK 800
LINK 800
COPY 807 X
MARK CLONE
MODI -1 X X
REPL CLONE
LINK X
MARK CASHGET2
COPY 20 #DISP
DIVI 999 #CASH X
JUMP CASHGET2
Yeah, you create 807 exas, but it works! MODI -1 0 X kills the exa.
Hah, nice. Yeah, basically you try to get to each ATM from 807 down to zero. That saves a check. At 3010 cycles it isn't even that slow (since creating all the EXAs doesn't take as long as emptying out the ATMs).

It's a bit weird to think about the modulo function with negative numbers but in this case it basically acts as a decrement operation that crashes at zero. I should remember that, it could come in handy later.

Moto42 posted:

So, yea, it is faster to start with 7 EXAs, but each one can only have 7 lines of code.
Yeah, that's why I never really considered that. 7 lines is not enough for any other optimizations, that have more of an effect.

Quackles posted:

Here's my desultory best effort, with loop unrolling in a similar way:
code:
@REP 3
LINK 800 ;LES GO
@END

COPY 800 X
MARK REPLICATE
REPL GOLINK
ADDI X 1 X
TEST X < 806
TJMP REPLICATE
MARK GOLINK
LINK X

MARK KICKOUT
COPY 20 #DISP
MODI #CASH 32 T
TJMP KICKOUT

MARK KICKTEN
@REP 32
COPY 20 #DISP
@END
COPY #CASH T
TJMP KICKTEN
1146/50/10.
Interesting idea to handle the "remainder" first. I tried if I could get any more optimizations out of this design but I couldn't.

GuavaMoment posted:

For getting things fast, you need lots of loop unrolling, so I populate the exas differently that doesn't need a killer. It's a tiny bit slower to do that task but saves a bunch of lines, making things overall faster. Why giant loops of 21 and 8? No idea, ask me years ago when I did this by trial and error until it worked. Why do I test for #CASH > 29 even at a time when I know it's not? No idea, but it's faster! 1102/50/10
code:
LINK 800
LINK 800
LINK 800
COPY 806 X

MARK CLONE
REPL CASHGET
SUBI X 1 X
TEST X = 800
FJMP CLONE

MARK CASHGET
LINK X

MARK SPILL
@REP 21
COPY 20 #DISP
@END
MARK TENS
@REP 8
COPY 20 #DISP
@END
TEST #CASH > 29
TJMP SPILL
TEST #CASH > 8
TJMP TENS

MARK CASHGET2
COPY 20 #DISP
DIVI 999 #CASH X
JUMP CASHGET2
You did a smart thing here I hadn't considered. You put the 21 and 8 loop right after each other, meaning that from the MARK SPILL you actually get a 29-size loop (with no delays, because the only thing in between is a MARK which doesn't use a cycle when you just pass it.) So, that's what the > 29 check is for. If there's more than 29 bills left, do the whole loop again, otherwise only do the partial loop of 8 bills, and if there's less than 8 left to the remainder one by one. But yes, the numbers that work best here can only be found by trial and error.

Alright, so GuavaMoment's 1102 cycle solution is the best we got in the threads. But that's still a ways from the 1072 top percentile, and I got curious. So I decided to look it up. Turns out someone called StinkingBanana uploaded a fast solution just last week. Since they also uploaded a lot of stuff about future puzzles I won't directly link to it here. But I will share the solution because it's a thing of beauty.
Spoilered for anyone who wants to give it a try themselves first.

After getting the clones in place, simply do:
MARK DISP
@REP {as often as possible}
MODI 20 #CASH #DISP
COPY 20 #DISP
@END
JUMP DISP


You see what this does? The MODI/COPY combination handles the checking if we're done without any conditional jumping at all.
- If #CASH > 20, MODI 20 #CASH #DISP will write 20 to #DISP, acting like a free, additional COPY.
- If it's between 0 and 20, it will write 0 to #DISP, which doesn't do anything. At this point only the actual COPY instructions work.
- If #CASH is exactly 0, the next MODI will immediately crash the EXA.

So, for the majority of the program, MODI will act like an additional COPY. For the last 20 bills, it'll act like a "Am I done?" check.

Their solution runs at 1072/50/10, but has a bit of slack in the cloning code. Combining it with GuavaMoment's cloning code drops it to 1069, and using my solution with the CLEANUP clone, I managed to get it down all the way to 1067 cycles.



=== Mitsuzen HDI-10 - Heart ===

Well, that caused a bit of chaos.
But not as much as I hoped.
I wonder why.




I got one vote for each option. This one goes to the random number generator.

People are good at ignoring problems.

Hmm.
I'll have to aim for something bigger next time.


...Uh oh.



They're not lying, though. There are computers everywhere. In fact, there's probably a computer near you, right now!



drat, the phage is getting to my heart. Gotta do something quick.

So you're going to be hacking your own heart.



Two votes for the third option.

I'm a little scared.

Why?
What happens if your heart stops beating?
Don't tell me. You die?
Processing.
Huh. I guess that explains some things.
At least all you need to do is make it beat.




It's, uh, it's a little more complicated than that, Ember. I thought you studied humans, how do you not know our basic biology?

Human physiology is fascinating.
I should learn more about it.


...Why do I feel like I just said the wrong thing?

Either way, let's get started.


OST: EXA Power

It's been a while since I last hacked my body, let's see if I remember how this works.

I have to do the following:
- Read a value from the nerve connected to your central nervous system (CNS) and make your heart beat by writing a sequence of values to your sinoatrial (SA-N) and atrioventricular (AV-N) nodes as indicated in the HDI-10 I/O log when holding the "SHOW GOAL" button. The length of each sequence of values should be equal to the value from the CNS divided by -10. Repeat ad infinitum.
- It is not necessary to leave no trave. Your EXAs should be written to operate indefinitely.
- For more information see "Debugging the Phage" in the first issue of the zine.


I've shown that article from the zine already, nothing new there. I have to write values like this:



Alright, if I understand correctly, when I get -42 as input, I have to write -42 / -10 = 4 (rounded down) values to the outputs. The first value to SA-N has to be 40, the others are -70 (neural resting potential, according to the zine). For the AV-N output the first value has to be -70, the SECOND 40, and the rest -70.

Note that EXA cycles are much faster than a heartbeat, so I don't have to sync cycles perfectly, as long as I get the order of outputs right.
code:
LINK 800
REPL SA
REPL AV

HALT

MARK SA
LINK 1
LINK 1

HALT

MARK AV
LINK 3
LINK 3
I'll just start with a single EXA that clones itself, to have the lowest activity score out of the way.

For the lowest activity score I also can't move the EXAs around any further so I'll have to use the M register, and since both EXAs need to know how many cycles to write, I'll need to send the value to M twice. So the input EXA will have to be something like this:
code:
LINK 800
REPL SA
REPL AV

MARK INLOOP
DIVI #NERV -10 X
COPY X M
COPY X M
JUMP INLOOP
Since I can read from the #NERV only once (after that it will output the next value), I use X as an intermediate and divide by -10 while I'm at it.

Both of the other EXAs have to read from M and write the values to their nerve connections:
code:
MARK SA
LINK 1
LINK 1

MARK SALOOP
SUBI M 1 T
COPY 40 #NERV

MARK SACOUNTDOWN
COPY -70 #NERV
SUBI T 1 T
TJMP SACOUNTDOWN

JUMP SALOOP

MARK AV
LINK 3
LINK 3

MARK AVLOOP
SUBI M 2 T
COPY -70 #NERV
COPY 40 #NERV

MARK AVCOUNTDOWN
COPY -70 #NERV
SUBI T 1 T
TJMP AVCOUNTDOWN

JUMP AVLOOP
I assume that every input corresponds to at least two writes to the outputs (otherwise you can't get a proper heartbeat). That's why I can put the special stuff (writing the 40) outside the loop, as long as I make sure to subtract the appropriate value from my counter too.

Let's test this code.



Oh... the first 17 tests succeeded but after that, "operation successful, patient dead" as they say? There's some wrong outputs in the list (and the cycle count keeps going until I abort since the EXAs never quit). What went wrong here?

Stepping through the code a bit, it turns out that the AV EXA is a bit faster than the SA one. Normally that's no problem, but since this test has several fast heartbeats (inputs between -30 and -39), at some point the AV EXA reads from the M register twice before SA has a chance, desyncing everything.

One way to fix that would be to have the input EXA only send to ONE of the others and have that one contact the other one. Serial messaging. That feels slow. I have a better idea.

The AV EXA does 2 writes before getting into the loop, the SA one only 1. That's why AV is faster. I'm going to try having the SA EXA also write two values before getting into the loop. This would fail if the input is ever between -29 and -20... but the AV EXA already can't handle that, so let's try it and hope for the best.



Aaaaand.... it works! 88/32/5.

Top percentiles are 80, 24, and 5. For the Phage levels, while the EXAs should run forever, the cycle count is based on how long it takes to fill out the test result table to the right.

For speeding it up, I tried some loop unrolls first.
code:
@REP 4
COPY -70 #NERV
SUBI T 1 T
FJMP SALOOP
@END
and also for AV. Or unroll the big SALOOP/AVLOOP. Can't use @REP there because the MARK names need to be different for each duplicate, but a manual unroll still works. Anyway, best I got with either attempt was 86 cycles. This ain't it.

Let's try something completely different. Can we parallellize? Well, not really with the M register. But we can have a lot of EXAs running around at the same time.

I tried some things the fact that the amount of time the EXAs are busy writing depends on the input caused me issues. If you send EXAs to the output nerves as fast as possible, the second EXA will start writing before the first is done. That won't work. We need to slow them down - but not too much. Perhaps the output EXA could signal when it's done? But that would be through the M register which is always a bit slow - taking 2 cycles at the least.

I came up with this instead.
code:
;XA

LINK 800
MARK NEXT
DIVI #NERV -10 X
SUBI X 3 T

REPL SA
REPL AV

JUMP NEXT

MARK SA
LINK 1
LINK 1


COPY 40 #NERV
COPY -70 #NERV
JUMP COUNTDOWN

MARK AV
LINK 3
LINK 3

COPY -70 #NERV
COPY 40 #NERV

MARK COUNTDOWN
@REP 5
COPY -70 #NERV
MODI -1 T T
@END

JUMP COUNTDOWN

;XB

LINK 800
REPL AV
REPL WAIT

LINK 1
REPL WAIT
REPL WAIT
REPL WAIT

LINK 1
REPL WAIT
MARK WAIT
JUMP WAIT

MARK AV
LINK 3
REPL WAIT
REPL WAIT
REPL WAIT

LINK 3
REPL WAIT
JUMP WAIT
XB simply fills up all the hosts with clones until there's only one free position and then gets into an infinite waiting loop. XA reads a value from the input, parses it, then clones itself and sends the clones off to the output. Since there's only one free space per host they'll just queue up in order, and LINK to the next host the first available cycle.
I needed to keep one XB in the input host as well, because otherwise there's some issues with the wrong XA clone LINKing first. This way, only one clone can be formed at a time.

Since each XA clone can die after doing its thing, this means I can consolidate the countdowns into a single loop, which can be unrolled quite a few times. And I use the MODI trick GuavaMoment showed us in the Trash World Inbox to decrement-or-die in a single cycle.



And this gets me a score way below the top percentile, with only 69 cycles. Nice!

To my surprise, when I looked at my stats after this, it listed my lowest size as 25. How did I do that?

Turns out it was actually the parallel-but-wait-for-M solution I mentioned being too slow. It's this code:
code:
LINK 800
MARK NEXT
DIVI #NERV -10 X
SUBI X 2 T
REPL SA
REPL AV

VOID M
VOID M
JUMP NEXT

MARK SA
LINK 1
LINK 1
COPY 40 #NERV
COPY -70 #NERV
JUMP COUNTDOWN

MARK AV
LINK 3
LINK 3
COPY -70 #NERV
COPY 40 #NERV

MARK COUNTDOWN
COPY -70 #NERV
SUBI T 1 T
TJMP COUNTDOWN

COPY 0 M
131/25/29. The original EXA won't jump to NEXT until it reads from M twice, which means both clones finished. I can't replace the two VOID M's with something like SUBI M M X, the game specifically disallows reading from M twice in the same instruction. The top percentile value is 24 so further improvement is possible but I'm not sure what.

Do you ever wish you were a computer?
A functioning computer, I mean.




Well, do we, thread?
And for next time...

Well, this is flattering.
Someone found a bunch of my network nodes and sent in a tip to Ghast!
Too bad I can't have people knowing about me.
You're going to have to hack me out of that message.




And that's the two votes for this week.

GuavaMoment
Aug 13, 2006

YouTube dude

Carbon dioxide posted:

The top percentile value is 24 so further improvement is possible but I'm not sure what.

23 Lines by having a main EXA send out AVN and SAN pairs. In pairs, the first value (AVN) is -70, then two 40 values (SAN then AVN), then -70 until you're done. AVN and SAN exas die graciously by trying to link to a non-existent node or just by running out of code. And a swizzle for style points.

code:
LINK 800
COPY -70 X

MARK COPY
SWIZ #NERV 2 T
ADDI 1 T T
REPL AVN
COPY 40 X

MARK REPL
REPL SAN
REPL AVN
COPY -70 X
ADDI 1 T T
TJMP REPL
REPL SAN
JUMP COPY

MARK SAN
LINK 1
LINK 1
COPY X #NERV

MARK AVN
LINK 3
LINK 3
COPY X #NERV
My low cycle solution was much worse than what you did.

Late edit: As pointed out a few posts below, change REPL SAN and JUMP COPY lines with REPL COPY to save one more line.

GuavaMoment fucked around with this message at 22:54 on Feb 26, 2022

berryjon
May 30, 2011

I have an invasion to go to.
Nah
Are you Spying?

Also, if I'm reading the nature of the code right, we've just created an adhoc pacemaker to stabilize the motions of the heart to keep blood flowing.

Junpei
Oct 4, 2015
Probation
Can't post for 11 years!
Nah and Are you spying on Ghast?

silentsnack
Mar 19, 2009

Donald John Trump (born June 14, 1946) is the 45th and current President of the United States. Before entering politics, he was a businessman and television personality.

Sometimes/how?

You can use some fallthrough structure to reduce size too
code:
LINK 800
MARK A
DIVI #NERV -10 X
SUBI X 2 T
REPL B
LINK 1
LINK 1
COPY 40 #NERV
COPY -70 #NERV

MARK BEAT
COPY -70 #NERV
SUBI T 1 T
TJMP BEAT

LINK -1
LINK -1
JUMP A
MARK B
LINK 3
LINK 3
COPY -70 #NERV
COPY 40 #NERV
JUMP BEAT
119/22/41

And to reduce time, the usual parallel countdown/kill shenanigans can work

code:
LINK 800
DIVI #NERV -10 X
SUBI X 2 T
REPL A

MARK LOOP
SUBI T 1 T
TJMP LOOP
DIVI #NERV -10 X
SUBI X 2 T
REPL LOOP

MARK A
REPL B
LINK 1
LINK 1
REPL TIMER
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT
MARK B
LINK 3
LINK 3
REPL TIMER
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT

MARK TIMER
SUBI T 1 T
TJMP TIMER
KILL
63/32/31


edit: ...and after randomly thinking about this again a couple of days later, it occurs to me that there might be a more efficient way make the timers and #NERV writing run both in parallel and serial, but actually implementing that plan ends up requiring a special-case for the first pair:
code:
LINK 800

REPL A0
DIVI #NERV -10 X
SUBI X 2 T
REPL A

MARK LOOP
SUBI T 1 T
TJMP LOOP
DIVI #NERV -10 X
SUBI X 2 T
REPL LOOP

MARK A
REPL B
LINK 1
LINK 1
MARK WAIT_A
SUBI T 1 T
TJMP WAIT_A
KILL
JUMP ADATA

MARK B
LINK 3
LINK 3
MARK WAIT_B
SUBI T 1 T
TJMP WAIT_B
KILL
JUMP BDATA

MARK A0
REPL B0
LINK 1
LINK 1
NOOP
NOOP
MARK ADATA
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT

MARK B0
LINK 3
LINK 3
NOOP
NOOP
MARK BDATA
COPY -70 #NERV
COPY 40 #NERV

MARK BEAT
COPY -70 #NERV
JUMP BEAT
62/50/45

1 cycle faster but it's tiredbrain'd garbagecode

silentsnack fucked around with this message at 06:58 on Feb 28, 2022

idhrendur
Aug 20, 2016

berryjon posted:

Nah
Are you Spying?

Carbon dioxide
Oct 9, 2012

Part 16 - TRASH WORLD NEWS - Unknown Context


=== Trash World Inbox ===

GuavaMoment posted:

23 Lines by having a main EXA send out AVN and SAN pairs. In pairs, the first value (AVN) is -70, then two 40 values (SAN then AVN), then -70 until you're done. AVN and SAN exas die graciously by trying to link to a non-existent node or just by running out of code. And a swizzle for style points.

code:
LINK 800
COPY -70 X

MARK COPY
SWIZ #NERV 2 T
ADDI 1 T T
REPL AVN
COPY 40 X

MARK REPL
REPL SAN
REPL AVN
COPY -70 X
ADDI 1 T T
TJMP REPL
REPL SAN
JUMP COPY

MARK SAN
LINK 1
LINK 1
COPY X #NERV

MARK AVN
LINK 3
LINK 3
COPY X #NERV
My low cycle solution was much worse than what you did.

Late edit: As pointed out a few posts below, change REPL SAN and JUMP COPY lines with REPL COPY to save one more line.
Nice, 22 lines with the additional line saved. The swizzle is used to put the tens in the ones place, meaning you can have a simple countdown on T without needing any TEST instructions. Of course a DIVI #NERV 10 T would've done the exact same.

silentsnack posted:

You can use some fallthrough structure to reduce size too
code:
LINK 800
MARK A
DIVI #NERV -10 X
SUBI X 2 T
REPL B
LINK 1
LINK 1
COPY 40 #NERV
COPY -70 #NERV

MARK BEAT
COPY -70 #NERV
SUBI T 1 T
TJMP BEAT

LINK -1
LINK -1
JUMP A
MARK B
LINK 3
LINK 3
COPY -70 #NERV
COPY 40 #NERV
JUMP BEAT
119/22/41
Ah, and to prevent EXAs interfering with each other you just have the same EXA going back home every time. Luckily the return link IDs happen to be different (-3) for the other path - that's not the case in every level.

silentsnack posted:

And to reduce time, the usual parallel countdown/kill shenanigans can work
code:
LINK 800
DIVI #NERV -10 X
SUBI X 2 T
REPL A

MARK LOOP
SUBI T 1 T
TJMP LOOP
DIVI #NERV -10 X
SUBI X 2 T
REPL LOOP

MARK A
REPL B
LINK 1
LINK 1
REPL TIMER
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT
MARK B
LINK 3
LINK 3
REPL TIMER
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT

MARK TIMER
SUBI T 1 T
TJMP TIMER
KILL
63/32/31
This was what I was struggling with. I was thinking about having one counter and the problems of it killing both "A" and "B" EXAs at once, but using one counter for each solves that.

silentsnack posted:

...and after randomly thinking about this again a couple of days later, it occurs to me that there might be a more efficient way make the timers and #NERV writing run both in parallel and serial, but actually implementing that plan ends up requiring a special-case for the first pair:
code:
LINK 800

REPL A0
DIVI #NERV -10 X
SUBI X 2 T
REPL A

MARK LOOP
SUBI T 1 T
TJMP LOOP
DIVI #NERV -10 X
SUBI X 2 T
REPL LOOP

MARK A
REPL B
LINK 1
LINK 1
MARK WAIT_A
SUBI T 1 T
TJMP WAIT_A
KILL
JUMP ADATA

MARK B
LINK 3
LINK 3
MARK WAIT_B
SUBI T 1 T
TJMP WAIT_B
KILL
JUMP BDATA

MARK A0
REPL B0
LINK 1
LINK 1
NOOP
NOOP
MARK ADATA
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT

MARK B0
LINK 3
LINK 3
NOOP
NOOP
MARK BDATA
COPY -70 #NERV
COPY 40 #NERV

MARK BEAT
COPY -70 #NERV
JUMP BEAT
62/50/45
:psyduck: Nice. The very same EXAs first kill the previous ones and then start sending the next heartbeat. Yeah, that'd be very fast. Of course the special first case is needed to get the timings to line up perfectly. Meanwhile the CNS EXA is also doing a countdown so it starts the new round at exactly the right time. And your solution barely fits in the 50 cycle limit.

berryjon posted:

Also, if I'm reading the nature of the code right, we've just created an adhoc pacemaker to stabilize the motions of the heart to keep blood flowing.
Yes, that seems to be the case.


=== TRASH WORLD NEWS - Unknown Context ===

Do you ever wish you were a computer?
A functioning computer, I mean.




Four votes for "Nah", one for "Sometimes".

Nah...

That's okay.
I never wished for a human body, myself.
But they're interesting to learn about.
Such strange design choices.


It's... complicated.





Hm, a Trash World News assignment again... but this time it's not a tutorial anymore.

Well, this is flattering.
Someone found a bunch of my network nodes and sent in a tip to Ghast!
Too bad I can't have people knowing about me.
You're going to have to hack me out of that message.




Four votes for "Are you spying", one for the other choice.

Are you spying on Ghast?

I live on computer networks.
Sometimes I see things go by.
That's all.



OST: Code and Registers

My assignment:
- Find and replace the keywords in the target message (file 212) as directed by EMBER-2.
- A list of keyword pairs indicating which words should be found and what they should be replaced with is available in file 300. For example, the keyword AI should be replaced with the keyword COLLECTIVE. Each keyword will only occur once, but may occur in any order.
- Also, move file 200 to the outbox.


... that third point is very random. Let's look at the files though, there's a whole bunch in Ghast's computer.


File 300 is the replacement list Ember prepared for us. 200 literally says "Move this file to the outbox". I really don't get the point of this file.
209, 212, and 217 contain mail, and 212 is the one we gotta change.

Finally, file 237 is in a host called PRIVATE and it says:
"Hi Ghast. I'm sorry to hear this news. And I'm sorry that this is the occasion that brings us back into contact with each other. We can't change the past, but we can focus on the good memories instead of the bad ones.
Though it may sound strange for me to say it, I'm glad you've found a purpose in life, even now. It's never too late for that. -K"


Um. I have a feeling I was not supposed to see that.

In the other test cases, all files are the same except 300 and 212, but they just have their contents shuffled. So there's no other messages to be found.

There's a lot of ways to approach this. Let's just start and see where we end up. I'll begin with getting the outbox file out of the way and getting an EXA's hands on 212.

code:
LINK 800
REPL OUTBOX
LINK 799
GRAB 212
[...]

MARK OUTBOX
GRAB 200
LINK 800
The easiest way I can think of to handle this is to search through the file once for every word I need to replace. Sure, it's slow, but it should work.



XB's only purpose is to send the contents of 300 over M.
XA gets the first value and just searches for that in the file. Now to build the replace logic.



It sort of works. The message now reads like some nonsense from a crazy person, so Ghast'll probably ignore it. Except XA gets stuck here after XB finishes and dies.

code:
;XA

LINK 800
REPL OUTBOX
LINK 799
GRAB 212

MARK REPLACE
COPY M X
TEST X = 0
TJMP OUTBOX
MARK SEARCH
TEST F = X
FJMP SEARCH
SEEK -1
COPY M F
SEEK -9999
JUMP REPLACE

MARK OUTBOX
GRAB 200
LINK 800

;XB

GRAB 300
MARK LOOP
COPY F M
TEST EOF
FJMP LOOP
COPY 0 M
A simple solution is to have XB send a final control message. That means XA has to test for it. If it finds the control message it jumps to the outbox MARK - and will then die because it cannot grab another file while it's still holding one. Success!



This runs at 561/24/3. Top percentiles are 541, 20, and 3. Hmm, I guess you can't make it all that much faster.

While I was thinking about improvements I suddenly remembered the TEST MRD instruction. That sets T to 1 if something is trying to send on M this cycle, 0 otherwise, WITHOUT actually reading the value from M. It's not often useful because the timing just doesn't line up, but in this case, because XB spends all its time waiting to send, we can use it as a "are we done" check.

code:
;XA

LINK 800
REPL OUTBOX
LINK 799
GRAB 212

MARK REPLACE
TEST MRD
FJMP OUTBOX
COPY M X
MARK SEARCH
TEST F = X
FJMP SEARCH
SEEK -1
COPY M F
SEEK -9999
JUMP REPLACE

MARK OUTBOX
GRAB 200
LINK 800

;XB
GRAB 300
MARK LOOP
COPY F M
JUMP LOOP
This improves the cycles and size: 555/22/3

To speed things up further I decided to make a separate EXA to move 200 to the outbox (saving one cycle from XA which doesn't have to do the REPL anymore), and to unroll part of the REPLACE loop.



In most cases, the second iteration in REPLACE jumps back into the first one with the FJMP SEARCH. The only exception is when the search word is at the very start of the file. That's why further unrolls don't help. 548/31/4.

Moving the TEST MRD at the top of XA to the end of the loop skips two cycles in the first search, bringing the total to 546. And we can skip another cycle by preventing the SEEK -9999 from running during the last loop. That requires a bit of fiddling, though.

code:
;XA

LINK 800
LINK 799
GRAB 212

MARK REPLACE
COPY M X
MARK SEARCH
TEST F = X
FJMP SEARCH
SEEK -1
COPY M F
TEST MRD
DIVI 0 T T

SEEK -9999
COPY M X
TEST F = X
FJMP SEARCH
SEEK -1
COPY M F

TEST MRD
DIVI 0 T T
SEEK -9999
JUMP REPLACE

;XB

GRAB 300
COPY F M
MARK LOOP
COPY F M
COPY F M
JUMP LOOP

;XC

NOOP
LINK 800
GRAB 200
LINK 800
Since the TEST MRD now happens a single cycle after COPY M F, there can't be a JUMP between them in XB. A bit of reordering in XB solved that. I also changed the jump to END by a divide by zero. It doesn't save any cycles but it looks nicer. 545/32/4.

To get to the top percentile score I thought about making a counting EXA that kills the writing one. The problem is that there's nothing to count - there's no way to know when the writer is done searching.

But what it can do is take over the MRD check. Taking the above code, I removed the two pairs of TEST MRD and DIVI instructions from XA, added an extra NOOP to the start of XC (so it goes behind all others, it'll finish first anyway), and made a fourth EXA:

code:
;XD

NOOP
LINK 800
LINK 799

MARK LOOP
TEST MRD
TJMP LOOP
ADDI X 1 X
TEST X = 5
FJMP LOOP

NOOP

MARK LOOP2
TEST MRD
TJMP LOOP2

KILL
Basically, the inner LOOP tests if there's something on M every other cycle. Whenever XA reads from M, there's a cycle when there's nothing to read and TEST MRD is false. These cycles line up once for every word to replace, so I keep count in X. Once it hits five, the EXA goes to another TEST MRD loop, because now, when it's false, XA is done and needs to be killed as quickly as possible. We could do that from the original loop but the ADDI and TEST would delay the KILL. The single NOOP saves a cycle by making sure M goes empty just when this EXA is about to test (instead of when it's about to jump back to LOOP2.

541/41/7. Note that this M testing is quite fiddly, and by doing stuff such as unrolling the XB loop or changing other things by a single cycle you get slightly different results. I couldn't get it under 541 though.

So, my best results are 541 cycles and 22 size. Who can do better?

You didn't look at any other files while you were in there, did you?



The first vote. This update isn't quite done yet, though.



[x10x10x]: true

Yes. Definitely lovely software and not a hacker.



Anyway, someone's at the door.



Hey.
I have some things for you.
First of, we got the next zine, hot off the press.

Ghast hands me the next issue of his zine.

Someone helped me out.
I had a balance at the copy shop, but someone hacked it.
Speaking of which, I brought you something else.

Ghast holds up what looks like a handheld game console.

You remember the Redshift?
I know people say this thing was underpowered and just a gimmick...
But it has its charms.
This is the developer version, so you could make something with it, if you wanted.
The game studio I worked for never took it back after I quit.
I'll be happy knowing it's going to a good home.
Gotta deliver more zines now.
I'll catch you later.


Dude, a Redshift dev kit? I loved that thing as a kid!



In the next parts, we have a whole new zine to explore, as well as a game console! But first, let's see what Ember has to say about the next assignment.

You're going to join in on a hacker battle?
But you never say anything in the chat room...


Carbon dioxide fucked around with this message at 11:04 on Apr 9, 2022

GuavaMoment
Aug 13, 2006

YouTube dude
This level is pretty straightforward without any neat tricks.

code:
XA:
GRAB 300
MARK LOOP
COPY F X
REPL REPL
COPY F M
JUMP LOOP
MARK REPL
LINK 800
LINK 799
GRAB 212
MARK LOOP2
TEST F = X
FJMP LOOP2
SEEK -1
COPY M F

XB:
LINK 800
GRAB 200
LINK 800
Find a keyword, make a copy to go change that keyword, repeat. 18 lines, saving 3 over yours. Sorry about naming my copies REPL all the time.

code:
XA:
GRAB 300
COPY F M
LINK 800
COPY F M
COPY F M
LINK 799
COPY F M
COPY F M
COPY F M
COPY F M
COPY F M
COPY F M
COPY F X
WIPE
COPY X M
KILL

XB:
NOOP
LINK 800
GRAB 200
LINK 800

XC:
LINK 800
LINK 799
GRAB 212
MARK LOOP
COPY M X
MARK LOOP2
TEST F = X
FJMP LOOP2
SEEK -1
COPY M F
SEEK -999
JUMP LOOP
Loop unrolling and transmitting data as fast as possible. The search takes the most time and it's hard to speed up. 540/32/7 a one cycle improvement (which I think comes from knowing how many keywords there are and wiping before transmitting the final keyword?)

berryjon
May 30, 2011

I have an invasion to go to.
I Might have
I just Lurk


Also, I can see why moving something to the outbox would be a viable option as it's not the inbox, or spam, so people might not think to look for an email they've received there. Especially ones delivered while they were out doing deliveries of their own.

megane
Jun 20, 2008



berryjon posted:

Also, I can see why moving something to the outbox would be a viable option as it's not the inbox, or spam, so people might not think to look for an email they've received there. Especially ones delivered while they were out doing deliveries of their own.

The joke is that this is the first tutorial mission network, so in addition to messing with Ghast's email you have to complete the now-hilariously-trivial tutorial task.

Junpei
Oct 4, 2015
Probation
Can't post for 11 years!
I might have and EXAs speak louder

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


This LP inspired me to go get the zines and the other Zachtronics stuff printed at Lulu. Gonna play this game finally when they arrive.

Adbot
ADBOT LOVES YOU

Carbon dioxide
Oct 9, 2012

Part 17 - Baby's first hacker battle


=== Trash World Inbox ===

GuavaMoment posted:

This level is pretty straightforward without any neat tricks.
code:
XA:
GRAB 300
MARK LOOP
COPY F X
REPL REPL
COPY F M
JUMP LOOP
MARK REPL
LINK 800
LINK 799
GRAB 212
MARK LOOP2
TEST F = X
FJMP LOOP2
SEEK -1
COPY M F

XB:
LINK 800
GRAB 200
LINK 800
Find a keyword, make a copy to go change that keyword, repeat. 18 lines, saving 3 over yours. Sorry about naming my copies REPL all the time.
555/18/3. The REPL'd EXA goes find the word and gets the replacement from M. That also means the original EXA knows when the previous one is done.

GuavaMoment posted:

code:
XA:
GRAB 300
COPY F M
LINK 800
COPY F M
COPY F M
LINK 799
COPY F M
COPY F M
COPY F M
COPY F M
COPY F M
COPY F M
COPY F X
WIPE
COPY X M
KILL

XB:
NOOP
LINK 800
GRAB 200
LINK 800

XC:
LINK 800
LINK 799
GRAB 212
MARK LOOP
COPY M X
MARK LOOP2
TEST F = X
FJMP LOOP2
SEEK -1
COPY M F
SEEK -999
JUMP LOOP
Loop unrolling and transmitting data as fast as possible. The search takes the most time and it's hard to speed up. 540/32/7 a one cycle improvement (which I think comes from knowing how many keywords there are and wiping before transmitting the final keyword?)
And another small but neat improvement. I don't think this code needs much explanation.

While I was looking at your solution I had a very cheesy idea, though. I checked the slowest running test (only one of the test cases actually needed all 540 cycles). It is so slow because almost all the keywords are near the end of the file. Can we speed up just this one test case? That could be done by starting further ahead in the file and looping back to the beginning. I did a quick attempt but this made other tests much, much slower. Maybe there's a way to optimize that, I don't know. So, other idea, how about a reverse search? That's somewhat slow because you have to SEEK back a bit each loop - but can't hurt to try.

My first attempt failed. It uses the same XA and XB from Guavanaut, but with a changed XC:
code:
LINK 800
LINK 799
GRAB 212
MARK LOOP
COPY M X
SEEK 999
SEEK -1
MARK LOOP2
TEST F = X
SEEK -2
FJMP LOOP2
SEEK 1
COPY M F
SEEK -999
JUMP LOOP
For every new search value, it SEEKs to EOF, and then one back to the last word and starts testing. Every LOOP2 iteration it has to SEEK -2 to move back one word from where it last searched. That means it has to step forward one position when it finds the word but that's fine.

You see the problem here? SEEK -2; SEEK 1 causes an off-by-one if the keyword is the very first word in the file. New attempt with a workaround:
code:
LINK 800
LINK 799
GRAB 212
MARK LOOP
COPY M X
TEST F = X
TJMP FIRST
SEEK 999
SEEK -1
MARK LOOP2
TEST F = X
SEEK -2
FJMP LOOP2
SEEK 1
COPY M F
SEEK -999
JUMP LOOP

MARK FIRST
SEEK -1
COPY M F
JUMP LOOP
Now it checks the first position first. If that's the one, it replaces it in the FIRST 'subroutine' and jumps right back to search for the next. In that case it doesn't need to jump back to the beginning of the file because we never have to replace the same position twice. If the first word doesn't need replacing it SEEKs to the end and searches backwards.

504/41/7. Perhaps this could be optimized more but I'm quite happy I found this at all.

megane posted:

The joke is that this is the first tutorial mission network, so in addition to messing with Ghast's email you have to complete the now-hilariously-trivial tutorial task.
:doh: Of course! It's the exact same as the very first tutorial assignment. I guess that's how Ember found us a way in, but if we don't solve the tutorial, Ghast might get suspicious.


=== Hacker battle at KGOG-TV ===

You didn't look at any other files while you were in there, did you?



Everyone voted for "I might have". Very honest.

Oops!
Maybe don't tell him you accidentally saw some of his private files.
No reason to upset him.
He needs to focus on the next issue of the zine anyway.


Yeah, ok.

Speaking of the next zine, I got it right here.

OST: Apartment

Nice cover:




I'm assuming the physical version came with actual 3D glasses.



It's completely filled with cool content again. I don't think Ghast's the best hacker out there - but he's a drat good editor. Also, I can't believe it's been only one month since the first issue. Feels like three months at least.

Anyway, we'll get to the hacking writeups when we need them. As for the other content, I'll be sharing that bit by bit again just to not overwhelm you with text. Let's start with Ghast's letter.



I'd love to stay curious, but I'm just trying to survive here, man.

Let's see what's going on online.





Well, mutex is challenging us to a "hacker battle". Can't say no to that.

Hacker battles have a different kind of leader board. They show who you've beaten and when. Apparently this is stored in the Steam cloud separately from your regular save file because it has a date corresponding to my initial playthrough (and I'm not using that save). Other than mutex8021, it shows my steam friends. I removed those from the pic for privacy reasons.

You're going to join in on a hacker battle?
But you never say anything in the chat room...




Two votes for "I just lurk", one for "EXAs speak louder".

I just lurk these days.

I guess the only thing that really matters is your ability.



As it should be.

It's a nice ideal.


Oh hey cool, Ember is all 3D with these glasses Ghast gave me.

Right, time to find out what this is all about.


OST: Getting Started

This is a completely different mode of the EXODUS simulator. There's some things to go through. Let's start with some info from the zine.





The left side looks very familiar. Some files and the EXA programming environment.



On the right we see some new things. The dark/blue host is our opponent's. We can never go there, but they can link from it to the network we're hacking.

At the bottom we see there's 100 test runs, like normal. New is the win count: this is increased by one for every test run where you get more points than your opponent. The goal is to get a win count that's greater than half of the number of test runs.

Next, the number of cycles is limited now - that's how long the program will run for during any test run before the points are added up. The size count is limited as always.

To the far right you see the points you and your opponent have and the storage limit. The storage limit is the number of EXAs you're allowed to create. It's 3 here - that means I can't have more than 3 EXAs to start with, and if my code REPLs to more than 3, the REPL instruction will pause that EXA until there's space again. As for how to get points, we need to read the instructions:

To win this battle you must make your movies play for longer than your opponent's. A movie will play when that movie's file is the only movie file sitting in a channel host.
- Gain one point every cycle for each of your movies that is playing (files 210 and 211).
- Lose one point every cycle for a movie that isn't yours (files 230, 231, 265) is held by an EXA you control or is sitting in your host.
- Lose one point every time one of your EXAs executes a KILL instruction.
Note that you may only battle your Steam friends after beating the NPC opponent. To view the list of possible opponents, click the "SELECT OPPONENT" button above.
For more information see "Hacker Battle Domination" in the second issue of the zine.


Alright, so I can use KILL instructions to kill the opponent's EXAs but it will cost me points.

Hey game, stop breaking the fourth wall. I'll get to Steam friends battles in a bit. Let's start with mutex.

If we don't do anything, mutex uses two EXAs to move 230 and 231 to the channels and they get 2 points per cycle (since file 265 doesn't give anyone points).



In case you're wondering, 265 is a movie of a bug moving next to a plant, 230 looks like some military device shooting missiles, and 231 is a mechanical monster walking throuch a city.

To prevent mutex from getting points, I could either kill their EXAs or grab their files. Since holding files that aren't mine costs points, and I can't beat mutex's first EXA to grabbing a file, I'm better off just killing them. I have to execute the KILL instructions while I'm in the same host as the opponent's EXAs. There can't be any other EXAs of mine there, because as the language reference guide in zine 1 says, for some reason KILL prioritizes your own EXAs.

So, let's start with this simple solution.



XA kills both of mutex's EXAs (giving me negative 2 points), then moves one of my files into an empty channel host. XB waits for the kills, then moves the other file over. As soon as both EXAs drop the files they start playing, and I get 2 points per cycle.



My movies are some swaying grass with figures in the background, and a Japanese looking scene with snow falling.

So you might think it's a good idea to get rid of file 265 too, or dump another movie in that host to cause a conflict. Turns out it isn't. Grabbing 265 or another opponent's file costs points. And the instructions for this battle are actually incorrect. You don't lose any points for having someone else's movie playing, the only thing that happens is that the opponent GAINS points if they have their movies playing. Since 265 is nobody's, no-one is gaining any points for it and I should just leave it alone.

This solution nets me 188 points for every test run, while mutex gets zero. By the way, the other test runs are almost identical. All that changes it the number in the third entry of each file, and the locations of mutex's and my host change around (while keeping the link IDs the same). I suspect that last change swaps who moves first within a cycle, but it doesn't matter for us.



I win every single test run, getting an S+ score on this battle.



This first hacker battle is very easy. It's more of a tutorial for a new mode than anything else.

As for the multiplayer mode, you're not battling at the same time. What happens is that after I beat the NPC, my solution becomes available for Steam friends to battle against. That means their goal becomes to specifically beat my solution. If you noticed - the battle field is basically symmetric, the only difference is some file IDs but the game can just replace them when simulating someone being "the other side".

I tried to pit my solution against someone else's and I lost every test run. It's hard to say what they did exactly - you can't see the opponent's code. But they use three EXAs, one of which tries to kill mine and another which constantly replicates, moving the repls into the channel hosts.

The way to handle this is to build another solution to specifically fight theirs. For instance, I changed XA to kill just once (it gets killed by an opponent in the same cycle) and then sent in a second EXA that aggressively kills both of the remaining opponent's EXAs.
I managed to secure a win, 76 out of 100 test runs. Good enough for a B. I can't really tell you why 'only' 76 runs, the interaction of two sets of separately programmed EXAs gets very unpredictable.

Either way, by doing so my new solution is uploaded to this specific Steam friend, so if they decide to ever reopen the game and scroll to this particular assignment, they can see I beat them and they can try to make a new solution to beat mine. I don't have much experience with this because the few Steam friends I have that also own this game apparently were happy to play through it just once, but I can imagine this way you could get a fun back-and-forth on these hacker battle levels.

Back to the plot.

You're off to a good start.
I knew you were good at what you did.
Even after you forgot, you picked it right back up.
That's why I contacted you.




The first vote for today.

For the second vote, Ember has a question about the Redshift handheld Ghast handed us.

Why do you think Ghast gave you this?





[Ghast] let's just say I'm pretty confident.
[x10x10x] cool im gonna hacker battle moss too


Oh... um, I don't think I ever introduced myself properly to you all, readers. Not that you would've believed it was really me, seeing how much I had to relearn at the start. I'm the hacker known as Moss. Nice to make your acquaintance. You've seen my name in the chat's user list, I just lurk all the time.

Carbon dioxide fucked around with this message at 11:57 on Mar 12, 2022

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply