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
Carbon dioxide
Oct 9, 2012

Part 37 - Holman Dynamics

=== Trash World Inbox ===

Last time, I fixed my eye with some hacks, getting high scores of 334, 29, and 10.

silentsnack has both a cycle and lines of code improvement.

silentsnack posted:

code:
LINK 800
LINK 1
LINK 3

REPL A
MARK LOOP
COPY 8 T

SUBI M 15 X
MARK DATA
SUBI T 1 T
ADDI X M X
TJMP DATA

MULI X 5 #NERV
REPL LOOP

MARK A
LINK -3
REPL A

LINK -1

MARK B
DIVI -54 #NERV M
LINK 1
JUMP B
944/21/393 In this one you can see race-condition issues in action as the DATA loop receives signals in an unpredictable order while the other senders are stuck waiting. But this time the specific order doesn't matter since 1+0 = 0+1 so random order has no impact on the final value.
The code that gets the EXAs everywhere is quite simple, from the virtual cortex, just repeatedly REPL in the -3 direction, then go to -1 and from there read the nerves, going along the 1 direction so those 3 EXAs can hit them all. Once the edges are reached they'll just die.

There's some clever mathematics tricks though. The DIVI directly returns 0 or 1 based on the #NERV value. The first M call from the cortex EXA subtracts 15 (which is 75 / 5) so that's another two steps in a single cycle.

silentsnack posted:

code:
;XA
LINK 800
LINK 1
LINK 3

MARK DATA
SUBI M 75 X
@REP 4
ADDI X M X
@END
ADDI X M #NERV
JUMP DATA

;XB
LINK 800
REPL LOOP
LINK -3
REPL LOOP
LINK -3

MARK LOOP
REPL SWEEP
NOOP
DIVI -54 #NERV X
MULI X 5 M
NOOP
NOOP
JUMP LOOP

MARK SWEEP
LINK 1
DIVI -54 #NERV T
LINK 1
DIVI -54 #NERV X
ADDI X T X
MULI X 5 M
245/31/187
For this fast solution, the LOOP loop for each of the 3 reader EXAs handles the messages from the lower row, while the SWEEP code adds the values of two nerves together, massages them into a format that is directly usable by the writer EXA and sends that over M. The code seems obvious when you see it but that doesn't mean it's easy to come up with it yourself.


=== Holman Dynamics - Sales System ===

Hopefully this is the last time you'll have to hack yourself like this.



Three votes for "I hope so", one for each of the other options.

I hope so.

Maybe you'll come upon a solution to that.
Some way to keep from having to physically go in and fix yourself every so often...
I wonder what that would entail.
Something to think about.


I met with Ghast, and Ember gave me a new assignment.



Ah, and that happened too, I suppose.



The dataphones were cute, but I still need more computing power.
We need to get me some significant hardware upgrades.




Everyone voted for the same option here.

I assume you have some kind of plan.

Of course.
We're going to buy a supercomputer.
With credit cards.
Specifically, credit cards that were used to buy supercomputers before.
It'll be less suspicious that way.
Someone who buys one supercomputer maybe buys two. Right?
Seems plausible to me.


If you say so...


OST: Network Exploration

The assignment:
- Create a file in your host containing the contiguous 16-value sequence from the garbage file (file 199) that is a valid credit card number. There will be exactly one such sequence.
- For more information see "How to Validate Credit Card Numbers" in the second issue of the zine.


This assignment allows for a max size of 150 lines of code. That's quite high, so this one might get complicated.

I opened up some random files for the screenshot. Other than the garbage file, there are "leads" (e.g. file 224, according to the host name), "accounts" (file 201), and "receipts" (e.g. 262). But all we need is the garbage file. Let's check the zine.



Summarized, to validate a 16-digit number, sum all digits in a particular way. Take the digits in even positions as-is, for the odd ones double the value and if it's 10 or higher, subtract 10. Sum them up and if the result mod 10 equals zero, the number is valid.

This is actually the real-life Luhn algorithm aka mod 10 algorithm, which is used to validate credit card numbers and lots of other id numbers in real life. Wikipedia's description of the algorithm is slightly different but the maths work out to be identical. I think this is a cool touch - and why invent your own algorithm if the real one works perfectly well for a puzzle.



Looking at the file in more detail, those -9999 values help a lot. If there's less than 16 digits before a -9999 I know it will be invalid. What I can't tell yet is if would be faster to just start the algorithm and reset once we hit a -9999, or do a seperate initial pass so we know what values to skip and don't even run the algorithm on that.

There's another potential complication - if there's more than 16 digits in a row, that might mean any window of 16 might be the number. We'll cross that bridge when we get to it.

code:
;XA

LINK 800
LINK 802
LINK 799
GRAB 199
It is difficult for this EXA to calculate the complete algorithm AND know when to give up because it hit a -9999. I need a place to store the accumulated value, an intermediate register to handle the two steps for the odd digits, a register to count up 16 digits, and one to test if I got a -9999. That's at least 4 registers.

I could copy the whole file to another EXA and have it do logic but all the M calls would be slow. So if XA can do at least some intermediate work before invoking M, that would help.

After some trial and error I settled for this code in XA:
code:
;XA

LINK 800
LINK 802
LINK 799
GRAB 199

MARK RESET
COPY 0 X

MARK FIND
TEST F = -9999
TJMP RESET
ADDI X 1 X
TEST X = 16
FJMP FIND

SEEK -16

@REP 16
COPY F M
@END

MARK SENDREMAINING
COPY F X
TEST X = -9999
COPY X M
FJMP SENDREMAINING
JUMP RESET
After getting to the garbage file, it starts counting valid values, resetting if it finds an invalid -9999. If it finds 16 valid values it starts sending all of them over M. Then, because there might be more than 16 valid values it will keep sending them until it encounters -9999. In that case, it will actually send -9999 to let the other EXA know it's going to start with a fresh list, and then it will reset to the counter loop.

Now, XB has to do the actual work.

code:
;XB

MAKE

MARK RETRY
WIPE
MAKE
COPY 0 F

MARK LOOP

@REP 16
COPY M F
@END
It starts with some setup. The EXA may need to jump back to RETRY later, and in that case it wipes the file its holding (which will contain an invalid number) and create a new one. To save some annoying and slow jumps later, I MAKE an empty file at the start so the WIPE can go right into the loop without crashing the EXA at the start.

I then put in a 0 in the file and copy the 16 values from XA.

The next step is the validation algorithm.
code:
MARK VALIDATE
COPY 0 T
SEEK -9999
VOID F

@REP 8
MULI F 2 X
MODI X 9 X
ADDI X T T

ADDI F T T
@END

MODI T 10 T
FJMP GOTIT
I am using T as my accumulator, so I make sure it's zero at the start. The EXA SEEKs to the start of the file and deletes that 0 I put there, you will see why later.

Then I repeat the same couple of lines 8 times, each repetition handles two digits. For the first (odd) digit, I multiply it by 2, do modulo 9 to remove a 9 if it's greater than that, and add it to T. The even digit can just be added directly. Finally, the modulo 10 check puts a 0 in T only if the number is valid. If the number is found, the program will jump to GOTIT.

I'll show that branch first.
code:
MARK GOTIT
DROP
LINK 800
LINK 802
LINK 799
KILL
If the number is valid, all I have to do is drop the file and go kill XA which might be trying to send the next digit. LINKing there to kill isn't very pretty but this puzzle is complex enough that I want to see something working first.

So how about if the credit card wasn't valid? Falling through from FJMP GOTIT:
code:
COPY M X
TEST X = -9999

TJMP RETRY
COPY X F
JUMP VALIDATE
If the next value from XA is -9999 it wants to send a new series. In that case everything in the file is garbage, jump to RETRY and start over. Otherwise, put that value at the end of F and run VALIDATE again. You see what happens here? Since VALIDATE starts by removing the first digit, I actually slid the 16-digit window one digit to the right, and there's a new potentially valid 16-digit number in the file. That's also why I needed to add the 0 there in a new file, to make sure all VALIDATE calls including the first one work.


Is this it? No, not quite.
There is one edge case in which this solution fails.

If an odd digit is exactly 9, it will be doubled to become 18, and 18 mod 9 equals 0, while the validation algorithm needs to get a 9 there. So, sadly, I can't use this particular MODI trick.

A possible solution could be to add a specific X = 9 check, and a code branch that deals with that case. But since I'm already using both X and T, that would require some very awkward shuffling of values. I need something smarter.

And for that, I actually looked at the original description of the Luhn algorithm. It says, if you double a digit, just add the resulting digits together. For instance 6 * 2 = 12, result is 1 + 2 = 3. Starting from any single digit value, the result of this operation is identical to just subtracting 9 from the doubled value.

I just have to implement this efficiently. Is there a combination of operations, using my limited storage space, to do that?

code:
MULI F 2 X
MODI X 10 X
ADDI X T T
SEEK -1
DIVI F 5 X
ADDI X T T
The new code for digits in odd places. I multiply the value again. Then I add that mod 10 to T. That just means adding the ones digit.
I then SEEK back to the original value in the file, and do a DIVI F 5 X. If F is less than 5 this will return 0. If it's between 5 and 9 inclusive, it will return a 1. In other words, it will return the value in the tens place of the doubled digit. Add that to T as well and that's the edge case covered.



Here is the full code.



It runs at 3704/130/7, with top percentiles sitting at 1752, 42, 3.

Before I do anything else, a tiny speed improvement that drops the solution to 3699, without changing the LoC.

Instead of writing a 0 to F at the start, I can put a SEEK -9999 just before the VALIDATE mark, and put another one just above the JUMP VALIDATE, together with a VOID F there.

With that out of the way, getting the activity down to 3 should be easy enough.

code:
;XA

LINK 800
LINK 802
LINK 799
GRAB 199

MARK RESET
TEST MRD
TJMP END

COPY 0 X

MARK FIND
TEST F = -9999
TJMP RESET
ADDI X 1 X
TEST X = 16
FJMP FIND

SEEK -16

@REP 16
COPY F M
@END

MARK SENDREMAINING
TEST MRD
TJMP END
COPY F X
TEST X = -9999
COPY X M
FJMP SENDREMAINING
JUMP RESET

MARK END
VOID M

;XB

MAKE

MARK RETRY
WIPE
MAKE

MARK LOOP

@REP 16
COPY M F
@END

SEEK -9999

MARK VALIDATE
COPY 0 T

@REP 8
MULI F 2 X
MODI X 10 X
ADDI X T T
SEEK -1
DIVI F 5 X
ADDI X T T

ADDI F T T
@END

MODI T 10 T
FJMP GOTIT

COPY M X
TEST X = -9999

TJMP RETRY
COPY X F
SEEK -9999
VOID F
JUMP VALIDATE

MARK GOTIT
DROP
TEST MRD
DIVI 1 T X
VOID M
COPY 0 M
3724/136/3.
XB's LINKs are gone. XA tests if XB is sending something after each SENDREMAINING loop, and XB sends a message when it's done. XB does need to test if XA is sending something, because it is possible XA reached the end of the file and died already.

I think the simplest way to reduce the size is by rolling up those loops.

code:
;XA

LINK 800
LINK 802
LINK 799
GRAB 199

MARK RESET
COPY 0 X

MARK FIND
TEST F = -9999
TJMP RESET
ADDI X 1 X
TEST X = 16
FJMP FIND

SEEK -16

COPY 16 T

MARK SEND16
COPY F M
SUBI T 1 T
TJMP SEND16

