The Let's Play Archive

EXAPUNKS

by Carbon dioxide

Part 13: Workhouse Work Management System

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?