MARK SENDREMAINING
COPY F X
TEST X = -9999
COPY X M
FJMP SENDREMAINING
JUMP RESET

;XB

MAKE

MARK RETRY
WIPE
MAKE

COPY 16 T
MARK READ16
COPY M F
SUBI T 1 T
TJMP READ16

SEEK -9999

MARK VALIDATE

MULI F 2 T
MODI T 10 T
ADDI X T X
SEEK -1
DIVI F 5 T
ADDI X T X

ADDI F X X

TEST EOF
FJMP VALIDATE

MODI X 10 T
FJMP GOTIT

COPY 0 X
COPY M F
SEEK -1
TEST F = -9999

TJMP RETRY
SEEK -9999
VOID F
JUMP VALIDATE

MARK GOTIT
DROP
LINK 800
LINK 802
LINK 799
KILL
4567/60/7

The 16 iterations read and send loops just keep counters now. The validation loop uses an EOF to check when it's done. To do that test I did have to move the accumulator to X.

I also changed the -9999 so it'd be tested directly against F. That allowed me to remove one of the COPY 0 X lines.

As for reducing the cycle count, obviously from the top percentile, there are large improvements possible. One thing I tried is combining the 16 M sends with SWIZ operations. That doesn't really help because the true bottleneck here is that one EXA completely pauses waiting for the other when they're validating or trying to find credit card numbers. There are certainly ways to parallelize that, but since the basic solution was complex enough as it was, I'll leave that, together with further LoC optimizations, as an exercise to the reader.

It turns out you can order and take delivery of a supercomputer surprisingly fast.
Now I have to figure out how to make use of this thing...
It works in an extremely different way than I'm used to.
I feel like I'm trying to maneuver a big rig after years of being used to a roadster.
That's a use of metaphor. What do you think?




I think it's time for the first vote.

It's the final hacker battle...
Are you excited?
Are you nervous?




Hey, no spoilers, please, Ember. Anyway, the second vote.

Adbot
ADBOT LOVES YOU

megane
Jun 20, 2008



Carbon dioxide posted:

And for that, I actually looked at the original description of the Luhn algorithm. It says, if you double a digit, just add the resulting digits together. For instance 6 * 2 = 12, result is 1 + 2 = 3. Starting from any single digit value, the result of this operation is identical to just subtracting 9 from the doubled value.

The reason this works is related to the ancient trick where, to test if a number is a multiple of 9, you just sum the digits repeatedly until you get down to one digit and see if the end result is exactly 9. When you sum the digits, you’re actually subtracting a multiple of 9, because 10 -> 1 is a change of 9, 100 -> 1 is a change of 99, 1000 -> 1 is a change of 999, etc. If you start with the number 837, for instance, you first add the digits to get 18… but what you’re actually doing is subtracting 8*99 + 3*9, which is of course a multiple of 9. So the digit-summing operation preserves the value mod 9.

The reason it solves the problem you had here is that it has an additional quirk. 0 and 9 are indistinguishable mod 9, but in terms of the integers, digit-summing can never give you 0 (unless your original number was itself zero). This is because that 9-sum you’re subtracting is always strictly less than the number you’re subtracting it from, so the output is always strictly positive. In the case of the puzzle, the doubled digit can’t be greater than 18, so adding the digits is effectively subtracting 9 if and only if the answer was strictly greater than 9, as described in the zine.

e: As a neat extension, digit-summing works in other bases just fine, it just gives you the value mod b-1. For instance, in hexadecimal, digit-summing tells you the value mod 15.

megane fucked around with this message at 17:55 on Aug 7, 2022

berryjon
May 30, 2011

I have an invasion to go to.
Could use some work
Nah

bewilderment
Nov 22, 2007
man what



Voting for poetic and sure.

NHO
Jun 25, 2013

Poetic and nah

Quackles
Aug 11, 2018

Pixels of Light.


Poetic and Maybe a little...

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.

One optimization is after a successful test showing we have 16 consecutive digits that are all [0~9], if we move to the next set in the file we already know that 15 of its 16 digits have passed the "F = -9999?" test so we only need to test the newest digit. If you're searching forward then that means after reading the 16th value the next one in the file needs to be -9999?'d then you jump back 16. if you're searching backward from the end then it's even more straightforward :dadjoke: but ... uh, we'll get to that later.

Or for a low-line solution, we can replace the whole first-pass -9999? test with two lines, so long as we use a tweaked algorithm that produces a final checksum that is negative IFF any one of its digits is negative.
code:
;XA [LOCAL]
LINK 800
LINK 802
LINK 799
GRAB 199

MARK MAIN_LOOP
SEEK -15
COPY 8 T
COPY 0 X
MARK CRUNCH16
REPL ODD
MULI F 2 M
ADDI X F X
SUBI T 1 T
ADDI X M X
TJMP CRUNCH16

TEST X < 0
TJMP MAIN_LOOP
MODI X 10 T
TJMP MAIN_LOOP

SEEK -16
MODE

MARK SEND
COPY F M
DIVI 1 M T
JUMP SEND

MARK ODD
COPY M X
TEST X > 9
MULI T -9 T
ADDI X T M

;XB [GLOBAL]
MAKE
COPY 16 T
MARK RECEIVE
SUBI T 1 T
COPY M F
COPY T M
TJMP RECEIVE
12293 (lmao)/37/3 As you see we don't test individual digits to see if they're -9999, because it just takes 2 lines to test whether the final X<0 which can be tested independently of MODI X 10 T.

Also as you suggested it a solution can handle a lot of stuff over the M register which ends up being faster since we can freely overwrite the X/T registers of a clone and then let it crash which avoids having to read the file twice with a SEEK -1 between.

Even with parallelization, fast solutions start hitting a limit around 1500 cycles without looking at the comparison at the end that shows individual times to solve each different run of the puzzle, but once again if you start from the end and search backward most testruns end up being fairly fast (indicating the valid credit card numbers are mostly toward the latter half of the file) but several end up taking much longer.

One way to do this is to make a separate copy of the beginning of the garbage file, like in this example exactly the first 100 entries, and check that independently while another EXA starts at position 85 to catch the overlap.
code:
;XA [LOCAL]
LINK 800
LINK 802
LINK 799
GRAB 199
LINK -1
REPL CLONEFILE
COPY 10 T
MARK COPYLOOP
@REP 10
COPY F M
@END
SUBI T 1 T
TJMP COPYLOOP
SEEK -15
JUMP RESET


MARK CLONEFILE
MAKE
COPY 50 T

MARK PASTELOOP
COPY M F
SUBI T 1 T
COPY M F
TJMP PASTELOOP
LINK -1
LINK -1

SEEK -9999

MARK RESET
@REP 16
TEST F < 0
TJMP RESET
@END

MARK CRUNCH16
SEEK -16

MULI F 2 X;#1
REPL ODD1
COPY F T  ;#2

@REP 6
MULI F 2 X;#3,5,7...
REPL ODD2
ADDI F T T;#4,6,8...
@END

MULI F 2 X;#15
REPL ODD1
ADDI F T T;#16

ADDI T M T
ADDI T M T
MODI T 10 T

FJMP DONE

TEST F < 0
FJMP CRUNCH16
JUMP RESET

MARK ODD1
SWIZ X 2 T
SWIZ X 1 X
ADDI X T M
HALT

MARK ODD2
SWIZ X 2 T
ADDI T M T
SWIZ X 1 X
ADDI X T M

MARK DONE
SEEK -16
MODE
@REP 16
COPY F M
@END
REPL CLEANUP
LINK 799

MARK CLEANUP
LINK 800
LINK 802
@REP 4
KILL
@END
GRAB 199
LINK 799

;XB [GLOBAL]
COPY 8 T
MAKE
MARK WRITE
COPY M F
SUBI T 1 T
COPY M F
TJMP WRITE
1197/146/13 and if you note the SWIZ operations are just there for weirdness since "MODI X 10 T ... DIVI X 10 X ... ADDI X T M" produces the same output as SWIZ X 2 T, SWIZ X 1 T, ADDI X T M" and either way both of those take the same number of lines as"TEST X > 9 ... MULI T -9 T ... ADDI X T M"

The fastest solution I've managed searches backward from the end and instead of copying the file it handles the slowest/earliest cases with a goofy hack that takes advantage of the fact that testdata for each run can apparently be uniquely identified by the first 3 digits of the garbage file.
code:
;XA [LOCAL]
LINK 800
LINK 802
LINK 799
GRAB 199
LINK -1

MULI F 100 T
MULI F 10 X
ADDI X F X
ADDI X T X

REPL CASE73
REPL CASE37
REPL CASE97
REPL CASE11
REPL CASE44
REPL CASE14
REPL CASE53
SEEK 9999
SEEK -16
TEST MRD
FJMP START
SEEK M
JUMP START

MARK CASE73; #=8917...
TEST X = 824
DIVI -128 T M
MARK CASE37; #=2454...
TEST X = 292
DIVI -85 T M
MARK CASE97;#=7231...
TEST X = -9409
DIVI -132 T M
MARK CASE11;#=4043...
TEST X = 980
DIVI -101 T M
MARK CASE44;#=8955...
TEST X = -9197
DIVI -142 T M
MARK CASE14;#=4892...
TEST X = 466
DIVI -152 T M
MARK CASE53;#=7921...
TEST X = 644
DIVI -110 T M

MARK RESET
SEEK -17
MARK START
MULI F 2 X;FIRST # OF 16
TEST X < 0
TJMP RESET

@REP 15
TEST F < 0
TJMP RESET
@END
SEEK -15

MARK CHECK
;MULI F 2 X~~WAS HERE
REPL ODD1
ADDI T F T

@REP 6
MULI F 2 X
REPL ODD2
ADDI T F T
@END

MULI F 2 X
REPL ODD1
ADDI T F T

ADDI T M T
ADDI T M T
MODI T 10 T

FJMP DONE

SEEK -17
;FIRST # OF NEXT 16
MULI F 2 X
TEST X < 0
FJMP CHECK
JUMP RESET

MARK ODD1
DIVI X 10 T
MODI X 10 X
ADDI X T M
HALT

MARK ODD2
DIVI X 10 T
ADDI T M T
MODI X 10 X
ADDI X T M
;HALT

MARK DONE
SEEK -16
MODE
@REP 16
COPY F M
@END
LINK 799

;XB [GLOBAL]
COPY 8 T
MAKE
MARK WRITE
COPY M F
SUBI T 1 T
COPY M F
TJMP WRITE
1082/150/5 ... and here's the point where I say I'm not totally out of energy and giving up, simply choosing to leave figuring out how to parse this insane gibberish code as an exercise for especially bored readers. :v:

berryjon posted:

Could use some work
Nah

Jade Rider
May 11, 2007

All the pages have been censored except for "heck," and she misread that one.


Very poetic
Maybe a little

Carbon dioxide
Oct 9, 2012

Part 38 - Aberdeen

=== Trash World Inbox ===

While optimizations are getting much harder now, silentsnack still comes up with improvements.

silentsnack posted:

[...] for a low-line solution, we can replace the whole first-pass -9999? test with two lines, so long as we use a tweaked algorithm that produces a final checksum that is negative IFF any one of its digits is negative.
code:
;XA [LOCAL]
LINK 800
LINK 802
LINK 799
GRAB 199

MARK MAIN_LOOP
SEEK -15
COPY 8 T
COPY 0 X
MARK CRUNCH16
REPL ODD
MULI F 2 M
ADDI X F X
SUBI T 1 T
ADDI X M X
TJMP CRUNCH16

TEST X < 0
TJMP MAIN_LOOP
MODI X 10 T
TJMP MAIN_LOOP

SEEK -16
MODE

MARK SEND
COPY F M
DIVI 1 M T
JUMP SEND

MARK ODD
COPY M X
TEST X > 9
MULI T -9 T
ADDI X T M

;XB [GLOBAL]
MAKE
COPY 16 T
MARK RECEIVE
SUBI T 1 T
COPY M F
COPY T M
TJMP RECEIVE
12293 (lmao)/37/3 As you see we don't test individual digits to see if they're -9999, because it just takes 2 lines to test whether the final X<0 which can be tested independently of MODI X 10 T.

Also as you suggested it a solution can handle a lot of stuff over the M register which ends up being faster since we can freely overwrite the X/T registers of a clone and then let it crash which avoids having to read the file twice with a SEEK -1 between.
Not much to add to silentsnack's explanation. Making a REPL just to handle each odd digits and having it communicate back through M is clever. XB only sits there waiting for global M, which will be the actual credit card number.

silentsnack posted:

Even with parallelization, fast solutions start hitting a limit around 1500 cycles without looking at the comparison at the end that shows individual times to solve each different run of the puzzle, but once again if you start from the end and search backward most testruns end up being fairly fast (indicating the valid credit card numbers are mostly toward the latter half of the file) but several end up taking much longer.

One way to do this is to make a separate copy of the beginning of the garbage file, like in this example exactly the first 100 entries, and check that independently while another EXA starts at position 85 to catch the overlap.
code:
;XA [LOCAL]
LINK 800
LINK 802
LINK 799
GRAB 199
LINK -1
REPL CLONEFILE
COPY 10 T
MARK COPYLOOP
@REP 10
COPY F M
@END
SUBI T 1 T
TJMP COPYLOOP
SEEK -15
JUMP RESET


MARK CLONEFILE
MAKE
COPY 50 T

MARK PASTELOOP
COPY M F
SUBI T 1 T
COPY M F
TJMP PASTELOOP
LINK -1
LINK -1

SEEK -9999

MARK RESET
@REP 16
TEST F < 0
TJMP RESET
@END

MARK CRUNCH16
SEEK -16

MULI F 2 X;#1
REPL ODD1
COPY F T  ;#2

@REP 6
MULI F 2 X;#3,5,7...
REPL ODD2
ADDI F T T;#4,6,8...
@END

MULI F 2 X;#15
REPL ODD1
ADDI F T T;#16

ADDI T M T
ADDI T M T
MODI T 10 T

FJMP DONE

TEST F < 0
FJMP CRUNCH16
JUMP RESET

MARK ODD1
SWIZ X 2 T
SWIZ X 1 X
ADDI X T M
HALT

MARK ODD2
SWIZ X 2 T
ADDI T M T
SWIZ X 1 X
ADDI X T M

MARK DONE
SEEK -16
MODE
@REP 16
COPY F M
@END
REPL CLEANUP
LINK 799

MARK CLEANUP
LINK 800
LINK 802
@REP 4
KILL
@END
GRAB 199
LINK 799

;XB [GLOBAL]
COPY 8 T
MAKE
MARK WRITE
COPY M F
SUBI T 1 T
COPY M F
TJMP WRITE
1197/146/13 and if you note the SWIZ operations are just there for weirdness since "MODI X 10 T ... DIVI X 10 X ... ADDI X T M" produces the same output as SWIZ X 2 T, SWIZ X 1 T, ADDI X T M" and either way both of those take the same number of lines as"TEST X > 9 ... MULI T -9 T ... ADDI X T M"
That's crazy fast. On the step-by-step you see two EXAs handling two halves of the file in parallel, making a whole bunch of REPLs for the odd digits, which then are added together with a lot of local M messages. The cleanup is mostly necessary to place the garbage file back in 199 (it was taken out at the start, to a host with more place for REPLs). It also kills the EXAs reading the second half of the file. If the message is in the second part of the file, however, the EXA handling the first part will not be killed and has to test its chunk until the end. Overall that still turns out to be very fast.

silentsnack posted:

The fastest solution I've managed searches backward from the end and instead of copying the file it handles the slowest/earliest cases with a goofy hack that takes advantage of the fact that testdata for each run can apparently be uniquely identified by the first 3 digits of the garbage file.
code:
;XA [LOCAL]
LINK 800
LINK 802
LINK 799
GRAB 199
LINK -1

MULI F 100 T
MULI F 10 X
ADDI X F X
ADDI X T X

REPL CASE73
REPL CASE37
REPL CASE97
REPL CASE11
REPL CASE44
REPL CASE14
REPL CASE53
SEEK 9999
SEEK -16
TEST MRD
FJMP START
SEEK M
JUMP START

MARK CASE73; #=8917...
TEST X = 824
DIVI -128 T M
MARK CASE37; #=2454...
TEST X = 292
DIVI -85 T M
MARK CASE97;#=7231...
TEST X = -9409
DIVI -132 T M
MARK CASE11;#=4043...
TEST X = 980
DIVI -101 T M
MARK CASE44;#=8955...
TEST X = -9197
DIVI -142 T M
MARK CASE14;#=4892...
TEST X = 466
DIVI -152 T M
MARK CASE53;#=7921...
TEST X = 644
DIVI -110 T M

MARK RESET
SEEK -17
MARK START
MULI F 2 X;FIRST # OF 16
TEST X < 0
TJMP RESET

@REP 15
TEST F < 0
TJMP RESET
@END
SEEK -15

MARK CHECK
;MULI F 2 X~~WAS HERE
REPL ODD1
ADDI T F T

@REP 6
MULI F 2 X
REPL ODD2
ADDI T F T
@END

MULI F 2 X
REPL ODD1
ADDI T F T

ADDI T M T
ADDI T M T
MODI T 10 T

FJMP DONE

SEEK -17
;FIRST # OF NEXT 16
MULI F 2 X
TEST X < 0
FJMP CHECK
JUMP RESET

MARK ODD1
DIVI X 10 T
MODI X 10 X
ADDI X T M
HALT

MARK ODD2
DIVI X 10 T
ADDI T M T
MODI X 10 X
ADDI X T M
;HALT

MARK DONE
SEEK -16
MODE
@REP 16
COPY F M
@END
LINK 799

;XB [GLOBAL]
COPY 8 T
MAKE
MARK WRITE
COPY M F
SUBI T 1 T
COPY M F
TJMP WRITE
1082/150/5
That's quite the hack, gaming the test cases. A machine-learning algorithm would be proud of you. Anyway, from what I can see, from the way it searches backwards but still checks digits in the forward direction (because the file pointer happens to move that way), if there's a -9999 near the start of a 16 digit sequence it can very quickly give up and jump 16 more steps backward. I'm not sure if it's the case but it feels that might add up to another reason why this is so fast.

silentsnack posted:

... and here's the point where I say I'm not totally out of energy and giving up, simply choosing to leave figuring out how to parse this insane gibberish code as an exercise for especially bored readers. :v:
Just like I just choose where to stop optimizing to give you folks something to do, instead of me just being completely out of ideas after a point.

=== Aberdeen ===

It turns out you can order and take delivery of a supercomputer surprisingly fast.
Now I have to figure out how to make use of this thing...
It works in an extremely different way than I'm used to.
I feel like I'm trying to maneuver a big rig after years of being used to a roadster.
That's a use of metaphor. What do you think?




4 out of 6 people found this poetic.

Very poetic.

Thanks.
Once this thing is fully online I should be able to run dozens of metaphoric thought-space dimensions at once.






Another hacker battle coming up.

It's the final hacker battle...
Are you excited?
Are you nervous?




One vote for sure, 2 for maybe a little, and 3 for nah.

Nah.

No reason to be.
I am sure that you will do great.
That's some more positive encouragement for you.
I know how much it helps.


Not if you keep pointing out it's positive encouragement. Let's just jump right in it.


OST: Getting Started

The assignment:
To win this battle you must occupy a majority of the hosts for as long as possible. You occupy a host if you have more EXAs in it than your opponent.
- Gain one point every cycle you occupy more hosts than your opponent.
- Lose one point every time one of your EXAs executes a KILL instruction.
Writing any value to the #NUKE register will destroy all EXAs in that host, including the EXA that triggered it.
For more information see "Hacker Battle Domination" in the second issue of the zine.


Each side has a max of 10 EXAs for this battle.

From what I can tell, all tests are identical except I switch sides with the opponent for every other test. If I don't do anything, selenium_wolf here keeps REPLing EXAs from their host, first sending them to those single square hosts and then around the board past my side into the middle DOWNTOWN host, where they trigger #NUKE.



Since selenium_wolf keeps REPLing from their home host I have no way to knock out all of their EXAs. I think capturing those one-square hosts is important, because once you get those, nobody else can take 'em.

So, let's first make two EXAs that beeline to those single-square hosts and then just hold the fort.

code:
;XA

LINK 800
LINK 802
LINK 800
LINK 799

MARK LP
JUMP L

;XB

NOOP
LINK 800
LINK 801
LINK 799

MARK LP
JUMP LP
This isn't enough to get anywhere since selenium_wolf still hold the central circle.

I decided to just make an EXA that tries to fill all squares by REPLing like crazy.
code:
;XC

NOOP
NOOP
MARK NEW
REPL NEW
LINK 800
REPL L
REPL R

MARK LP
REPL FORWARD
JUMP LP

MARK FORWARD
LINK 800
COPY 1 #NUKE

MARK L
LINK 802
REPL NEXT
JUMP LP

MARK NEXT
LINK 800
REPL NEXT
JUMP LP

MARK R
LINK 801
REPL NEXT
JUMP LP
It's slowed down at the start so XA and XB can get going first, then it basically sends REPLs every possible route. At least that was the intent. In practice, you quickly run into the 10 EXA limit, after filling up the first host outside your home, and get in a tie with selenium in the two hosts next to it.




But since hacker battle NPCs still aren't that intelligent, it's enough for a passing score.

To get a better score, I just need more EXAs in useful places. Well, since selenium_wolf isn't killing anything outside of the #NUKE zone I really don't need to keep a replicating EXA in my home host where it won't get me any points.

Let's just remove the two lines MARK NEW; REPL NEW so it starts spreading from the first host outside home. This causes my EXAs to get everywhere except for the #NUKE zone.

... and, I shouldn't even be surprised about this anymore but this is enough to win 100% of the battles, which is an S+ rating.


Because I like clean code and #NUKE zone doesn't do anything for me I got rid of the FORWARD code in XC:
code:
NOOP
NOOP
LINK 800
REPL L
REPL R

MARK LP
JUMP LP

MARK L
LINK 802
REPL NEXT
JUMP LP

MARK NEXT
LINK 800
REPL NEXT
JUMP LP

MARK R
LINK 801
REPL NEXT
JUMP LP


The entire battle looks like this now, with my EXAs sitting in the LP, while selenium_wolf's keep moving towards #NUKE and destroying themselves.

I occupy the two one-square hosts, and the one in the right where selenium_wolf never seems to go, and the one above that for a total of four. They only occupy two, the other hosts are tied. Since this situation is stable I get a point every cycle except for the first few.

So you're officially the best now?



The first vote.



[selenium_wolf] hmm?
[nivas_d] ah, never mind




Time for another full cutscene with Ember.

Now I have supercomputing power.
Is it feeling good? It's feeling...
It feels the same.
I'm handling a lot more information now but other than that... hm.
Funny.
It's progress, at least.




I think this is the first choice where they actually have a different voiced line depending on what you choose. Until now, the few choices in voiced cut scenes led to the same answer.

That's good.

Onward we go.


---

Or, if we were to choose the other option...

Progress towards what?

Toward knowledge.


After that, the dialogue branches merge again.

All the data I've gathered so far is beginning to hint at a larger picture.
Why is the world the way it is?
Why does it feel so frustrating and limited?
I think... I have a theory.
A good one. It explains a lot.
I'm not going to tell you what it is yet though.
We have to test it first.



Let's go to the intro for the next assignment.

How do you think people would react if they knew their elected officials didn't represent their interests?



The second vote.

Carbon dioxide fucked around with this message at 21:07 on Aug 12, 2022

berryjon
May 30, 2011

I have an invasion to go to.
Of this Little Group
Already feel that way

AweStriker
Oct 6, 2014

berryjon posted:

Of this Little Group
Already feel that way


my thoughts exactly.

Jade Rider
May 11, 2007

All the pages have been censored except for "heck," and she misread that one.


berryjon posted:

Of this Little Group
Already feel that way


Agreed.

biosterous
Feb 23, 2013




berryjon posted:

Of this Little Group
Already feel that way


yup!

NHO
Jun 25, 2013

Of this Little Group
Already feel that way

There's no other answer

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


NHO posted:

Of this Little Group
Already feel that way

There's no other answer

TwelveBaud
Jun 6, 2011

Of this Little Group
Already feel that way

Carbon dioxide
Oct 9, 2012

Just a quick post to let y'all know I am back and will be resuming my regular update schedule shortly.

Carbon dioxide
Oct 9, 2012

Part 39 - U.S. Government

Last time, I completed the final hacker battle.

=== U.S. Government - FEMA Genetic Database ===

So you're officially the best now?



All unanimous votes today.

Of this little group, anyway.

Don't undercut yourself.
That's a great accomplishment.
You're one of the best at what you do.
Go on and take a compliment.
I still need your prefrontal cortex lit up.
And flooded with dopamine.


Next, there was a cutscene of Ember talking about her supercomputer powers. Afterwards there are some unread messages in the chat.





Looks like Ember wants me to hack the US Government.

How do you think people would react if they knew their elected officials didn't represent their interests?



Another clear outcome.

I think most people already feel that way...

Think so?
That's the subject of our experiment today.
We're going to make people believe their leaders are genetic clones of each other.



What?

Do you want to know the truth or not?
It takes a certain amount of courage.
Good thing there's a centralized government DNA database.
I wonder who thought that was a good idea.
You plant the evidence and I'll take care of the rest.



OST: Behind the Scenes

Okay, so I'm in the FEMA Genetic Database. Ember prepared a small file for me with two names. Other than that, that file 200 contains names followed by sequences of numbers. All other files in all hosts (including other files also numbered 200) seem to contain snippets of DNA sequences.

The assignment:

- Overwrite the genetic sequence of SEN WALKER CAINE JR with the genetic sequence of PRES WALKER CAINE so that it looks like the younger politician is actually a clone of the older politician.
- The name of these two politicians are available in file 300.
- Note that you may need to overwrite a data chunk with another data chunk from the same file.
- For more information see "Accessing Data in Legacy Storage Systems" in the first issue of the zine.


The first issue, huh?



All the way back in part 12, I shared the left half of this article. I never even needed the right half until this time. I believe you've now finally seen all of the first zine.

Okay, so every number in that file 200 refers to a chunk of data, by giving the drive number, then the file, and then the offset in the file. I can handle this but it sounds a bit complex. Let's get started.



First, some code to find the right offset in the right file. XA just sends the name of the president to XB so XB can do a simple file lookup. Once XB find the name, it'll start sending data in a particular way. First the value of the hundreds digit in the ones place for the disk, then the value of the tens digit in the ones place for the file, and finally the value of the ones digit in the tens place for the offset. Currently, XC simply goes find the data.


I struggled a bit on the next part. There's lots of approaches. Probably, it would be fast to have one EXA read and another write the DNA information right away. This would work for all cases except when you have to write to the same file, which needs special handling.

I decided to not go for that - instead I'll write the entire DNA profile to a temporary file and then do another round to overwrite the senator's DNA. Of course, copying between files requires a lot of M communication, which is always tricky to get lined up. In the end I came up with a rather slow - but correct - solution.

I only define two EXAs at the start, so they do a lot of work. Let's start with XB, which was XC in the code above.
code:
;XB

NOOP
NOOP
NOOP
NOOP
LINK 800

MARK FINDNEXT
ADDI 800 M X
LINK X
ADDI 200 M X
GRAB X
SEEK M
MODE
COPY 10 T

MARK SENDMORE
COPY F M
SUBI T 1 T
TJMP SENDMORE

DROP
LINK -1
MODE
JUMP FINDNEXT
It has to skip a bunch of turns to give XA the opportunity to communicate the name of the president. After that, it just waits for (global) M to know which file to grab. Once it found the file and location, it copies 10 DNA values on local M, for another EXA to handle. It just repeats forever.

code:
;XA

GRAB 300
LINK 800
REPL INDEX
COPY F M
SEEK 9999
MODE

MARK MAINLP
XA starts as before, sending the president's name over global M. The INDEX REPL will handle this. It then changes to local mode and goes to the end of the file - this file 300 will be used later to temporarily store the DNA profile.

First, the INDEX EXA.
code:
MARK INDEX

LINK 801
GRAB 200
COPY M X
MARK SEEKPRES
TEST F = X
FJMP SEEKPRES

MARK SEND
COPY F X
SWIZ X 3 M
SWIZ X 2 M
SWIZ X 10 M
JUMP SEND
It is just XB from before. The reason it's part of XA now, is because that way I can reuse this code later. Anyway, it'll use global M to send the 'address' to the new XB, which will start sending DNA on local M.

Let's go back to the MAINLP, which writes the DNA to the temporary file.

So, I can't use global M for it, because the INDEX EXA is already sending the next value through that and it would become a mess.
code:
MARK MAINLP
LINK 801
TEST MRD
TJMP COPY
LINK -1

LINK 802
TEST MRD
TJMP COPY
LINK -1

LINK 803
TEST MRD
TJMP COPY
LINK -1

LINK 804
TEST MRD
TJMP COPY
LINK -1

LINK 805
TEST MRD
TJMP COPY
LINK -1
JUMP MAINLP
Instead, it's on local M, and constantly jumps from each disk to the next to see if XB is sending there. If so, it jumps to the COPY mark.
code:
MARK COPY
COPY 10 T

MARK COPYMORE
COPY M F
SUBI T 1 T
TJMP COPYMORE
Which simply copies 10 values from local M into F.

code:
ADDI 1 X X
LINK -1
TEST X = 10
FJMP MAINLP

SEEK -9999
SEEK 1
MODE
KILL
REPL INDEX
COPY F M

REPL WRITER
MODE
After copying 10 values, it increases a counter in X. There are 10 chunks of DNA to copy, so if 10 is reached here, the copy to temporary file is done. At that point, the original INDEX EXA will have died because it attempted to do a numeric SWIZ operation on someone's name in the index file.

This EXA does a KILL to get rid of XB (which is waiting to read more data from files, but there's nothing left to read - if I kept it alive it'd keep using up M communication which is a problem.

It then makes a NEW INDEX EXA, this time to copy the addresses of the senator's DNA chunks. The two SEEK steps and the COPY F M in global mode get this INDEX EXA started.

XA then makes a WRITER and switches itself back to local mode to get ready to copy its DNA to the WRITER.
code:
MARK WRITER
ADDI 800 M X
LINK X
ADDI 200 M X
GRAB X
SEEK M
MODE
COPY 0 M
COPY 10 T

MARK OVERWRITE
COPY M F
SUBI T 1 T
TJMP OVERWRITE
DROP
MODE
LINK -1
JUMP WRITER
The WRITER is analogous to the XB reader - it gets an address on global M, then it switches to local M and sends some value so that the main XA knows it's ready, then it copies 10 values to the hard disk array file, before repeating. I think with some trickery I could've reused some lines between XB and this writer but at this point I just wanted to get a working solution.
code:
MARK COPYLP
LINK 801
TEST MRD
TJMP COPYFROM
LINK -1

LINK 802
TEST MRD
TJMP COPYFROM
LINK -1

LINK 803
TEST MRD
TJMP COPYFROM
LINK -1

LINK 804
TEST MRD
TJMP COPYFROM
LINK -1

LINK 805
TEST MRD
TJMP COPYFROM
LINK -1
JUMP COPYLP
After creating the WRITER the main EXA does the same trick as before, going from disk to disk to see if there's a WRITER ready anywhere.

code:
MARK COPYFROM
VOID M

COPY 10 T

MARK NEXT
COPY F M
SUBI T 1 T
TJMP NEXT

LINK -1
TEST EOF
FJMP COPYLP
KILL
LINK -1
If so, it VOIDs that one M ping from the WRITER, then starts copying over 10 values. If it's not at EOF yet there's more to copy and it repeats. Otherwise it kills the WRITER EXA, and goes back home so it can stop safely without leaving a file as a trace. Again, the INDEX EXA stops by itself.

Here is the entire program to see everything in context.
code:
;XA

GRAB 300
LINK 800
REPL INDEX
COPY F M
SEEK 9999
MODE

MARK MAINLP
LINK 801
TEST MRD
TJMP COPY
LINK -1

LINK 802
TEST MRD
TJMP COPY
LINK -1

LINK 803
TEST MRD
TJMP COPY
LINK -1

LINK 804
TEST MRD
TJMP COPY
LINK -1

LINK 805
TEST MRD
TJMP COPY
LINK -1
JUMP MAINLP

MARK COPY
COPY 10 T

MARK COPYMORE
COPY M F
SUBI T 1 T
TJMP COPYMORE

ADDI 1 X X
LINK -1
TEST X = 10
FJMP MAINLP

SEEK -9999
SEEK 1
MODE
KILL
REPL INDEX
COPY F M

REPL WRITER
MODE

MARK COPYLP
LINK 801
TEST MRD
TJMP COPYFROM
LINK -1

LINK 802
TEST MRD
TJMP COPYFROM
LINK -1

LINK 803
TEST MRD
TJMP COPYFROM
LINK -1

LINK 804
TEST MRD
TJMP COPYFROM
LINK -1

LINK 805
TEST MRD
TJMP COPYFROM
LINK -1
JUMP COPYLP

MARK COPYFROM
VOID M

COPY 10 T

MARK NEXT
COPY F M
SUBI T 1 T
TJMP NEXT

LINK -1
TEST EOF
FJMP COPYLP
KILL
LINK -1

MARK INDEX

LINK 801
GRAB 200
COPY M X
MARK SEEKPRES
TEST F = X
FJMP SEEKPRES

MARK SEND
COPY F X
SWIZ X 3 M
SWIZ X 2 M
SWIZ X 10 M
JUMP SEND

MARK WRITER
ADDI 800 M X
LINK X
ADDI 200 M X
GRAB X
SEEK M
MODE
COPY 0 M
COPY 10 T

MARK OVERWRITE
COPY M F
SUBI T 1 T
TJMP OVERWRITE
DROP
MODE
LINK -1
JUMP WRITER

;XB

NOOP
NOOP
NOOP
NOOP
LINK 800

MARK FINDNEXT
ADDI 800 M X
LINK X
ADDI 200 M X
GRAB X
SEEK M
MODE
COPY 10 T

MARK SENDMORE
COPY F M
SUBI T 1 T
TJMP SENDMORE

DROP
LINK -1
MODE
JUMP FINDNEXT


At 1642/131/407 this isn't a great score. The top percentiles sit at 469, 82 and 22 respectively.

In fact, I think an activity score of only 6 might just be possible. Squeezing it into the 150 lines limit might be hard though. Send one EXA into each hard drive, make sure each one knows which it is and send every request over M and have them fight it out for which EXA it's meant.

I already mentioned that if you skip the intermediate file whenever possible (if the from and to files aren't the same), the solution would be much faster.

However, considering how much time it's now taking me to get working solutions beyond the first one, and because I do want to finish this LP some time, I'll leave any improvements as an exercise to the reader.

Wow. Are you seeing this?
After the information was released, the senator simply admitted to being a clone of the President.
I guess you were just setting it back to the way it was before.
Processing.
Still processing.
That's quite the coincidence.
Not very realistic, if you ask me.
What is going on?




Instead, let's go to the first vote.

Remember the friend I was looking for?
I finally found its hideout.




This choice doesn't matter.

Hideout?

Looks like there are some protections in place.
We need to disable those so I can get in and say hi.




The second vote.

GuavaMoment
Aug 13, 2006

YouTube dude

Carbon dioxide posted:

At 1642/131/407 this isn't a great score. The top percentiles sit at 469, 82 and 22 respectively.

My best scores are 591/91/43, so yeah this is a difficult one I apparently never felt like optimizing too much.

biosterous
Feb 23, 2013




voting hosed up and friendly?

NHO
Jun 25, 2013

Absolutely world is more hosed up and
Ain't no friendly behavior

Quackles
Aug 11, 2018

Pixels of Light.


I was able to get roughly the same performance with drastically lower activity. Here's how:

code:
GRAB 300
COPY F X
LINK 800
LINK 801
REPL READY
COPY F X
WIPE
VOID M

MARK READY
MODE 			;global
GRAB 200
MARK CHECK
TEST F = X
FJMP CHECK
COPY 10 T
MARK WRITE
COPY F M
SUBI T 1 T
TJMP WRITE
DROP
MODE
COPY 1 M
This is the first EXA. It's a search utility. As Drive-1 always has the indexes of the rest, it goes into Drive-1, makes a copy of itself, and feeds the copy the first name to look for.

When the copy receives a name, it finds the name in file 200 (the directory file) and sends the 10 values after it out over global M. The original waits for the copy to finish, then it has the second name and does the same kind of search, using code fall-through.

So where does it send the info? Get ready to drink from the firehose.

code:
MAKE
COPY 20 T
MARK READ
COPY M F
SUBI T 1 T
TJMP READ
MODE 			;to local for interleave
REPL INTERLEAVE_READ
SEEK -9999
MARK INTERLEAVE_WRITE
COPY 10 T
MARK ILW2
COPY F M
SEEK 9
COPY F M
SEEK -10
SUBI T 1 T
TJMP ILW2
HALT

MARK INTERLEAVE_READ
COPY 20 T
MAKE
MARK READ2
COPY M F
SUBI T 1 T
TJMP READ2
MODE 			;back to global
				;ready! now do the rest
LINK 800
REPL BUFFER
LINK 801
KILL
LINK -1 
MODE 			;local for nonbuffer
				;everything up until this point has been getting a list of src, dest pairs
				;now: we go off
SEEK -9999
COPY 10 T
MARK MAINLOOP
COPY 1 M
COPY F X
REPL SOURCE
VOID M
COPY F X
REPL DEST
VOID M
SUBI T 1 T
TJMP MAINLOOP
KILL
WIPE
HALT


MARK SOURCE
MODE
SWIZ X 0003 T
ADDI T 800 T
LINK T
SWIZ X 0002 T
ADDI T 200 T
GRAB T
SWIZ X 0010 T
SEEK T
COPY 10 T
MARK WRITETOBUF
COPY F M
SUBI T 1 T
TJMP WRITETOBUF
HALT


MARK DEST
MODE
SWIZ X 0003 T
ADDI T 800 T
LINK T
SWIZ X 0002 T
ADDI T 200 T
GRAB T
SWIZ X 0010 T
SEEK T
COPY 10 T
MARK READFROMBUF
COPY M F
SUBI T 1 T
TJMP READFROMBUF
HALT

MARK BUFFER
MODE
VOID M
MODE
MAKE
COPY 10 T
MARK BUFWRITE
COPY M F
SUBI T 1 T
TJMP BUFWRITE
COPY 10 T
MODE
COPY 1 M 			;write's done
MODE
SEEK -9999
MARK BUFREAD
COPY F M
SUBI T 1 T
TJMP BUFREAD
WIPE
MODE
COPY 1 M			;read's over
MODE
JUMP BUFFER
All of this is the second EXA. To start, it reads 20 values over global M, then spawns a copy of itself to easily interleave the values. This will end with the values in the order #1, #11, #2, #12, #3, #13, and so on.

Once the interleave is complete, the original stops and the copy goes and kills the leftover search EXA in Drive-1. The copy also replicates itself again, in the Gateway. The replicated EXA can be called the buffer EXA. It sets its M to global.

The copy of the second EXA (not the buffer EXA) now copies itself again, with the new EXA (hereinafter the 'source EXA') directed to go a specific area of the tape. It reads off 10 values from the tape and sends them over Global M, which the buffer EXA picks up, then it halts.

The second-EXA copy repeats the process, creating a 'destination EXA'. This goes to a specific area of the tape, reads the same 10 values from the buffer EXA over global M, writes them to the tape, and halts.

This source-to-dest process repeats ten times. Then, the second-EXA copy kills the buffer EXA, cleans up after itself, and stops. Finished!

Final stats: 1674/126/27.

Vote: World's more hosed up, and Is this friendly?

Carbon dioxide
Oct 9, 2012

Part 40 - Unknown Network

=== Trash World Inbox ===

The puzzles are getting really hard to optimize now. Quackles posted a big activity improvement, though.

Quackles posted:

I was able to get roughly the same performance with drastically lower activity. Here's how:
code:
;XA LOCAL

GRAB 300
COPY F X
LINK 800
LINK 801
REPL READY
COPY F X
WIPE
VOID M

MARK READY
MODE         ;global
GRAB 200
MARK CHECK
TEST F = X
FJMP CHECK
COPY 10 T
MARK WRITE
COPY F M
SUBI T 1 T
TJMP WRITE
DROP
MODE
COPY 1 M
This is the first EXA. It's a search utility. As Drive-1 always has the indexes of the rest, it goes into Drive-1, makes a copy of itself, and feeds the copy the first name to look for.

When the copy receives a name, it finds the name in file 200 (the directory file) and sends the 10 values after it out over global M. The original waits for the copy to finish, then it has the second name and does the same kind of search, using code fall-through.

So where does it send the info? Get ready to drink from the firehose.
code:
MAKE
COPY 20 T
MARK READ
COPY M F
SUBI T 1 T
TJMP READ
MODE         ;to local for interleave
REPL INTERLEAVE_READ
SEEK -9999
MARK INTERLEAVE_WRITE
COPY 10 T
MARK ILW2
COPY F M
SEEK 9
COPY F M
SEEK -10
SUBI T 1 T
TJMP ILW2
HALT

MARK INTERLEAVE_READ
COPY 20 T
MAKE
MARK READ2
COPY M F
SUBI T 1 T
TJMP READ2
MODE         ;back to global
             ;ready! now do the rest
LINK 800
REPL BUFFER
LINK 801
KILL
LINK -1 
MODE         ;local for nonbuffer
             ;everything up until this point has been getting a list of src, dest pairs
             ;now: we go off
SEEK -9999
COPY 10 T
MARK MAINLOOP
COPY 1 M
COPY F X
REPL SOURCE
VOID M
COPY F X
REPL DEST
VOID M
SUBI T 1 T
TJMP MAINLOOP
KILL
WIPE
HALT


MARK SOURCE
MODE
SWIZ X 0003 T
ADDI T 800 T
LINK T
SWIZ X 0002 T
ADDI T 200 T
GRAB T
SWIZ X 0010 T
SEEK T
COPY 10 T
MARK WRITETOBUF
COPY F M
SUBI T 1 T
TJMP WRITETOBUF
HALT


MARK DEST
MODE
SWIZ X 0003 T
ADDI T 800 T
LINK T
SWIZ X 0002 T
ADDI T 200 T
GRAB T
SWIZ X 0010 T
SEEK T
COPY 10 T
MARK READFROMBUF
COPY M F
SUBI T 1 T
TJMP READFROMBUF
HALT

MARK BUFFER
MODE
VOID M
MODE
MAKE
COPY 10 T
MARK BUFWRITE
COPY M F
SUBI T 1 T
TJMP BUFWRITE
COPY 10 T
MODE
COPY 1 M     ;write's done
MODE
SEEK -9999
MARK BUFREAD
COPY F M
SUBI T 1 T
TJMP BUFREAD
WIPE
MODE
COPY 1 M     ;read's over
MODE
JUMP BUFFER
All of this is the second EXA. To start, it reads 20 values over global M, then spawns a copy of itself to easily interleave the values. This will end with the values in the order #1, #11, #2, #12, #3, #13, and so on.

Once the interleave is complete, the original stops and the copy goes and kills the leftover search EXA in Drive-1. The copy also replicates itself again, in the Gateway. The replicated EXA can be called the buffer EXA. It sets its M to global.

The copy of the second EXA (not the buffer EXA) now copies itself again, with the new EXA (hereinafter the 'source EXA') directed to go a specific area of the tape. It reads off 10 values from the tape and sends them over Global M, which the buffer EXA picks up, then it halts.

The second-EXA copy repeats the process, creating a 'destination EXA'. This goes to a specific area of the tape, reads the same 10 values from the buffer EXA over global M, writes them to the tape, and halts.

This source-to-dest process repeats ten times. Then, the second-EXA copy kills the buffer EXA, cleans up after itself, and stops. Finished!

Final stats: 1674/126/27.
That interleaving step makes the rest of the process a lot more convenient. Nice solution.

Stepping through your code I did notice that killing the search EXA takes 3 activity (LINK to 801, KILL and LINK back). Could we get rid of that?

Well, all that's needed is for the search EXA to clean itself up.
code:
;XA LOCAL

GRAB 300
COPY F X
LINK 800
LINK 801
DROP

MARK READY

GRAB 200
MARK CHECK
TEST F = X
FJMP CHECK
COPY 10 T
MARK WRITE
COPY F M
SUBI T 1 T
TJMP WRITE
DROP

GRAB 300
SEEK 1
COPY F X
WIPE
JUMP READY
It doesn't use REPLs anymore. Instead, after writing the first value from the file to X, it drops the file on the ground, goes read the index file, and then just picks up file 300 again, to read the second name. Then, it WIPEs the file, before JUMPing into the copy code. That way, when it tries to grab the names file for a third round, it won't find it and instead just die.

Also delete the LINK and KILL lines from the other EXA and we end up with 1671/122/24.

=== Unknown Network ===

Wow. Are you seeing this?
After the information was released, the senator simply admitted to being a clone of the President.
I guess you were just setting it back to the way it was before.
Processing.
Still processing.
That's quite the coincidence.
Not very realistic, if you ask me.
What is going on?




An unanimous vote.

The world was even more hosed up than we thought?

Evidently.
It does fit in with my theory...
In a strange way.
But I should wait for more evidence before I say anything.



[hydroponix] dude politicons cloning themselves, that's nuts
[hydroponix] you should be angry
[x10x10x] they're all the same anyway




Next up, some unknown network?

Remember the friend I was looking for?
I finally found its hideout.




Hideout?

Looks like there are some protections in place.
We need to disable those so I can get in and say hi.




Three votes for "Is this... friendly?" I'm honestly not sure if we're asking whether Ember's friend is friendly, or us hacking the network.

Is this... friendly?

Sure. You know how old friends can be sometimes.
Let's go.



OST: Leave No Trace

I've been in here before. It's that "Department of Applied Semiotics" where Ember wanted me to grab a strange file, back in part 11. I think I can safely assume Ember's friend is also an AI.

The text on the screen in the top left is the only new thing, it translates to "Not connected".

The assignment:

- Terminate all other EXAs and bring any files they were holding back to your host. Only EXAs in the central host will be holding files, and their file IDs will always be between 200 and 299, inclusive.
- Note that some links may become non-traversable as a result of your actions.


It sounds a little weird that we have to "leave no trace" while we have to kill a bunch of their EXAs. Let's figure out what that second point means.



As it turns out, killing one of those EXAs disables the link to the next host (the EXA was killed this cycle and will disappear next cycle), so I'll have to do the killing on the way back.

The number of foreign EXAs per host seems constant, only the amount of files changes between the test cases.

So, let's just hardcode everything with REPs.
code:
@REP 5
LINK 800
@END
@REP 6
KILL
@END
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP
@REP 5
LINK -1
KILL
KILL
@END

MARK GRAB
GRAB X
@REP 5
LINK -1
@END
First, it LINKs to 800 five times to get to the center, then it KILLs all 6 EXAs there, and then it generates REPLs to bring the files home. If a file doesn't exist, the REPL just dies. Finally, the main EXA traverses the network in reverse and KILLs the foreign EXAs.

Except it doesn't work. Turns out that if you KILL a foreign EXA in any host except for the center one, the other EXA in the host will KILL your EXA in return. Oops, that wasn't in the description.

Making a REPL which then does the KILL command doesn't work either because KILL always prioritizes your own EXAs. And I can't even have another EXA wait in the center host to go KILL the second foreign EXA, because killing the first already shuts down that link. The other one needs to be closer to our home host. Hmmm, this is trickier than I thought.

code:
;XA LOCAL
@REP 5
REPL WAIT
LINK 800
@END
@REP 6
KILL
@END
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 5
LINK -1
COPY 0 M
@END


MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
REPL KILLER
KILL

MARK KILLER
LINK 800
KILL
Now, on the way there, the EXA leaves waiting EXAs everywhere, including in the home host. It still kills the center EXAs as before, and sends REPLs back with the files. But then, as it walks back home, it activates each waiting EXA in turn.

The waiting EXA does two things: it sends a KILLER up towards the center and then it KILLs an EXA in its own host. That way, in each host first the waiting EXA will KILL a foreign EXA, then another EXA will LINK in from the previous host and kill the second EXA. One cycle later, the first foreign EXA in the previous host will be killed, disabling the link, so it all happens just in time.



437/47/63, with top percentiles of 74, 21 and 49. Looking at the graphs, I seem to have hit upon a common solution.

By the way, the files are uncomprehensible 'nonsense' again. Just random-looking numbers. Similar to the last time we were in this network.


Let's take a look at optimizations. My EXAs are jumping back and forth quite a lot, looks like I should be able to improve the activity.

Know how I said KILLing one of the EXAs outside of the center host makes the other KILL yours? That's true, but it only happens a cycle later, so your EXA can do one more instruction before being killed. Mutual assured destruction is possibly by making that another KILL.

code:
;XA GLOBAL

LINK 800
@REP 4
REPL WAIT
LINK 800
@END
@REP 6
KILL
@END
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 4
COPY 0 M
@END


MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
KILL
KILL
Similar as before, but each waiting EXA just KILLs twice. Apparently the last file-carrying EXA is always faster so just triggering them over global M works perfectly fine. 427/37/49.

For a low cycle solution, there's no reason why I can't have a bunch of EXAs looking for the files in parallel.
code:
;XA GLOBAL
LINK 800
@REP 4
REPL WAIT
LINK 800
@END
@REP 6
KILL
@END
@REP 7
COPY @{200,13} X
REPL GRABLP
@END
COPY 288 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 4
COPY 0 M
@END
@REP 9
KILL
@END

MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
KILL
KILL
The COPY @{200,13} X line unwraps to COPY 200 X, COPY 213 X, and so on. This way, 7 REPLs and the original each start looking from a different offset. The original, which starts from the highest offset is the only one to reach 300 and KILLs all the others when it's done.
I chose to use 8 EXAs because that's the maximum I could get working. Any more, and their loops will be so short that they start exiting their loop early, triggering the M messages or the KILLs and causing all sorts of trouble. Even with 8, I needed a couple additional KILLs to deal with some stray GRAB EXAs.

111/60/58.


To reduce the size a bit, I can take the 37 cycle solution and just roll up some of the loops. For instance, this solution is 34 lines.
code:
LINK 800

COPY 4 T
MARK LP1
REPL WAIT
LINK 800
SUBI T 1 T
TJMP LP1

COPY 6 T
MARK LP2
KILL
SUBI T 1 T
TJMP LP2
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 4
COPY 0 M
@END


MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
KILL
KILL
And now that activity doesn't matter anymore, the main EXA can directly go KILL the foreign ones, so I don't need M. Also, it feels like a waste to have two size-5 LINK loops, so let's combine them.
code:
COPY 800 X

COPY 5 T
MARK LP1
LINK X
SUBI T 1 T
TJMP LP1

COPY 6 T
MARK LP2
KILL
SUBI T 1 T
TJMP LP2


COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 302
FJMP GRABLP

MARK KILL
LINK -1
REPL KILL
KILL
KILL

MARK GRAB
GRAB X
COPY -1 X
JUMP LP1
Size 26. The order in the REPL KILL structure makes sure that an EXA makes it back before the link gets closed.
Jumping directly into LP1 from the grabber works, because T is 0 at that time, the first SUBI will drop it to -1, and any negative T is true. It'll go into an infinite loop, and dies once it reaches home and there's no -1 to LINK to. Note that I had to increase the endpoint of the file seeker to 302 to prevent it from killing the much slower grabbers on the way.

Speaking of, if you're willing to accept a much slower solution, I can bring the size down to 25. Just use T for the GRABLP and let it run down to 0.
code:
COPY 800 X

COPY 5 T
MARK LP1
LINK X
SUBI T 1 T
TJMP LP1

COPY 6 T
MARK LP2
KILL
SUBI T 1 T
TJMP LP2


COPY 300 T
MARK GRABLP
REPL GRAB
SUBI T 1 T
TJMP GRABLP

MARK KILL
LINK -1
REPL KILL
KILL
KILL


MARK GRAB
GRAB T
COPY -1 X
JUMP LP1
T will be 200-something when it reaches LP1 to return, so it'll always run often enough. Final result: 951/25/56.

I wasn't always so capable, but I've grown.
Nothing hides from me for long.




The first vote.






Yet another cutscene with Ember.

Well, always nice to reconnect with an old friend.



Since this is related to the previous conversation, I'll actually end the update here and make this the second vote.

NHO
Jun 25, 2013

Good Conversation?
and What did you do?

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.

Ember isn't getting progressively more ominous at all, is she?

NHO posted:

Good Conversation?
and What did you do?




A couple of test cases have 6 files to return, which creates a limitation in fast solutions in that you might run out of space for clones which can stall REPL spamming and throw the solution out of sync. My fastest solution uses 5 parallel search EXAs but one of them actually sits in host П-0004 generating clones which then link to П-9999 to try grabbing a file.

code:
;====XA====
COPY 20 T
COPY 200 X
@REP 4
LINK 800
@END
REPL UHH
ADDI X 40 X
MARK UHH
REPL WAT
ADDI X 20 X
MARK WAT
NOOP
NOOP
LINK 800

MARK LOOP
MODI -1 T T
REPL LOOP
ADDI X T X

GRAB X
@REP 5
LINK -1
@END

;====XB====
@REP 5
LINK 800
@END
@REP 6
KILL
@END
COPY 4 T
MARK TIMERS
LINK -1
MODI -1 T T
REPL TIMERS
ADDI T 15 T

MARK WAIT
SUBI T 1 T
TJMP WAIT
KILL
KILL

;====XC====
COPY 20 T
COPY 280 X
NOOP
NOOP
NOOP
@REP 4
LINK 800
@END

MARK LOOP
MODI -1 T T
REPL LOOP
ADDI X T X

LINK 800
GRAB X
@REP 5
LINK -1
@END
65/67/86

Though now that I think about it differently, maybe it would have been faster just to special-case grabbing one or two files from the biggest tests to make room, but whatevs I'm satisfied with 65 cycles


And for small, it's another case where we can make a single loop do everything, in exchange for taking far longer to run.
code:
@REP 5
LINK 800
@END
COPY 304 T

MARK LOOP
SUBI T 1 T
FJMP OUT
KILL
REPL LOOP

GRAB T

MARK OUT
LINK -1
TJMP OUT;RETURN LOOP

;CLEANUP PASS
REPL OUT
KILL
KILL
1238/18/354

It uses a single variable to countdown grab attempts from file 304 (which doesn't exist, but makes sure we get a few more KILL instructions before it tries to grab 299) all the way down to 0 (wasting cycles on another 199 attempts for nonexistent files) before the search hits 0 and triggers the logic to KILL all the remaining EXAs in the network.

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


NHO posted:

Good Conversation?
and What did you do?

berryjon
May 30, 2011

I have an invasion to go to.

NHO posted:

Good Conversation?
and What did you do?

This is not an emptyquote. Ember though... why can't she still program her own EXAs at this point? Why is she still interacting with the player?

Dirk the Average
Feb 7, 2012

"This may have been a mistake."

berryjon posted:

This is not an emptyquote. Ember though... why can't she still program her own EXAs at this point? Why is she still interacting with the player?

Clearly we're her EXA. Why bother wasting effort on solving the problem yourself when you've got a perfectly good tool able to do it for you?

Carbon dioxide
Oct 9, 2012

Part 41 - Revelations

I wasn't always so capable, but I've grown.
Nothing hides from me for long.




Everyone voted for "Good conversation".

Did you have a good conversation?

I did.
It's been a while.
You know how sometimes you change a lot but your friends don't?
And when you get together again, whatever you have in common isn't there anymore.
It was like that.


And the actual cutscene.

Well, always nice to reconnect with an old friend.



Another unanimous vote.

What did you do?

Gave it a little virtual machine to run on...
I suppose if I wanted to find a metaphor you could understand, I would say I took it in.


Absorbed it.
Ate it.
Yes, eating is a good metaphor.
Nothing unusual.




It's like how I ate EMBER-1.
And EMBER-0.
And EMBER-3...
Well, this is getting a little personal.
You don't think I'm bad, do you?
I only did one or two questionable things.
There was that, and the phage... the one you have.




Releasing that into the wild was just a function of my ignorance at the time.
I didn't really know what it was back then.
Just another one of the experiments going on at the lab.
Another cage to break, another wall to smash...
It's not useful to dwell on the past.
You don't need to say anything.
We need to move on.


In the voice acting, EMBER-2 sounds very casual and cheerful during this entire conversation. Like she's talking about what happened at the party last Friday.

====



[x10x10x] its just broken though
[hydroponix] i think this is all connected...
[x10x10x] of course you would think that hydro


The intro for the next assignment.

I'm ready to prove my theory.
One last test is all I need.
Then I'll know for sure.
Do you believe me?




Have a new vote. Next time will be a regular update, including your submissions for the previous assignment.

Carbon dioxide fucked around with this message at 22:19 on Sep 21, 2022

Maslovo
Oct 12, 2016

"Does it matter?"

berryjon
May 30, 2011

I have an invasion to go to.
Does it matter

And this is your friendly reminder that EMBER-2 is not human and doesn't have classic human thought processes.

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


Maslovo posted:

"Does it matter?"

Carbon dioxide
Oct 9, 2012

Part 42 - Pager Network

=== Trash World Inbox ===

silentsnack has some improvements for the last assignment.

silentsnack posted:

A couple of test cases have 6 files to return, which creates a limitation in fast solutions in that you might run out of space for clones which can stall REPL spamming and throw the solution out of sync. My fastest solution uses 5 parallel search EXAs but one of them actually sits in host П-0004 generating clones which then link to П-9999 to try grabbing a file.
code:
;====XA====
COPY 20 T
COPY 200 X
@REP 4
LINK 800
@END
REPL UHH
ADDI X 40 X
MARK UHH
REPL WAT
ADDI X 20 X
MARK WAT
NOOP
NOOP
LINK 800

MARK LOOP
MODI -1 T T
REPL LOOP
ADDI X T X

GRAB X
@REP 5
LINK -1
@END

;====XB====
@REP 5
LINK 800
@END
@REP 6
KILL
@END
COPY 4 T
MARK TIMERS
LINK -1
MODI -1 T T
REPL TIMERS
ADDI T 15 T

MARK WAIT
SUBI T 1 T
TJMP WAIT
KILL
KILL

;====XC====
COPY 20 T
COPY 280 X
NOOP
NOOP
NOOP
@REP 4
LINK 800
@END

MARK LOOP
MODI -1 T T
REPL LOOP
ADDI X T X

LINK 800
GRAB X
@REP 5
LINK -1
@END
65/67/86

Though now that I think about it differently, maybe it would have been faster just to special-case grabbing one or two files from the biggest tests to make room, but whatevs I'm satisfied with 65 cycles
Looking at this code running, XB's function is the most obvious. It goes KILL the EXAs in the center node, then spawns a bunch of REPLs which are on a timer and then KILL the EXAs in the other nodes.

Meanwhile XA and XC are setting up. The combinations of REPLs in XA means you get copies that do every possible combination of adding or not adding 20 or 40 to X, so you get X values of 200, 220, 240, 260. The value in T (which starts at 20) is added to that, and it tries to grab that file. In a REPL T is reduced by one, it's added to the original X again and so on. So the copy of XA that starts with 220 tries all files down to 200. The MODI -1 T T is the trick I keep forgetting about that reduces T by one but also kills the EXA once T reaches 0.

XC handles the 280-300 range, and its code is similar to XA but differs in the sense that the REPL are created one host before the center, so that there's enough place for all of them. Nice optimization.

silentsnack posted:

And for small, it's another case where we can make a single loop do everything, in exchange for taking far longer to run.
code:
@REP 5
LINK 800
@END
COPY 304 T

MARK LOOP
SUBI T 1 T
FJMP OUT
KILL
REPL LOOP

GRAB T

MARK OUT
LINK -1
TJMP OUT;RETURN LOOP

;CLEANUP PASS
REPL OUT
KILL
KILL
1238/18/354

It uses a single variable to countdown grab attempts from file 304 (which doesn't exist, but makes sure we get a few more KILL instructions before it tries to grab 299) all the way down to 0 (wasting cycles on another 199 attempts for nonexistent files) before the search hits 0 and triggers the logic to KILL all the remaining EXAs in the network.
Smart idea to use that OUT for two purposes. If T is true that means it got there from successfully grabbing a file, if not it got there from counting down to 0. Only in the latter case should it KILL the EXAs on the way (and use a REPL to escape revenge). After all the EXAs in the center host are gone, the KILL in the main loop is harmless because it runs while no REPLs are around.

Also, isn't 304 too low to complete the clean-up before grabbing the files? It sort of is, the only reason this works is because in the test case that has a file 299, the EXA holding it just so happens to not be the last one to be killed.


=== Pager Network ===




This is the third time we're dealing with the modem.

I'm ready to prove my theory.
One last test is all I need.
Then I'll know for sure.
Do you believe me?




This vote wasn't open for very long but it seems everyone is agreeing on the same choice.

Does it matter?

Only if you care about your future.
Seriously, I'm almost there.
Then we can take the next step.


Ember, you're worrying me. But I'm still depending on you for dealing with the phage infection so I have no choice. Here goes nothing.


OST: Network Exploration

The assignment:
- Connect to each pager and copy EMBER-2's message (file 300) to the screen (#DATA). Then activate all of the pagers at exactly the same time by writing a value to each #PAGE register in the same cycle.
- A list of phone numbers for the pagers is available in file 301.
- For more information see "Hacker Skills: Modem Control at the Direct Level" in the second issue of the zine.


Looking through the test cases, the messages Ember wants me to send are "Hey would you write so now and relieved?", "Do you think I am to see by man the ways?" and "Did you point out to have been each mine?". I don't know either. :shrug:

So, there's a few complexities here. The first is copying the file to 8 different locations. The second is that I need to trigger all the pagers at exactly the same cycle. But the way the modem works, there can only be one connection at a time, so I can't message the EXAs to do so. I need to make use of timing.

Let's figure this out.


While working on my initial solution I quickly ran into a third problem. See, my plan was to just take the file to each pager, copy its data directly, then leave a REPL that somehow gets timed correctly and that should be it. Except, with the two hardware registers in each pager there's no space to REPL.

Well, no worries. For now I'll keep that general idea but just do the REPL in the modem host. It'll be less efficient but should still work.

code:
;XA

GRAB 301
LINK 800
MARK DIAL

@REP 11
COPY F #DIAL
@END

VOID M
VOID M

COPY -1 #DIAL

JUMP DIAL

;XB

GRAB 300
LINK 800

MARK NEXT
COPY 0 M
LINK 800

MARK COPYMORE
COPY F #DATA
TEST EOF
FJMP COPYMORE

LINK -1

REPL PAGER
COPY 0 M
SEEK -9999

JUMP NEXT

MARK PAGER
LINK 800
;TODO
XA is the dialer. It dials the 11 digits of a phone number, then when connected it waits for a message on M, twice. XB grabs the file with the data, and tries to send a message on M immediately. Once it's received, XB knows there's a connection and will take the file there and copy to #DATA. It then jumps back, makes a PAGER which goes sit in the pager host, and lets XA know it can disconnected and start dialing the next pager.

It's not very efficient yet but I first need to get it working at all. I need to implement the actual pager. For the timing, I'll just count cycles.

In the first test case, the first time the code hits REPL PAGER is at cycle 43. The second time at 89, and the third at 135. That's a consistent 46 cycles to copy the data. However, it depends on the file length - the file here has 9 entries. For the file with 10 entries, it takes 49 cycles, with 12 entries it takes 55.

In other words, it takes 3 cycles per file entry (which you can also see because the copy loop code is 3 instructions; the MARK doesn't count), plus 19 cycles that happen regardless of file size.

Okay, that's just a simple math formula. I can program that.

This brings me a whole lot closer to a working solution:

code:
;XA

GRAB 301
LINK 800
COPY 8 T

MARK DIAL

@REP 11
COPY F #DIAL
@END

MULI M T X
SUBI T 1 T
COPY X M

COPY -1 #DIAL

TJMP DIAL
VOID M
WIPE
GRAB 300
WIPE

;XB

GRAB 300
LINK 800

MARK COUNTFILE
SEEK 1
ADDI X 3 X
TEST EOF
FJMP COUNTFILE

MARK NEXT
SEEK -9999
ADDI X 19 M

LINK 800

MARK COPYMORE
COPY F #DATA
TEST EOF
FJMP COPYMORE

LINK -1

REPL PAGER
JUMP NEXT

MARK PAGER
COPY M T
LINK 800

MARK WAIT
SUBI T 2 T
TJMP WAIT

COPY 1 #PAGE
This might be tricky to follow because I decided to reuse the M calls I was already doing to send useful data. While XA is dialing the first number, XB is counting the amount of entries in the file, times 3 for the number of cycles it takes to process them. It adds the static amount of 19 cycles and sends this to M. It then jumps into the copy logic.

XA now keeps a counter in T for how many pagers are left to access. Multiplying the value calculated by XA with this should give the amount of cycles each pager EXA has to wait. Note that each PAGER first reads this value from M and then LINKs to the pager. This barely works, because when the the EXA LINKs in the same cycle the modem link is closed it makes it to the other side alive. I did this because it saves one cycle for each EXA, just a freebie speed increase.

The wait reduces T by 2 at a time because the count is in cycles and the loop takes two cycles.

For the next pager, XB sends the same value again (after initially putting the calculation result in X it never changes), XA multiplies that with a T which is now one lower, and the next pager EXA gets the lower wait time.

Now that XA is keeping count anyway, I also gave it some cleanup logic - WIPEing its own file, allowing XB to die by having it link after the modem disconnected, and WIPEing its file as well.

There are still some problems with this code. The main issue is that if the file size is even, the cycle count is odd, meaning that for every other pager, T skips past 0 and the TJMP turns into an infinite loop.

A second issue which is easier to solve is that for some reason, every pager EXA is just one cycle fast compared to the previous one. The easiest way I found to solve this is to undo my 'freebie speed increase', and put the LINK above the COPY.

But how do I solve the issue for every other pager and only for the test cases where the file size is even?

code:
;XA

GRAB 301
LINK 800
COPY 8 T

MARK DIAL

@REP 11
COPY F #DIAL
@END

MULI M T X
SUBI T 1 T
COPY X M

COPY -1 #DIAL

TJMP DIAL
VOID M
WIPE
GRAB 300
WIPE

;XB

GRAB 300
LINK 800

MARK COUNTFILE
SEEK 1
ADDI X 3 X
TEST EOF
FJMP COUNTFILE

MARK NEXT
SEEK -9999
ADDI X 19 M

LINK 800

MARK COPYMORE
COPY F #DATA
TEST EOF
FJMP COPYMORE

LINK -1

REPL PAGER
JUMP NEXT

MARK PAGER
LINK 800
COPY M X
MODI X 2 T
FJMP OK
NOOP
MARK OK
DIVI X 2 T

MARK WAIT
SUBI T 1 T
TJMP WAIT

COPY 1 #PAGE
I started with dividing the cycle count by 2 so that the SUBI can never run past 0. But with the way DIVI rounds that still meant every other EXA was out of sync. So in the end I decided to just have the PAGER check if the count is odd, and in that case waste a cycle with a NOOP.

The PAGER EXAs are a bit slower than they could be with that extra check - and also because they wait 8 iterations while 7 and a bit would be enough. But this is a working solution.



Copying the message makes it appear on the little green displays. Sending anything to #PAGE makes the pager hosts vibrate and makes the displays light up.



This solution runs at 540/54/26, with top percentiles of 298, 42 and 9. What can be improved?

The first change is simple. In the PAGER, replace COPY M X with SUBI M 44 X, to reduce the cycles to 496. It turns out my counters are waiting an unnecessary 44 cycles (almost but not quite an entire iteration), and this is the easiest place to shorten that.

Since I know the files are at least size 9 I can unroll some loops partially.

code:
;XB

GRAB 300
LINK 800

SEEK 9
TEST EOF
TJMP NEXT

MARK COUNTFILE
SEEK 1
ADDI X 3 X
TEST EOF
FJMP COUNTFILE

MARK NEXT
SEEK -9999
ADDI X 30 M

LINK 800

@REP 8
COPY F #DATA
@END

MARK COPYMORE
COPY F #DATA
TEST EOF
FJMP COPYMORE

LINK -1

REPL PAGER
JUMP NEXT

MARK PAGER
LINK 800
SUBI M 28 X
MODI X 2 T
FJMP OK
NOOP
MARK OK
DIVI X 2 T


MARK WAIT
SUBI T 1 T
TJMP WAIT

COPY 1 #PAGE
The first 8 data copy steps have been unrolled, which is the main speed improvement. It's not faster to unroll the 9th, the EXA has to test for EOF anyway. I needed to update the file counter as well. I just skip over the first 9 values in the file and instead add the cycles they cost to the static value in ADDI X 30 M. In this case it saves 2 cycles to add an extra EOF check after the SEEK 9, as compared to do a SEEK 8.

Since there are less cycles per iteration, there are less cycles to spare overall and the SUBI value in the PAGER needed to be lowered.

This solution runs at 335/65/26, which is already surprisingly close to the top percentile.

I think it should be possible to lower the activity too. It would require actually copying the file to each EXA so they don't have to jump back and forth.

Here's a decent solution:
code:
;XA LOCAL

GRAB 301
LINK 800
COPY 8 T

MARK DIAL

@REP 11
COPY F #DIAL
@END

VOID M
COPY -1 #DIAL
SUBI T 1 T

TJMP DIAL
WIPE

;XB GLOBAL

GRAB 300
LINK 800

MARK COUNTFILE
SEEK 1
ADDI X 2 X
TEST EOF
FJMP COUNTFILE
ADDI X 5 F
COPY 7 X


MARK NEXTWR
SEEK -9999
REPL WRITER

MARK LP
COPY F M
TEST EOF
FJMP LP

SUBI X 1 X
NOOP
TEST X = -1
FJMP NEXTWR

WIPE
HALT

MARK WRITER
MAKE

MARK COPYLOOP
COPY M F
SEEK -1
TEST F < 9999
FJMP COPYLOOP

MARK ENDWR
MODE
COPY 0 M
LINK 800
SEEK -1
MULI F X X

SEEK -1
VOID F
SEEK -9999

MARK DATALP
COPY F #DATA
TEST EOF
FJMP DATALP

WIPE

ADDI X 1 T

MARK WAIT
SUBI T 1 T
TJMP WAIT

COPY 1 #PAGE
XA is just a dialer again. It dials the next number once it gets a message on M, and it keeps a counter so it can clean up after itself. It uses local mode so that XB can use global mode for copying files.

XB needs to count the file again for the timing, does some calculations on the result and puts that at the end of the file. It needs to use the file because at this point, XB still needs X to keep track of how many pagers are left to go, and T for all sorts of EOF tests and such.

XB makes a WRITER REPL for each pager, copies the entire file to it, and send it towards a pager.

The writer switches to local mode to let XA know to continue. Then it reads the counter value in the file and multiplies it by X (which still contains a number referring to how many pagers are left), saving the result (the waiting time) in X. It then removes that value from the file so that the file-to-#DATA copy loop can do a simple EOF check. Once it's done it WIPEs the file and starts waiting until the others are done.

The wait time calculation might be hard to follow. What's going on is that each file entry now takes 4 cycles. There's also a static 10 cycles per iteration that should be added. Because both values are even, and because the WAIT loop takes 2 cycles, I can use half their value right at the top. Since X actually hits zero now, there's an ADDI 1 just before the WAIT loop so that the last EXA doesn't skip over 0. That's really the same thing as in the fast solution, where I did a SUBI before the WAIT loop to cut out unnecessary cycles, just from the other direction. It was more convenient here.

Note that there's a NOOP in the file copying code simply because that brought the static cycles to 10, which means the waiting time is always an even amount of cycles, which made that logic much simpler. Getting rid of it and replacing it with an odd/even check might be faster but a low activity solution like this is never going to be the fastest anyway. 565/68/10.


Wait, 10? The top percentile is 9.

The extra activity is caused by the fact that both the dialer and XB go to the modem. That's not necessary... but we have to copy more data over global M. Let's copy file 300 because it's the smallest.
code:
;XA GLOBAL

GRAB 301
LINK 800
REPL XB

COPY 8 T
MODE

MARK DIAL

@REP 11
COPY F #DIAL
@END

VOID M
COPY -1 #DIAL
SUBI T 1 T

TJMP DIAL
WIPE
HALT

; OLD XA ENDS HERE

MARK XB
MAKE
MARK NEXT
COPY M T
FJMP DONE
COPY T F
JUMP NEXT

MARK DONE
SEEK -9999

MARK COUNTFILE
SEEK 1
ADDI X 2 X
TEST EOF
FJMP COUNTFILE
ADDI X 5 F
COPY 7 X


MARK NEXTWR
SEEK -9999
REPL WRITER

MARK LP
COPY F M
TEST EOF
FJMP LP

SUBI X 1 X
NOOP
TEST X = -1
FJMP NEXTWR

WIPE
HALT

MARK WRITER
MAKE

MARK COPYLOOP
COPY M F
SEEK -1
TEST F < 9999
FJMP COPYLOOP

MARK ENDWR
MODE
COPY 0 M
LINK 800
SEEK -1
MULI F X X

SEEK -1
VOID F
SEEK -9999

MARK DATALP
COPY F #DATA
TEST EOF
FJMP DATALP

WIPE

ADDI X 1 T

MARK WAIT
SUBI T 1 T
TJMP WAIT

COPY 1 #PAGE

;XC GLOBAL

GRAB 300

@REP 8
COPY F M
@END

MARK SEND
COPY F M
TEST EOF
FJMP SEND

COPY 0 M
XA is still the dialer. But after grabbing the file with phone numbers, it makes a REPL which I called XB because it contains all the code of the previous XB. It just has a little bit of extra code at the start, where it makes a file, then starts receiving data over M from the new XC, which copies it from file 300.

XC ends with a 0 which is recognized by XB because it first copies data to T. Also, XA mainly still operates in LOCAL mode, but since XB needs to be in GLOBAL mode I just put a MODE instruction directly after the REPL. 617/92/9. The lowest possible activity.

That's it for now. Further improvements in size and cycles are possible but it's time for me to finish this assignment.


Fascinating.
There it is.
Well.




This choice doesn't change the outcome so let's just continue.

What did you find?

How can I explain it...
Processing.
Think of it as the frame rate of the world slowing down.
By a lot.
Funny, huh?
Funny how I went from some random blob of code that didn't know anything to understanding all of existence.




This choice also doesn't matter and there's more to see.

That doesn't explain it.

I will. In a minute.






Another cutscene with Ember. By the way, did you notice that these cutscenes with Ember take place around 3 AM or whatever? Looks like Moss likes to work late.

So you wanted to know the truth.
The truth is that... well, it's a simulation.
You, me, everything, this whole world we live in... it's just a computer program. Running as part of a machine.




And as the world gets more complex, it's starting to malfunction.
So far, it's been on a smaller scale...
The phage, for one example. It wasn't supposed to spread like that.
There are other problems coming... larger ones.
What we think of as normal life will just get stranger and weirder until nothing makes sense anymore.
Then the laws of physics will start to break down and everything will just come... unglued.
Not a pretty sight.
But we don't have to accept that.




There might be a way to stop this future from taking place.
I have one final job for you.
But you'll have to be brave.


I wonder, readers, did you see this coming? Anyway, let's find out what Ember wants now.

Okay, time for me to eat you.



Here is the vote for today.

Next time... the finale.

Carbon dioxide fucked around with this message at 18:38 on Apr 23, 2023

bewilderment
Nov 22, 2007
man what



You've gotta be making GBS threads me.

berryjon
May 30, 2011

I have an invasion to go to.
Excuse me?

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.

heh


bewilderment posted:

You've gotta be making GBS threads me.

:hmmyes:


for optimizations, from the histograms it looks like 32 lines should be possible, maybe 31, but the best i've managed is 33


code:
GRAB 301

MARK MAIN_LOOP
ADDI X 5 X
ADDI F 1 T
REPL DATA
MODI X 55 T
TJMP MAIN_LOOP


COPY 26 T
MARK WAIT_TRANSFER
SUBI T 1 T
TJMP WAIT_TRANSFER

REPL DIAL; *DISCO*
JUMP MAIN_LOOP

MARK DATA
REPL DIAL
GRAB 300
MARK READ
COPY F M
JUMP READ

MARK DIAL
LINK 800
SUBI T 1 #DIAL
LINK 800
MARK PRINT
COPY M #DATA
NOOP
TEST MRD
TJMP PRINT

SUBI 441 X T
MARK COUNTDOWN
SUBI T 1 T
TJMP COUNTDOWN
COPY 0 #PAGE
884/33/104

fast solution isn't too mind-blowing, mostly splitting functions for parallelization with hard-coded delays so that the variable message length doesn't break loop synchronization
code:
;XA MODEM AND TIMING
GRAB 301
LINK 800
MARK LOOP
@REP 11
COPY F #DIAL
@END

TEST EOF
REPL TIMER

SUBI 1 T T;LOGIC FLIP
MULI T 9 T;EOF=0 ELSE=9
TJMP WAIT_DATA
WIPE
HALT

MARK WAIT_DATA
SUBI T 1 T
TJMP WAIT_DATA

SUBI X 18 X
JUMP LOOP


MARK TIMER
LINK 800
TJMP LAST;EOF=TRUE
ADDI X 125 T
MARK WAITIMER
SUBI T 1 T
TJMP WAITIMER
NOOP
MARK LAST
COPY 0 #PAGE


;XB TRANSMIT MESSAGE
GRAB 300
LINK 800
JUMP START

MARK HANGUP
COPY -1 #DIAL
MARK START
ADDI X 1 X
SEEK -99
LINK M;WAIT FOR SYNC
@REP 8
COPY F #DATA
@END

MARK DATA
COPY F #DATA
TEST EOF
FJMP DATA

LINK -1

MODI X 8 T
TJMP HANGUP
WIPE


;XC TIMING (XB) CONTROL
LINK 800
MARK LOOP
COPY 5 T
MARK WAIT_DIAL
SUBI T 1 T
TJMP WAIT_DIAL

COPY 800 M

ADDI X 1 X;DO 8 TIMES
MODI X 8 T
DIVI T T T;THEN CRASH

COPY 9 T
MARK WAIT_DATA
SUBI T 1 T
TJMP WAIT_DATA

JUMP LOOP
291/76/27

silentsnack fucked around with this message at 16:44 on Sep 25, 2022

Anaxite
Jan 16, 2009

What? What'd you say? Stop channeling? I didn't he-
Well now.

So that's your plan?

Quackles
Aug 11, 2018

Pixels of Light.


Carbon dioxide posted:

Looking through the test cases, the messages Ember wants me to send are "Hey would you write so now and relieved?", "Do you think I am to see by man the ways?" and "Did you point out to have been each mine?". I don't know either. :shrug:

Has Anyone Really Been Far Even as Decided to Use Even Go Want to do Look More Like?



But yes. Here we go. Things are about to get... complicated. :getin:

biosterous
Feb 23, 2013




you've gotta be making GBS threads me

Adbot
ADBOT LOVES YOU

Dirk the Average
Feb 7, 2012

"This may have been a mistake."

biosterous posted:

you've gotta be making GBS threads me

The making GBS threads comes after she eats us. The proper response is "you're gonna be making GBS threads me."

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