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



Hello and welcome to this Screenshot Let's Play of EXAPUNKS!

To quote the Steam store page:



The year is 1997. You used to be a hacker, but now you have the phage. You made a deal: one hack, one dose. There’s nothing left to lose... except your life.


EXAPUNKS is a Zachtronics game released in 2018. It's similar to their earlier titles TIS-100 and Shenzhen I/O and you know what that means - we're gonna get programming, so get your thinking caps on.

Speaking of Shenzhen I/O, make sure to check Quackles's LP of that game if you haven't yet. You could call it an inspiration for this LP.

This game has an assembly-like programming language that should be straightforward enough if you played those earlier games, but it's just different enough to really be its own thing.

I also really like the plot and the way this game makes itself feel 'realistic'. But you'll see that when we get to it.

Formatting note
- I will use italic text to indicate any text that is actually in the game.
- Regular text is me taking the role of the game's protagonist.
- I will use this CO2 symbol whenever I break the fourth wall, such as for game design notes.

Spoiler policy
Please do not talk about anything in the game or additional materials we have not encountered yet.

Table of contents

Part 1 - Old friends and new issues
Part 2 - TRASH WORLD NEWS - Tutorial 1
Part 3 - TRASH WORLD NEWS - Tutorial 2
Part 4 - TRASH WORLD NEWS - Tutorial 3
Part 5 - TRASH WORLD NEWS - Tutorial 4
Part 6 - Euclid's Pizza
Part 7 - Mitsuzen HDI-10
Part 8 - Peanut-free Peanut bars
Part 9 - Point of Sale System

Carbon dioxide fucked around with this message at 19:48 on Jan 15, 2022

Adbot
ADBOT LOVES YOU

Carbon dioxide
Oct 9, 2012



EXA language reference guide




(click to enlarge)

Carbon dioxide fucked around with this message at 16:26 on Dec 18, 2021

Carbon dioxide
Oct 9, 2012



Part 1 - Old friends and new issues



As we start the game and the loading screen pops up we immediately get blasted by this jam.
OST: Exapunks :siren: LISTEN to this. Seriously. :siren:



This is my apartment.

It acts as the main menu screen.

OST: Apartment



The TEC Constellation II tablet is our options menu. Mostly standard stuff - controls, full screen vs windowed, sound volume, a few visual options, a profanity filter, and some options related to how online leaderboards are shown. I'll make one change so that my Steam friends aren't highlighted on the leaderboards, for their privacy. Otherwise the defaults are fine.

Well. I might be in all sorts of trouble but at least I got a good shitposting box. Let's check out my SAWAYAMA Z7 TurboLance.



I'm using the Axiom Developer Edition operating system. It's what all the cool kids use. Very customizable and doesn't get in your way. Chatsubo is a nice chat program. I like to lurk in the EXAPUNKS channel, where all of the hackers from the old days hang out. It's a bit quiet at the moment though.

But I almost forgot, I'm supposed to meet up with someone. I'm gonna need meds soon.



*Knock knock*

Someone's at the door.
I can't remember... Did I ask them to come up?
Things have been hazy...
Every day, more of my body is turned into junk...



Nivas: Hey.
Nivas: Hey, can you hear me?
Nivas: I heard you were looking for some medicine for the phage?




Nivas is voice acted by Emma Adele Galvin. The protagonist's voice/thoughts are not voice acted.

Looks like you definitely need it.

That's right... Nivas.
Said they could find anything.
Even bootleg medication.

So, I do have a source. I know where to get it.
It's cheaper than the real deal, but it's still gonna be pricey...

Nivas pauses and looks me in the eye.

The going rate is 700 a dose. You need to take one dose every day.
Yeah, that's dollars.
Sorry, I don't set the prices. I'm just a courier.
It's not like any of that money goes to me...
Anyway, if you do get the money, give me a call.


Nivas left for now.


While I was at the door, there was some activity in the chat. At least it's not entirely abandoned.


Anyway, I'm going to need money and I'm going to need it fast. Well, I have this program, WorkHouse on my computer. People can hire me through that to do boring tasks for a couple pennies. At least I don't have to leave my house, so people don't have to see me like this.

Let's give it a go.




Man, this looks terrible already. And who the gently caress has the money to pay 200 dollars for a steak or whatever? Ugh.


Hehehe.


Huh? It said "validating..." and it accepted that? Still, ten cents? This will take forever.

I actually have no idea what makes this thing accept your input. Putting in completely random crap makes it say "A peer reviewer rejected your work.", but a certain amount of minor errors seems allowed.


what the gently caress

Wow, a whole ten cents!
Congratulations.
You only need to do 6,999 more of these and you'll have enough for today.




Sometimes the game gives you dialogue choices. I don't think it affects anything but the next line or two. You can replay cutscenes at any time so if you like you could go through all the choices to see what they do.

By the way, this character is voiced by Sarah Elmaleh.

Who is this?

Don't worry about that right now.
You need that medication to stay alive, right?
Well guess what? I can get it to you.
You'll need to start hacking again though.
One hack, one dose.
Easy.
Deal?



I've forgotten how...

You're about to remember.
Knock knock.



I've no idea who or what that was but she seems to have set up residence on my desktop and I can't make her disappear.

There's also some activity in the chat but that's not important right now. A meeting with an old friend appeared in my organizer, and it's planned for, huh, right now?

*knock knock*

Someone's at the door again.



An old friend...
Ghast.
I knew his real name once, but that's gone now.

Hey. Came by to give you something.

Ghast hands me a small booklet. It's made of real paper.
Apparently, it's something called TRASH WORLD NEWS...

I can't hack like I used to.
Whatever edge I had, it's gone now.
But I had to keep doing something.
Something to keep the culture alive, you know?
Computers are running everything these days.
Before long, human beings aren't even going to have a say.
So now I equip people with knowledge.
The knowledge to make a computer do what you want, on your terms.
Anyway, I won't keep you. I know you like to be alone.
Hope you like what you see in the zine.


Thanks mate, I appreciate it.

Ghast is voiced by Cornell Womack.



As the game says here, it uses printed zines as a reference manual. Originally, these were actually printed and sent to your home if you bought the limited release. I absolutely love that! It makes the game feel much more real.

As a matter of fact, hacker magazines were a real thing in the 80s and 90s. They had all sorts of information on phreaking (phone hacking), early modem usage, and so on.

For the Steam version, they come as PDF files, both in a printable format and a format for digital reading. Since last year, it's also possible to buy physical copies again through Lulu.

Carbon dioxide fucked around with this message at 08:54 on Nov 28, 2021

Carbon dioxide
Oct 9, 2012



Part 2 - TRASH WORLD NEWS - Tutorial 1

So, my old friend Ghast came by and gave me this hacking magazine. Let's have a look.

The cover:




Point of sale systems? Banks? drat, these people seem to have a lot of insider info. Well, at least there's a "for EDUCATIONAL PURPOSES ONLY" disclaimer to the side. I'm sure that'll help.


Ghast is right you know. Programs and websites run by big corporates... nothing good comes from that. As for the EXAs, I've heard of those but I'm not sure what they do.


Okay... so to summarize, EXAs are these small programs that move from one computer to another. You can actually see them move around in a network, and they contain code and registers. The code of course tells them what to do. The registers are slots to store values. You can put numbers in, both positive and negative, as well as words, and you can access them from code.

Yeah. That sounds kinda familiar... every EXA acts like a tiny little CPU of its own.


This page explains modern networking. A single computer is called a "host" and it looks like a little platform on the EXODUS programming tool. The number of squares in a host shows how many EXAs can be in a computer at once. Hosts are connected to each other through "links" which can be traversed by EXAs.
There are "files" which can store a lot of values but don't have code. EXAs can interact with files by grabbing and dropping them.
Finally, there's "hardware registers" which are a way for EXAs to talk to the hardware of the host system directly. Not sure what that's useful for but maybe I'll find out.



Hey... something appeared on my computer. I'll leave the magazine on my table so I can look at it at any time.


Looks like =plastered has been busy. Good for them!


Anyway, a new item appeared in my organizer. Is this what the mysterious lady on my screen was talking about?



Actual levels usually start and end with a conversation. These are not voice-acted.

Would you look at that!
That zine's got a hacking tutorial in it.
How about that?
Funny coincidence, huh?
Isn't it?



I don't really trust her. Why would I interact with her more than necessary?

I guess.

Oh, come on.
I timed that just right, didn't I?
Let's continue.



OST: Getting Started

This must be that EXODUS environment mentioned in the Zine. Let's click around a bit and see how it works.

The X at the top right lets me go back to the desktop and organizer. Always good to know.


At the top left, where it says NEW SOLUTION 1 I can put in a name and click the little file icon to save and load multiple solutions. It even has stats for how fast each solution is, so I can optimize my programs. Nice!


I start with one EXA simply called XA which has no code yet, but I can just type it in. I can create more EXAs and name them, but they are limited to two-character names.

Below that I seem to have a file browser, even listing files outside my own computer. I don't know why that works but okay.


The big screen to the right is obviously my network overview, and the bottom part contains some controls and my goal for this assignment.
Pressing the SHOW GOAL button changes the network overview so that the file is moved to the OUTBOX host and there are no EXAs in sight.

Well, I guess I should check out that tutorial.


Since I don't want to overwhelm you folks I'll only post the left page for now, since it's all we need for this puzzle.

Well, this seems easy enough. Just literally copy what it says in the book? I'll give that a try.


Looks good to me.


So, the controls at the bottom. From left to right: reset simulation, pause simulation, step through a single cycle (useful for debugging), run (at a watchable speed), fast forward.

Each cycle, every EXA can execute one line of code.

Here I let the simulation run for two cycles. In the first cycle, XA executed LINK 800. That means: from the starting point (my own host, called RHIZOME), traverse the link with ID 800. The EXA ended up in the INBOX host. Then, GRAB 200 caused the EXA to grab the file with ID 200. This was now possible because the EXA and the file were in the same host.


Another LINK 800 operation makes the EXA traverse another link. Since from the point of view of the INBOX, link ID 800 goes to the OUTBOX, that's where the EXA went.


The DROP command lets the EXA drop the file, and finally the HALT command destroys the EXA entirely. The "Leave no trace" goal means you need to either HALT all your EXAs or get them all to come back home.


Once my program is working, the simulation will then run 100 tests at fast forward speed. I guess it wants to make sure my solution wasn't a fluke and actually works all the time.


And we get stats. Cycles is the total amount of cycles the program needed to complete. Size is a measure of the amount of lines of code. For both, lower is better. We'll get into Activity later.

Wait a second, does that say "Record Solution Gif"? That is very kind, game. Don't mind if I do.


Neat.

Now, if you noticed, we didn't have the best score on the leaderboard histogram. Any idea what could improve it?

.
.
.
.
.
.
.
.




Turns out the DROP operation is not necessary. An EXA will automatically drop whatever it's holding if it gets destroyed.

It's easy enough to optimize this tutorial level if you know what you're doing. It will get much harder later. I'll probably come up with a reasonable solution or two and leave finding the optimal solutions to the thread.


Back in the organizer, we can see our stats, and a new mission appeared.


Also some more talking in the chat.

Finally, the lady behind our assignments has more to say after each assignment.

I can see everything, you know.
Everything on your computer.




Even though they're not the most exciting options, for some additional thread participation, I'll see if I can end posts on one of these dialogue option screens.

Please vote what our protagonist answers.

Carbon dioxide fucked around with this message at 08:56 on Nov 28, 2021

Quackles
Aug 11, 2018

Pixels of Light.




I vote for "There's not much to see."

Also, fun fact: If an EXA runs out of instructions, it will stop. This means it's possible to save an instruction by leaving off the HALT at the end.

But yeah, I love this game - it's one of Zach's finest works. It certainly feels a lot less constrained than SHENZHEN I/O was.

Quackles fucked around with this message at 09:22 on Nov 28, 2021

Carbon dioxide
Oct 9, 2012



Quackles posted:

Also, fun fact: If an EXA runs out of instructions, it will stop. This means it's possible to save an instruction by leaving off the HALT at the end.

Nice. That reduces the size to 3, but leaves the cycles at 4. I guess the EXA "realizing" it is out of instructions takes a cycle.

GuavaMoment
Aug 13, 2006

YouTube dude


Do you have the physical version of this game?

Good luck getting through all the levels! There's one in particular at the end only 3 of my steam friends have beaten.

DivineCoffeeBinge
Mar 3, 2011

Spider-Man's Amazing Construction Company


Quackles posted:

I vote for "There's not much to see."

:same:

Junpei
Oct 4, 2015

Cuz I'm a creep
I'm a weirdo
What the hell am I doin' here
I don't belong here

There's not much to see.

Anticheese
Feb 13, 2008

$60,000,000 sexbot
:rodimus:



Junpei posted:

There's not much to see.

Not an emptyquote!

megane
Jun 20, 2008





I’d gotten like 1/3 of the way through this game and then dropped it, but this thread got me to go back and finish it. Game rules.

bewilderment
Nov 22, 2007
man what





I wanna see more! Not much to see on the desktop though.

peachsynapse
Dec 22, 2007

The sea monsters appreciate your good taste.

This game scratches a particular itch. Thanks for doing this.

I vote for the most apathetic response in each scenario. In this case, not much to see fits the bill.

Carbon dioxide
Oct 9, 2012



Part 3 - TRASH WORLD NEWS - Tutorial 2

Let's start with some comments from the threads.

Quackles posted:

Also, fun fact: If an EXA runs out of instructions, it will stop. This means it's possible to save an instruction by leaving off the HALT at the end.
Good point. That reduces the size to 3, but leaves the cycles at 4. I guess the EXA "realizing" it is out of instructions takes a cycle.

GuavaMoment posted:

Do you have the physical version of this game?

Good luck getting through all the levels! There's one in particular at the end only 3 of my steam friends have beaten.

No, I only have the Steam version. I have beaten story mode before, but not the postgame stuff.

Adding up the votes from both the SA and Beach threads, we have one vote for "Oh" and seven votes for "There's not much to see". So let's dive into it.



There's not much to see.

There isn't.
I expected you to be sitting on all kinds of secrets...
It's alright though.
We'll find plenty more.




Alright, looks like next up is another tutorial.

People or animals are often motivated by the anticipation of a reward.
Are you anticipating the medication as a reward?




Oh come on, lady. I need that to survive, it's not like I have a choice. That's not a reward.

I guess you're right.
It's about survival.
Processing.
Okay. Let's continue.


Yes, survival, that's what I said... wait, did you just say "processing"? Hm, could it possibly be the case that the lady, whose window literally says "Emulated Multi-Branch Emotional Reasoning", is not in fact, human? 🤔

Since the game doesn't try very hard to hide this fact, neither will I. As the screen says, we can just call her EMBER.


OST: Getting Started


Once again, one of the goals is "Leave no trace." Since that seems to be common, I won't be mentioning it anymore.

Clicking "Show Goal" in this case not only shows file 200 in the output, but it shows the value 436 appended to the end of the file.

Anyway, let's see what Ghast has to say about this tutorial.



Alright, just copy the code again. That I can do.


Code copied, and I started stepping through it. Just as a note - there doesn't seem to be a limit to how many lines of code a single EXA can have. There's only the global limit, which is 50 for this tutorial assignment.

Anyway, the LINK 800 took the EXA to the INBOX again, and the GRAB operation grabbed the file. As you can see, the file has moved from the file explorer under the "CREATE NEW EXA" button to being 'held' by the EXA's window.

Now, the new COPY operation does exactly what it says, it copies a value from one place to another. In this case, from the F register to the X register. However, the F register always points to whatever file the EXA's holding - and more specifically, the location of the cursor within the file. So F holds '72' right now.


The value 72 has been copied from F into X now, and the file's cursor moved to the next position. The cursor moves forward automatically whenever you interact with the F register.

The ADDI operation adds two values together (the first two arguments, X and F) and stores it in the register given by the third argument (X). So, it will add 72 from the X register to 52 from the cursor's location in the file.


Which makes 124 and moves the file cursor forward again. MULI works the same as ADDI, except it multiplies the values.


And SUBI subtracts the second value from the first.


The cursor is now at the end of the file.


If you use COPY to F while the cursor is at the end, it will append the value to the end of the file.

The rest of the program is stuff we've seen before. We move the file to the OUTBOX and destroy the EXA.



The gif function isn't that useful here because it only shows EXAs moving around, it doesn't show operations within files. So the result seems identical to the one from the first tutorial.

Not bad... but can I do better?


You may have thought of doing something like this. Use meaningless COPY operations to move the cursor to the end of the file and then just write a hardcoded value '436' in there. But that doesn't work - not only doesn't it save any time, the values in the file are different for each test run so only the first out of a hundred runs succeeds with this code.


What I can do is apply my learnings from the first tutorial. The HALT is unnecessary because an EXA destroys itself once it runs out of instructions, and the DROP is unnecessary because when an EXA destroys itself, it drops whatever it's holding.

This drops the cycle count to 9 and the size to 8.

There's one more trick that's less obvious. You can combine the COPY and ADDI operations like this:


Why does this work? Well, now the ADDI operation says "add the value in F to the value in F and store that to X". But, remember, EVERY interaction with F moves the cursor forward. So this actually adds the first value in the file to the second value and stores that in X, giving the same result with one less operation.


This drops both the size and count one further.

As you can see from the leaderboard, a lot of people managed to save another cycle. That might be because they use an operator that's not been introduced yet. Feel free to discuss improvements in the thread, but if they involve operators we haven't seen yet, please put them in spoiler tags, for any readers that prefer experiencing this game as it comes.



Does it upset you that I will provide your medication only if you work for me?

I'm noticing that Ember usually has two questions to ask between assignments - one in the outro and one in the intro for the next assignment. You know what... since one doesn't affect the other I'll just throw both of 'em up for a vote.



What do you think of your life situation overall at the moment?

Please vote for both questions.

Carbon dioxide fucked around with this message at 16:49 on Dec 4, 2021

Yvonmukluk
Oct 10, 2012

Everything is Sinister



I'm liking this LP, even if I'm too tinybrained to understand all the programming stuff.

1) Does it matter? I don't have a choice.
2) Why all the questions?

idhrendur
Aug 20, 2016



Yvonmukluk posted:

1) Does it matter? I don't have a choice.
2) Why all the questions?

Seconded.

Also it seems a little odd to see COPY instead of MOV. Though it makes sense, COPY is a little more accurate to what happens on any architecture I've seen and also fits the four character instruction length this game seems to be using.

megane
Jun 20, 2008





A way to save a cycle (without using any new operations) is SUBI X F F.

Carbon dioxide
Oct 9, 2012



Part 4 - TRASH WORLD NEWS - Tutorial 3

megane posted:

A way to save a cycle (without using any new operations) is SUBI X F F.
Of course. :doh:



We can use the exact same trick that saved a COPY operation at the beginning to have the subtraction step write directly to the file. Remember, reading F moves the file pointer forward so the write happens at the end of the file



Which nets us the best solution anyone found. Anyway, where were we?



Adding the votes in both threads together, one vote for Nothing is free and two for Does it matter?

Does it matter? I don't have a choice.

That's true.
Your agency is severely constrained by your situation.
Interesting.
This is good data.


Data? What kind of data are you collecting?
Anyway, while we were busy the folks in the chat were discussing that wardialer business.



Hah, yeah. Might make for a bit of a show.

Our next assignment is TRASH WORLD NEWS - Tutorial 3. I see only four tutorial pages in the Zine so hopefully this tutorial nonsense is over soon. I want to get to work already.



One vote for What? and two for Why all the questions? this time.

Why all the questions?

I am collecting data.
It will help me formulate future actions and responses.
In other words, I'm curious, that's all.
Recalibrating.
Let's continue.


Okay, whatever. Let's dive into it.


OST: Getting Started

A slightly more complicated network this time.



So, the file we need to copy data from is sitting in the SECRET host at the top left. And my EXA can't just carry it out. The link to SECRET is one-way only, since it has no ID on the SECRET side. We're going to need something new. Let's see what Ghast has to say.



No solution to copy anymore. Instead Ghast explains some new instructions. I'll build something with them and explain during the test run.



XA will go up to the SECRET host and send the file data over the 'M' communication register, while XB will read from there and write it to a new file.



As always, let's first get the EXAs to the right place.





XA grabbed the file, while XB used the MAKE command to create an empty file.
Next, XA sends the first entry in the file (the word ECHO) to the M register.

M has two modes, which you can set for each EXA: GLOBAL and LOCAL. I like to think of them as radio broadcast frequencies. If you write a value to the M register, the EXA will completely pause until some other EXA reads from it. If you try to read a value from the M register and nobody is broadcasting, that EXA will pause until it can receive something.

EXAs in GLOBAL mode can communicate across hosts, but EXAs in LOCAL mode can only communicate if they're in the same host. Importantly, and this is where the frequency analogy comes in, an EXA listening in GLOBAL mode cannot receive a message from an EXA in the same host that's sending in LOCAL mode. It can receive messages from an EXA in the same host that's also broadcasting in GLOBAL mode though.

As you can see, XA is sending, and XB is already ready to receive so it will get the message the very next cycle.



Since I need to swap the order of the entries in the file, I decided to buffer the first entry in the X register, then copy the second one directly into the file, and then copy the buffered value into the file.

Words act exactly the same as numbers except you can't use any of the arithmetic instructions with them.



The file info was copied, XA ran WIPE as its last instruction, which deletes the file it's holding. Next, as they run out of instructions, both EXAs self-destruct and the assignment is complete.



The EXODUS simulator shows an EXA wiggling with static around it if you pause the simulation in the cycle before it self-destructs, which is a nice touch.



As usual, we can do better.

The first improvement is both incredibly simple and a bit stupid.



All we do is swap the instructions of XA and XB. That's easy enough - the game allows you to select text with your mouse and copy-paste with ctrl+c/x/v. This drops the cycle count by one. But why does this work?

Well, every cycle, every EXA will attempt to execute one instruction. However, only one EXA can traverse a specific network link at a time, so XA and XB can't both cross from RHIZOME into INBOX during the same cycle. Since both start with the LINK 800 instruction, who wins?

Turns out the game has some hidden ordering of EXAs which determines this.

In the original solution, the receiving EXA wasted a cycle reading from M while the other wasn't sending yet. This caused the sending EXA to also waste a cycle waiting for the other one to accept the message. Both still finished at the same time, but both wasted a cycle. By switching who arrives first, the receiving EXA starts reading at the same cycle the other EXA sends the data, and they can both save the waiting cycle. Yeah, sometimes this kind of meta gaming is necessary in EXAPUNKS to get the high score.



The histograms show that for this assignment it is also possible to get a lower (=better) activity score. As the game explains it, Your activity score is the number of times EXAs you control execute LINK or KILL instructions. Well, we haven't even seen the KILL instruction yet. We do four LINKs total to get the EXAs to the right places. Reducing that is possible, but not with the instruction set we know about right now. I'll get back to this puzzle a bit later.


Oh, while I was leafing through the Zine I noticed there's some stuff in the back that's not related to programming. For instance there's a recipe!



Anyone up for some dumpster donuts?

Anyway, let's submit my solution and see what Ember has to say.

How do you feel about it now?
You're closer to the goal.
Any change?




And also the intro dialogue for the next assignment:

Yes. You can do it!
This is positive encouragement.
It is designed to increase activity in your prefrontal cortex.




As usual, please vote for both questions.

Arcon
Jul 24, 2013


Hack the planet!

1. What do you really want?
2. Don't count on it.

Quackles
Aug 11, 2018

Pixels of Light.




Hack your kitchen.

Incidentally, the EXA order thing reminds me of bonder order (and having to swap bonders around to get the desired result) in SpaceChem.

[[What do you really want? / I'm sure it is.]]

idhrendur
Aug 20, 2016



1. I feel like I'm in a study
2. Don't count on it.

Carbon dioxide
Oct 9, 2012



Part 5 - TRASH WORLD NEWS - Tutorial 4

The last of the tutorial assignments! Let's jump right into it.

How do you feel about it now?
You're closer to the goal.
Any change?




The votes were more divided this time. One for Not really and two each for the other two options. I did a pseudorandom toin coss to settle the tie.

I feel like I'm in a study.

Sure, think of it like that.
Everything's an opportunity to learn.
Anyway, there's just one more tutorial to go.
You're almost there.


Meanwhile in the chat:



Yeah. "Don't touch the poop", as they say.



Sounds like a useful thing to learn.

Yes. You can do it!
This is positive encouragement.
It is designed to increase activity in your prefrontal cortex.




Three votes for Don't count on it and one each for the other options.

Don't count on it.

But you're doing great!
There, a little more for you.
I'm sure it will help.


Well, whatever. Let's see the assignment.


OST: Getting Started





The Zine page for this assignment goes into loops and conditionals. These are a necessary component to make any programming language "Turing-complete", which basically means it can be used to write any arbitrary program.

We learn four new instructions. The first is TEST. It tests whether some comparison is true or not. What this page doesn't mention is that it can do checks with =, <, and > (is number A equal to, less than, greater than number B). If the comparison is true, it places 1 in the T register. If not, it places 0 there.

TJMP and FJMP go together: TJMP (jump if true) makes the EXA start executing elsewhere in the program, if T equals 1. Otherwise it just continues with the next instruction down the line. FJMP (jump if false) does the opposite: it causes the EXA to start executing elsewhere if T is set to 0.

It is not required to set T with the TEST command, you can just COPY or ADDI or whatever to T as well.

How does it decide where to jump execution to? Well, you need to add a label, and you can mark the location to jump to with MARK label. The example code in the Zine shows how it's done.

I think things will get more clear as I try to solve the assignment.

But I think this is a good time to bring up Compiler errors.

A compiler is a special program that translates human readable code (such as the EXA language we've been learning) into machine instructions that can actually be fed into a CPU. But it can only translate code that follows the syntax rules. Otherwise, it will give an error and you can't even run or test your program. That might seem like a bad thing but it's actually very helpful - it prevents a lot of bugs from making it into the final program.




In the case of EXODUS, any compiler errors are underlined in red and you can just hover over them to see the error message. The run buttons at the bottom are disabled until you fix all compiler errors.

Here, I hover over the 'instruction' MAGIC. Sadly, EXAs have no MAGIC instruction, and the compiler immediately tells me so. This is quite helpful when coming from another language, such as the one used to program chips by that automation company in Shenzhen you might've heard of.




In a similar vein, you can't jump to a label that isn't defined anywhere by a MARK instruction.

Anyway, back to the assignment itself.

Since this tutorial ramps up the complexity I'll try to take you step by step through my thinking process instead of just giving the solution all at once.




I first built the 'skeleton' of the code. I decided to go with two EXAs where one reads the file and sends data to the other who writes it.
XA grabs the file, copies the value into X, and then, as an example, forwards it to the communication register M and subtracts one for the next round.

Why use X as an intermediate? Because doing arithmetic such as SUBI directly on a file is very annoying. The file cursor keeps moving forward and is never where you want it to be.

Anyway, for now XB goes to the OUTBOX host and puts the value it gets from M into a newly created file.

Now, just copy-paste that subtraction-and-copy code 9 times and we're done, right? Not quite. Since the starting number is different for each test, that would never work. It would also make the program size huge. Let's write a loop!




I have two loops in place now. XA does the same it did before, but after subtracting 1 from X it checks if X is less than 0. If that is NOT the case, it jumps back to LOOPSTART. If it is, we know it's done (because it just sent 0 to the other EXA, then subtracted 1, so it's sitting at -1 now). It WIPEs the file and self destructs as it runs out of instructions.

Note that both the MARK instruction and the empty lines never use up any cycles. The empty lines help with code readability and the MARK is exactly that, just a bookmark. It doesn't "do" anything. The FJMP instruction does use a cycle, though.

XB has a loop too, and as you can see I named the mark LOOPSTART as well. That's fine - an EXA only knows about its own code, it won't suddenly start running another EXA's code. Anyway, this loop is very simple. It copies the value it gets from M into the file, and will do so repeatedly. Since there's no TEST, T is always zero, and FJMP will always make it jump back.




The resulting file is exactly what I need! However, XB gets stuck in this case. Once XA is done, the next COPY M F instruction in XB will wait forever for a message and never get one. So I need to do a bit more.




This should solve it. The loop in XB is now conditional as well. It only jumps back if X does not equal 0, otherwise it tries to run the next instruction, doesn't find one, and self-destructs.
Again I decided to use X as an intermediate because I run into the same annoyance of the file cursor being in the wrong place if I do a TEST on F directly.

Let's test the program.




Both EXAs are set up where they need to be, XA is about to send and XB is about to receive.




The EXAs are at their first TEST. Since for neither of them the test is true, they jump back to the start of the loop.




XA is ready to send the next number, which is one less than the last one: 8.




The loops repeat a whole bunch of times, writing a new number to the file every round, until only the 0 is left to write.




That's done now, and in the last loop, both EXAs' tests are now true, so the FJMP does not jump back to the loop, but causes the EXAs to finish.




And I'm left with nothing but the correct file.







As you can see we can do (much) better on every count. That's not surprising - there are many ways to optimize loops like this.




This is the test run data screen at the end. For every test run, it shows the number of cycles and the activity. You can see the cycles differs quite a bit. That's because the EXAs have to go through more loops if the starting number is higher. The value shown on the leaderboard is the worst value of all 100 test runs.

So, how can we improve this?

Let's start with the most straightforward improvement: We can drop the activity from 3 to 2 by switching to a one-EXA solution. Maybe that improves other stats too.




This EXA GRABs the file in the INBOX, copies the one value to its X register, then WIPEs the file and continues on to the OUTBOX. There it MAKEs an empty file, copies X into the file, subtracts 1 from X, copies that into the file, and repeats until X is less than 0.




This change improves all stats significantly.




And this was another idea I had. We keep two EXAs, however the first EXA only sends the individual value from the file to M, and the second handles lowering the value and writing it to the file repeatedly. Since the communication through M took a lot of cycles this is a huge improvement compared to the other two-EXA solution.

This solution uses 406 cycles, has size 13 and the activity is of course 3 again.

That's one cycle lower than the one-EXA solution but worse, size and activity-wise.

Luckily, the game keeps track of each leaderboard separately. So currently it says my best solutions have 406 cycles, size 11 and activity 2. You don't need to optimize all 3 in the same solution!

Anyway, apparently better solutions are possible. Some people solved it with size 12 and they got the cycle count under 200.

I'm not sure what they are. For the cycle count I suspect they did something like hardcode a bunch of COPY 5 F; COPY 4 F; COPY 3 F; etc. and then using a whole bunch of conditional jumps to decide where to start, avoiding the looping code altogether and requiring less TESTs overall.

Since we're out of tutorial mode now, I will make a follow-up post containing the full instruction sheet of the EXAs. We've seen most of them already anyway. Feel free to use that to suggest further improvements. Also, with that instruction sheet, perhaps you can figure out how to reduce the activity number in the previous tutorial.
If you're not that familiar with programming and don't get happy from reading instruction sheets, feel free to skip that post. You'll see the instructions in use before too long.

But before that, let's go check on Ember.

Nice work.
I knew you could do it.




And the intro to the next assignment.

So you want to know who I am.
I will reveal this information.
Let us discuss it over a pizza...
A free pizza.
I want to see you use your regained skills first.




Next time... pizza, apparently. Please vote for both questions.

Carbon dioxide fucked around with this message at 16:43 on Dec 18, 2021

Carbon dioxide
Oct 9, 2012



EXA Language Reference Guide




(click to enlarge)

You can also quickly find the reference guide in the second post.

An overview of all the instructions we haven't seen yet:

DIVI - Similar to the ADDI/SUBI/MULI arithmetic instructions we've seen. DIVI does a division, rounding down to the nearest whole number.
MODI - Another arithmetic instruction, for the modulo operation. Basically, this gives the remainder of a division. For example, 11 / 3 = 3 remains 2. So DIVI 11 3 returns 3, while MODI 11 3 returns 2.
SWIZ - "Swizzles" the value. This is a very unusual instruction that allows you to rearrange or extract digits of a number.

JUMP - Unconditional jump. This jumps to a MARK label regardless of the state of the T register.

REPL - Creates a copy of this EXA (so with the same code), and have the copy start executing code from the MARK label following this instruction.
KILL - Destroys another EXA in the same host as this EXA.

HOST - Copies the name of the host (such as INBOX) into a register.

MODE - Switches the M communication mode between global and local.
VOID M - Reads a value from M but doesn't store it anywhere.
TEST MRD - If this EXA could read a message from another EXA through the M register this cycle, sets T to 1, otherwise 0.

FILE - Copies the ID of the held file (such as '200') into the given register.
SEEK - Move the cursor within the file, the number of steps given. E.g. SEEK 2 moves the cursor two forward and SEEK -3 moves it three steps backward. SEEK -9999 moves the cursor to the beginning of a file and SEEK 9999 to the end.
VOID F - Deletes the value at the cursor from the file.
TEST EOF Sets T to 1 if the file cursor is at the end of the file, 0 otherwise.

NOTE - This is not an instruction, but a way to leave notes to explain the code to yourself. It does not take up any cycles.
NOOP - Do nothing for a cycle. Can be used if this EXA needs to wait for another EXA.
RAND - Generate a random number.

Carbon dioxide fucked around with this message at 16:48 on Dec 18, 2021

idhrendur
Aug 20, 2016



I was waiting for the reference because one optimization is obvious: use T as the working register and skip the check. You're waiting for the value to be zero anyways, and TJMP will implicitly do that check for you.

Carbon dioxide
Oct 9, 2012



idhrendur posted:

I was waiting for the reference because one optimization is obvious: use T as the working register and skip the check. You're waiting for the value to be zero anyways, and TJMP will implicitly do that check for you.

Good point!

I specifically didn't mention yet that TJMP activates for any non-zero value of T, not just 1 (while FJMP only activates on 0). That is: any non-zero value is considered "True".

In this solution


Changing XB from what it is to:

code:
LINK 800
LINK 800
MAKE

COPY M T

MARK LOOPSTART
COPY T F
SUBI T 1 T
TJMP LOOPSTART
COPY T F
This drops the cycle count to 304 cycles.

Note that that final copy is necessary to get the final zero in the file.

Doing the same with the single EXA solution gets us to 305 cycles btw.

The size is still 11, and according to the histograms, 10 is possible, and so is a sub-200 cycle account. If anyone has any thoughts on how to get there, please share them.

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.



edit: wrong tab whups

Carbon dioxide posted:

The size is still 11, and according to the histograms, 10 is possible, and so is a sub-200 cycle account. If anyone has any thoughts on how to get there, please share them.
To reduce solution size you can combine the "we need a file containing N+1 entries" with "we need to retrieve N from a file" into a single step by using ADDI F 1 [?] instead of COPY F [?] and changing the order slightly, e.g. with a single exa
code:
LINK 800
GRAB 200
LINK 800
ADDI F 1 T
WIPE
MAKE
MARK WATT
SUBI T 1 T
COPY T F
TJMP WATT
Size 10
Cycles 307
Activity 2


edit N+1

Another thing you can streamline is the fact that the TJMP step itself takes a cycle, so if you can pack more useful operations into a given execution of the loop the exa wastes less time doing its logic check. This ugly abomination does batches of 2 variables but as an ugly kludge has to work around the fact that it even numbers and odd numbers behave differently (it does this by adding another dummy entry at the beginning, then erasing it once the iterator has finished doing its thing)
code:
LINK 800
GRAB 200
LINK 800
ADDI F 1 X
WIPE
MAKE
MODI X 2 T
TJMP EVEN
COPY X T
MARK LOOPA
SUBI T 1 F
SUBI T 2 F
SUBI T 2 T
TJMP LOOPA

HALT

MARK EVEN
ADDI X 1 T
MARK LOOPB
SUBI T 1 F
SUBI T 2 F
SUBI T 2 T
TJMP LOOPB
SEEK -9999
VOID F
Cycles: 212
Size: 24
Activity 2

:doh: A couple of further tweaks actually make it a lot easier just to split it into two loops, by varying the number (in this case 8) you can change the batchsize
code:
LINK 800
GRAB 200
LINK 800
ADDI F 1 X
WIPE
MAKE
MODI X 8 T
SUBI X T X

FJMP EVEN

MARK LOOPA
SUBI T 1 T
ADDI X T F
TJMP LOOPA

MARK EVEN
COPY X T
MARK LOOPB
@REP 8
SUBI T @{1,1} F
@END
SUBI T 8 T
TJMP LOOPB
Cycles 143
Size 26

...which is both faster and also slightly less horrendously inelegant, but I dunno if you really want to get into @rep structures just yet.

silentsnack fucked around with this message at 03:29 on Dec 19, 2021

Quackles
Aug 11, 2018

Pixels of Light.




To get the cycles much lower than the default, you'll have to be clever. Specifically, you have to make a loop with only two instructions in it.

That sounds impossible, but what if you didn't do the loop jump every cycle? In fact, what if you did it as little as possible?

In that case, you'd have to have something else to stop you at 0.

So, the solution: split your EXA into two. One monitors the other, and force-quits it after it's written '0'. We know this works because every expression takes the same amount of time.

code:
LINK 800
GRAB 200
COPY F T
LINK 800
REPL WRITER
;FALL THROUGH - TIMER
MARK TIMER
@REP 8
SUBI T 1 T
FJMP BAIL
@END
JUMP TIMER
MARK BAIL
WIPE
NOOP
KILL
HALT

MARK WRITER
MAKE
MARK TIMER2
@REP 8
COPY T F
SUBI T 1 T
@END
JUMP TIMER2 
;LOOPS INFINITELY
;DROPS FILE WHEN KILLED
In case you haven't seen it yet, REPL splits your EXA into two. The copied EXA jumps to the new address, with the same register values, but (critically) not carrying a copy of any file the first one had.
The original EXA's control falls through the REPL instead.

So, once the value in the original file is copied into T, this EXA splits. The original EXA, the reader, subtracts from T and jumps to BAIL if it's 0. Once ther,e it clears its file, waits for the last write to clear, then KILLs the other EXA.

The other EXA, the writer, subtracts from T and writes to F. It does this forever until KILLed.

Both EXAs use loop unrolling (@REP 8 repeats the lines in the block 8 times) to avoid jumping around the loop when not necessary. I can't unroll any further without the programs being over the 50 instruction limit and ineligible for evaluation. (The game will let you continue but you won't get on the histograms).

This is a direct tradeoff of program space for cycles; final stats are 219 cycles, 48 size, 3 activity*.

*KILL counts as 1 activity.

Carbon dioxide
Oct 9, 2012



Very nice stuff!

What I'm gonna do is discuss your solutions in my next LP update. I'll clearly section it off from the new puzzle so that people who are mostly here for the plot can just skip over that while we can nerd out over optimizations.

Quackles
Aug 11, 2018

Pixels of Light.




OK, so I was inspired by silentsnack's trick with the @{1,1} and made my version which uses a similar trick.

code:
LINK 800
GRAB 200
LINK 800
COPY F X
WIPE
MAKE

MARK BOUND
@REP 8
SUBI X @{0,1} F
@END
SUBI X 8 X
TEST X > 7
TJMP BOUND

COPY X T
COPY T F
FJMP FINAL ;T = 0?

MARK LASTCALL
SUBI T 1 T
COPY T F
TJMP LASTCALL

MARK FINAL
The range of numbers Ghast tests you with goes from 9 to 99. Because of this, we split the program into two parts: one that removes batches of 8 numbers at a time (and always runs at least once, so we can put the test at the end), using loop unrolling to write 8 numbers in 8 instructions.

The second part is a regular loop that jumps or falls through to end-of-instructions once 0 is written. It's quicker not to unroll the loop here.

152 cycles, 26 lines, 2 activity. I'm happy with that.

Carbon dioxide
Oct 9, 2012



Part 6 - Euclid's Pizza

Thanks for all the posts about optimizations! What I'll do is discuss them in the first part of new updates. If you like to nerd out about that and get a deeper comprehension of the code, read on.

I will try to explain all the submissions as clearly as I can. Even if you're not that familiar with programming, give it a try! Perhaps my explanations help.

In this part, I need to go into quite some detail as your ideas introduced a lot of new concepts.

If you want to skip past all that because you're here mostly for the plot and new puzzles, search for the next occurrence of the word "pizza" in this post.


=== Trash World Inbox ===

Alright, before we dive into your suggestions, let's jump back for a moment to Tutorial 3.



In my original solution we got it down to 9 cycles, with size 12 and activity 4. Now that we have the full language reference, we can get the activity further down.



The solution is the REPL command. It replicates the EXA, and the replicated one starts processing from the given label (in this case WRITER).
By doing this after the first LINK, the total number of LINK operations is reduced to 3.





Here is the simulation just after the REPL instruction. You see the new EXA has the same name as the old but with a number appended. And it starts executing below the WRITER mark, while the original EXA just continues below the REPL instruction.

I realize now I named the mark wrong - the 'writer' actually does the reading. Oh well.



We got the activity down to three, but the cycles and size increased a bit. If you're wondering why that says "Unchanged", it's because I tend to run the simulation multiple times trying small tweaks and it only compares your new score to the last run.

I could've put a HALT instruction just before the WRITER mark. It's not really necessary. After its last copy to F instruction, the original XA will skip the MARK (which doesn't take a cycle), try to execute LINK 799, find there's no 799 link id from its current position, throw an error and explode.

Errors that destroy an EXA can be surprisingly useful, the Zine even has a page on it. I'll show it below when we get to the new assignment.

Using a HALT here has some limited use - destroying an EXA through an error takes two cycles (one to show the error and one to explode), while a HALT does it in one. So adding a HALT would save one cycle but also increase the size by 1.

Either way, we don't need to do this because since each score is tracked separately, with the original solution and the REPL solution combined, we got the best score in each of the histograms now.



And with that, let's go to Tutorial 4 and the optimizations y'all sent in.

Looks like I'll have to go into a lot of detail this time because you chose some strategies we haven't seen at all yet.

idhrendur posted:

I was waiting for the reference because one optimization is obvious: use T as the working register and skip the check. You're waiting for the value to be zero anyways, and TJMP will implicitly do that check for you.
Yes, so what you need to know for this is that TJMP activates for any non-zero value of T, not just 1 (while FJMP only activates on 0). That is: any non-zero value is considered "True".

Changing this solution from the last update...



... to this solution.



This drops the cycle count from 406 to 304.

Basically what this is doing is, it subtracts 1 from the value in T every loop, then if T is still greater than 0, it jumps back to LOOPSTART. The final COPY is necessary to get the required zero at the end of the file.

Doing the same with the one-EXA solution gives us a count of 305 by the way.

silentsnack posted:

To reduce solution size you can combine the "we need a file containing N+1 entries" with "we need to retrieve N from a file" into a single step by using ADDI F 1 [?] instead of COPY F [?] and changing the order slightly, e.g. with a single exa
code:
LINK 800
GRAB 200
LINK 800
ADDI F 1 T
WIPE
MAKE
MARK WATT
SUBI T 1 T
COPY T F
TJMP WATT
Size 10
Cycles 307
Activity 2
This one starts by storing a value that's one higher than what we need. Since that can be done in a single ADDI instruction that replaces the COPY, it doesn't change the size. silentsnack reordered the loop so the SUBI happens before the COPY. That way we still write the correct values to the file - but we're still inside the loop when T becomes zero, so we write the zero to the file as well. That extra copy operation is no longer necessary and the size drops to 10.

We've now minimized both the size and activity - all that's left is the cycles and since we don't care about size or activity anymore we can use every ugly trick you can think of.

silentsnack posted:

Another thing you can streamline is the fact that the TJMP step itself takes a cycle, so if you can pack more useful operations into a given execution of the loop the exa wastes less time doing its logic check. This ugly abomination does batches of 2 variables but as an ugly kludge has to work around the fact that it even numbers and odd numbers behave differently (it does this by adding another dummy entry at the beginning, then erasing it once the iterator has finished doing its thing)
code:
LINK 800
GRAB 200
LINK 800
ADDI F 1 X
WIPE
MAKE
MODI X 2 T
TJMP EVEN
COPY X T
MARK LOOPA
SUBI T 1 F
SUBI T 2 F
SUBI T 2 T
TJMP LOOPA

HALT

MARK EVEN
ADDI X 1 T
MARK LOOPB
SUBI T 1 F
SUBI T 2 F
SUBI T 2 T
TJMP LOOPB
SEEK -9999
VOID F
Cycles: 212
Size: 24
Activity 2
I think silentsnack explains this one quite well. In my own words: it writes two values to the file every loop. E.g, if the value in T is 10, it writes 9, 8 and then updates T to 8. However, because you're only testing every 2 values, you'd run into trouble handling odd numbers. You'd check T at 1 (which is True), then next loop, T contains -1 (which is also True), and the loop would never end.

This is handled by splitting the code into two and using a MODI operation to find if the number is even. MODI X 2 equals 0 for even numbers, 1 for odd numbers. Since the MODI operation is done on the original value + 1 (there's an ADDI on the fourth line), it becomes the opposite so we have to jump to EVEN if the value is 1 (= True). In that case one more is added to the value to make sure the loops exits correctly, then SEEK -9999, VOID F is used to delete the first value of the file, which was one too high.

So, for each test run it runs EITHER the even, or the odd code. Never both in the same run.

Meanwhile, Quackles was working on a slightly different solution.

Quackles posted:

To get the cycles much lower than the default, you'll have to be clever. Specifically, you have to make a loop with only two instructions in it.

That sounds impossible, but what if you didn't do the loop jump every cycle? In fact, what if you did it as little as possible?

In that case, you'd have to have something else to stop you at 0.

So, the solution: split your EXA into two. One monitors the other, and force-quits it after it's written '0'. We know this works because every expression takes the same amount of time.


Here is Quackles' actual program. It looks different from the code example in their post and I'll get into why that is in a bit.

The lines starting with a ; (semicolon) are just notes, like the NOTE "instruction". They help us understand the program but the EXAs ignore them entirely, their size is 0 and they don't take up any cycles.

First, let's dig into how it actually works.

It uses two tricks:
- The first is "loop unrolling". Instead of doing jump instructions we just repeat the code of the loop a bunch of times. Since each jump instruction takes a cycle, this can save a lot of cycles in a simple, but ugly way. In fact, silentsnack's solution did this as well by putting 2 steps in every loop.

Loop unrolling is actually a common optimization technique in real programs, although usually the programmer doesn't have to think about it, because the compiler is programmed to make an informed decision when this is worth it and changes the compiled program on the fly.

You see both of the loops (The loops starting with the TIMER and TIMER2 marks) are repeated 8 times and then use a jump. It would work just as well, and save even more cycles, to repeat them more times before the jump, as long as you have a way to stop looping once the file is written. But, doing so would push the size over this assignment's limit of 50. Submitting a solution like that counts as finishing the assignment - but is not eligible for the leaderboards at all. So we have to stop at 8. Still, that means you save seven out of each eight jump cycles, a huge improvement.

- The second improvement is using two EXAs, made through a REPL instruction. REPL copies all code, the state of the X and T registers, but, importantly, NOT the file the original is holding.

The first EXA loops through TIMER and checks every step if T is zero (in which case it jumps to BAIL). The second EXA loops through TIMER2, copying a new value to the file every step. It has an unconditional JUMP so it would loop forever.

This takes less cycles than the previous solutions because each 'loop' is only two cycles (SUBI / FJMP for the first EXA and COPY / SUBI for the second, as compared to the three-cycle SUBI / SUBI / TJMP originally.)

It does mean you have to stop the infinite loop somehow, and that's what the first EXA is for. As soon as T hits zero, it jumps to BAIL.
It then has to wait for a bit to allow the second EXA to write the last zero. Since it has to wait anyway, it can use this free cycle to WIPE the original file it was still holding, and then it uses KILL to kill the other, infinitely looping EXA, after which it HALTs itself.

The NOOP instruction turns out to be necessary in case the starting number is divisible by 8 - then the second EXA needs one more cycle before it writes the 0 because it's jumping back to TIMER2. It does no harm in other cases because the second EXA spends the additional cycle doing a harmless SUBI to T.

The final result is 219 cycles, 48 size (but who cares) and 3 activity (since KILL counts for activity).

Now, to go back to Quackles' actual code example.



We haven't seen the @REP 8 and @END instructions before, they aren't explained until the second edition of the Zine. They are macro instructions. In short, that means they tell the compiler to rewrite the code in some way before the program even starts. @REP 8 means that the lines of code following that instruction until the @END instruction, should be repeated 8 times. That is, it does the loop unroll for you.

REP macro instructions take up no cycles (since they are done before the program even starts), but they cannot make use of any registers or other variables (since they are done before the program even starts), only hardcoded numbers.

You also can't use REP to cheat the size limit - it counts the size after unrolling. In fact, as soon as you press run on this code, EXODUS will show the code after the REP instructions are processed, which is the screenshot I used to explain the solution above.

So, REP can't win you any cycles or size - the only thing it really does is save you from copy-pasting a bunch of code, making the result a bit easier to read.

Let's go to the next improvement silentsnack came up with:

silentsnack posted:

:doh: A couple of further tweaks actually make it a lot easier just to split it into two loops, by varying the number (in this case 8) you can change the batchsize
code:
LINK 800
GRAB 200
LINK 800
ADDI F 1 X
WIPE
MAKE
MODI X 8 T
SUBI X T X

FJMP EVEN

MARK LOOPA
SUBI T 1 T
ADDI X T F
TJMP LOOPA

MARK EVEN
COPY X T
MARK LOOPB
@REP 8
SUBI T @{1,1} F
@END
SUBI T 8 T
TJMP LOOPB
Cycles 143
Size 26

...which is both faster and also slightly less horrendously inelegant, but I dunno if you really want to get into @rep structures just yet.
The SUBI T @{1,1} F line is a special syntax you can use together with REP. The @{1,1} is substituted by a number at runtime. The initial value will be the left number (1 in this case), then every next value will be the previous one increased by the right number.
In other words, this unrolls into
code:
SUBI T 1 F
SUBI T 2 F
SUBI T 3 F
And so on.

Anyway, this is a very neat solution. It starts the same as their last solution but then it does a MODI X 8 T. T now contains the remainder of dividing the original value (plus 1) by 8. Then it deletes the remainder from X, meaning X will now contain a value that can be divided by 8.

If the remainder was already 0 it skips a step and jumps directly to EVEN. Else, it gets into LOOPA, where it writes the sum of the remainder and X (so the original value) to the file, reduces the remainder by 1, and repeat. In this loop you write all the values above the current value of X.

After that, whether working through a reminder was necessary or not, the program goes to MARK EVEN and writes 8 values to the file per LOOPB cycle. We know for sure the test will trigger at the right time because we made sure to not go to this loop before the value is divisible by 8.

Finally, Quackles submitted this solution:

Quackles posted:

OK, so I was inspired by silentsnack's trick with the @{1,1} and made my version which uses a similar trick.

code:
LINK 800
GRAB 200
LINK 800
COPY F X
WIPE
MAKE

MARK BOUND
@REP 8
SUBI X @{0,1} F
@END
SUBI X 8 X
TEST X > 7
TJMP BOUND

COPY X T
COPY T F
FJMP FINAL ;T = 0?

MARK LASTCALL
SUBI T 1 T
COPY T F
TJMP LASTCALL

MARK FINAL
The range of numbers Ghast tests you with goes from 9 to 99. Because of this, we split the program into two parts: one that removes batches of 8 numbers at a time (and always runs at least once, so we can put the test at the end), using loop unrolling to write 8 numbers in 8 instructions.

The second part is a regular loop that jumps or falls through to end-of-instructions once 0 is written. It's quicker not to unroll the loop here.

152 cycles, 26 lines, 2 activity. I'm happy with that.
It is indeed quite similar to the previous one, just handling the remainder at the end instead of at the start. And perhaps the TEST X > 7 is a bit easier to read than a test based on MODI.

As silentsnack said, you can easily change the size of the loop by changing the 8s. That works in either of the solutions. I played around a bit with that and it looks like 8 is optimal. For both solutions you can't go too high because the code can't handle an initial number smaller than the loop size. And other loop sizes speed up some tests but makes the slowest test run (which is used for cycle count) slower.

Theoretically you could start with another split in the code path, to use a larger loop for larger initial numbers only. But that means you need at least two unrolled loops, probably pushing the size past the limit. And no matter what you choose, you always run into cases where you need to handle the biggest remainder possible, which will take longer for larger batch sizes, so I don't think it's possible. And the community seems to agree with me on that, since silentsnack's 143 cycles solution is the best anyone's gotten.




=== Euclid's pizza - Order System ===

Nice work.
I knew you could do it.




Looks like everyone was so busy optimizing code that they forgot to vote. No worries, I'll use my trusty three-sided dice again.

Stop that.

But you're awesome!
This is more talk designed to further excite your prefrontal cortex.
Now it's time to do some real hacking.


Finally.





I could use some pizza. How're we gonna do that?

So you want to know who I am.
I will reveal this information.
Let us discuss it over a pizza...
A free pizza.
I want to see you use your regained skills first.



Okay.

Great.
I am looking forward to this.



New :siren: OST: Code and Registers

This actual business system already looks a lot more complicated than the tutorial assignments.

Our assignment is:
- Append your order (file 300) to the end of the order list (file 200)
- Note that all orders, including yours, will consist of exactly five keywords.




While we're here, let's poke around in their files a bit.

I'm not entirely convinced those are actually the Pythagorean Theorem and Zeno's Paradox but what do I know...



Anyway, I have to copy the data from our file 300 and add it to the end of their file 200. Doesn't sound too complicated, let's get started.



The first EXA grabs the file with our order, and sends the data one by one over the M register.

The second EXA goes into the order system, grabs the file with their orders list, uses SEEK 9999 to jump to the end of the file and writes the data from M to the file.

I don't even need to bother destroying our file 300, since it's sitting in my home host, it doesn't count as leaving a trace.

Of course, I could use a loop and loop 5 times over a single copy command. But that would involve:
- Keeping a counter that is increased every round, then checked every round, and then a conditional jump, and a mark for the jump to go somewhere.
- Or a check in XA if it's at the end of the file, in which case it tells XB to die, which is also a bunch extra logic.

If you read through the Trash World Inbox section of this update you've seen that sometimes, repeating code is the simplest solution, and it's the case here too.



As it turns out, this is actually the best solution possible for this assignment. The loop solutions require so much setup that they require as much lines of code, while costing more cycles. I'll take it!

Before we continue, what's that on the right side of the simulation?

You might've seen on page 7 of the Zine, those things such as #POWR are hardware registers. They're a way for EXAs to communicate with external hardware directly. In this assignment I don't need them, but we can certainly mess around with them.

Those #TEMP ones have widely different initial values. I guess one is just the room thermostat, one is for the freezer, and one is for the oven? The first #POWR register is for the lights, I don't know what the second one is for.

No, I can't put the place on fire, apparently there's limits on the #TEMP registers. But there is a Steam achievement associated with this assignment.



Flipping the lights on and off like this nets me the achievement PIZZA_PARTY: Throw a rave at the pizza parlor.

Time to enjoy pizza!
For you at least.
I'm not going to have any.
Guess why.



Uhhh.. you're far away?

I am an AI construct.
You know. Artificial intelligence.
Surprised?




Where's the option "I saw that coming a mile away"?

A little.

A little.
Okay.
I'll have to remember that.




Yeah, the zine is kinda nice, isn't it?

Speaking of, there's an interesting page about runtime errors.



So, a runtime error is completely different from a compile error, which we've seen before. An EXA with a compile error won't even run until you fix it. Compile errors often come from incorrect syntax. But a runtime error is using correct syntax in the wrong place. For instance, trying to GRAB file 200 while that file doesn't exist, or LINKing to a host that doesn't exist. If you do so, the EXA that tried to run that instruction is immediately destroyed, but at least you know that that file or host isn't there.

If you want some homework, consider how we could make use of this. We'll see it soon enough in future assignments though.

Anyway, looks like my pizza is here.



Pizza delivery...

It's Nivas again, except this time they're wearing a Euclid's Pizza uniform.
"Euclid's- a better pie, and we can prove it!"
The reference seems kind of obscure for a pizza joint.

Don't look too surprised.
I'm an independent operator. I handle a wide range of businesses.
Economy like this, you gotta hustle.
So here's your pizza... and here's your "other" package. I hope it helps.

Nivas hands me an unlabeled prescription bottle. It's clearly a knock-off.

Good work getting that money together.
If there's anything else you need, you know who to call.


Nice! Free pizza, and the first batch of the medicine. Exactly what I need.

Let's see what Ember has to say about that.

So about that left arm of yours.
The medicine stops your condition from spreading, but it can't fix things like that.
You'll need to take care of that yourself.




This choice seems a good place to end this update. Feel free to vote.

Carbon dioxide fucked around with this message at 15:30 on Dec 24, 2021

GuavaMoment
Aug 13, 2006

YouTube dude


Carbon dioxide posted:

As it turns out, this is actually the best solution possible for this assignment.

It's not, you can do it in 12 cycles. It's complicated. Glancing at my code it has something to do with storing two values of your order, using the CHEESE that's always there in the file, then transmitting the last two values. The rest is an exercise for the reader. :)

You wouldn't hack your own body?

Tatters
Jan 29, 2020


I just started this game fairly recently, it'll be neat to have someone actually good at this to compare my code against.

Also, I'd vote for "This is going to be weird" because things are about to get slightly confusing from a lore perspective.

megane
Jun 20, 2008





I was deeply disappointed to discover I couldn't set the ovens to 3000 degrees and burn down the pizza place.

Tatters posted:

Also, I'd vote for "This is going to be weird" because things are about to get slightly confusing from a lore perspective.
:emptyquote:

bewilderment
Nov 22, 2007
man what





This is going to be weird.

Hacking bodies is common in video games, though; you just normally do it with a weapon.

Quackles
Aug 11, 2018

Pixels of Light.




I vote for 'hack your own body'.

idhrendur
Aug 20, 2016



Quackles posted:

I vote for 'hack your own body'.

This!

Junpei
Oct 4, 2015

Cuz I'm a creep
I'm a weirdo
What the hell am I doin' here
I don't belong here

This is going to be weird.

omeg
Sep 3, 2012



Hack your own body. Because of course! :science:

Carbon dioxide
Oct 9, 2012



Part 7 - Mitsuzen HDI-10


=== Trash World Inbox ===

GuavaMoment posted:

It's not, you can do it in 12 cycles. It's complicated. Glancing at my code it has something to do with storing two values of your order, using the CHEESE that's always there in the file, then transmitting the last two values. The rest is an exercise for the reader. :)
Interesting. I attempted this but couldn't make it work. You could start with an EXA that stores the first two values in X and T, then REPLs, write those two into a file, and meanwhile another EXA grabs the "Cheese" from file 280. But no matter what I tried it would take more than 13 cycles.

Cloudmonkey98 posted:

You didn't give us two Qs, so I'll present thoughts about usage of Runtime errors instead as requested, including an interesting thought about the boring error of "Math on words"
Failure to locate a link or file, as you noted can be used in REPL set ups to halt machines when they run into code segments intended for clones, or for snooping around unknown spaces where things may be random(though I feel like thats the kind of behavior that'd get you caught by the system for illegal commands so I'm not sure its actually a great plan but if the game says its safe sure go ahead)
Depending on how "grabbing" a file held by another EXO behaves, failure to locate file or failure to have an F register to use could both be used in ways to manage baton passing files if need be

Math on Words however could be useful for semi-blind random cases involving files or hardware registers if you know certain key facts, eg if you're looking for a passcode and know its on one of these things, but the others have words, you could ADDI F 1 M and have the receiver just deduct the 1 after, the EXOs that find words instead of a number would promptly explode upon attempting ADDI instead of getting stuck hosting an M value transmission, I somehow doubt such a situation would arise, but the idea of using the fact that something is a word rather then a number as a fail switch strikes me is possibly of similar but less common use to failure to locate
Yeah, those are good points. I don't remember from the top of my head which of these we're going to see but we'll find out.

As for the system catching illegal commands - well, EXAs as sort of virtual robots making their way through a computer system is a bit of a stretch as it is, so I wouldn't worry about it that much. :)


=== Mitsuzen HDI-10 - Left Arm ===



Looks like someone else discovered the Dumpster Donuts recipe too.



This time two assignments pop up. Since my arm is hurting a lot I'll start with this one.

I'm not entirely sure if you need to do both to continue. On my initial playthrough I just did them in order and I'll do the same now.

So about that left arm of yours.
The medicine stops your condition from spreading, but it can't fix things like that.
You'll need to take care of that yourself.




One vote for Uhh..., four for This is going to be weird. and five for You mean, hack my own body?

You mean, hack my own body?

Yes, exactly.
If you can hack anything else, why not your own body?


...I feel like hacking computer programs is not quite the same as messing with living tissue.


New :siren: OST: EXA Power

Assignment:
- Read a value from the nerve connected to your central nervous system (CNS) and relay it to the nerve connected to your arm (ARM), clamping the value so that it never goes below -120 or above 50. Repeat ad infinitum.
- Since this task takes place inside a network you control - that is, your own body - it is not necessary to leave no trace. Your EXAs should be written to operate indefinitely.
- Note that #NERV is a
hardware register, not a file. You can use it directly in your code like any other register.
- For more information about the phage, see "Debugging the Phage" in the first issue of the zine.


So, I literally need to hack my own arm right now. The Zine has a couple pages on it.





Cool, I'm going to do a completely untested procedure on my own arm. Well, uh, let's go I guess.



When the assignment says the EXAs need to operate indefinitely, in practice this means every test-round checks if they get the first 30 values right and then assumes your program works as intended. As you can see, it expects the input values as output, except when they need to be 'clamped'.



This is my first attempt. XB is simple - it just goes to the ARM nerve, waits for messages on the M register, copies those to the #NERV register and jumps back to the COPY from M in an infinite loop.

XA does most of the real work: it copies the value from the CNS #NERV register into X, uses that to check if clamping either way is necessary, sends the correct value into M, and repeats that in an infinite loop.



It isn't the most efficient solution but it works.



As an initial improvement I moved one of the clamp checks to XB. Since now each EXA only has to do one check per loop, they can do some more cycles in parallel and the number of cycles drops to 184 (but the total size grew by one).



I quickly combined the two EXAs into one initial one that gets split by a REPL instruction. It's otherwise identical from the last one, but it reduces the activity to 5.

This was just to get a low activity score.



Back to the two EXA design, a small size improvement is possible if you reuse the COPY into M or #NERV for both branches. You'll have to make sure that the execution falls through the clamp MARK instruction to the COPY to make this work.



One trick we've seen before to reduce the cycles is by unrolling the loops, like so:



This runs at 163 cycles, a nice improvement, and it's as big as we can go with size 48.

If you're wondering why I'm not using the @REP instruction, it's because we only saw that in solutions from the thread. Not everyone might read the INBOX section so I won't use them in 'story' updates until we're introduced in-game. Feel free to use them in optimizations though.

I'm not storing the clamped values into X anymore because that takes more cycles, which is what I'm optimizing for here.

It's important to spread the loop unrolling equally between the EXAs because otherwise they'll just be waiting for each other and there won't be any gain.

Since all clamp jumps use the same clamp label, doing a clamp always resets the loop but that doesn't matter since we're not keeping track of any additional data in the loop. But... that gives me an idea. What if we do put the clamp code inside the loop so we can use fall-through instead of jumps sometimes?



I went through several different designs and got it down to 155 cycles. For both EXAs the loop works the same. It first loads a value into X and checks if it needs to clamp it. If so, it does and jumps back to the start of the loop. If not, it jumps to DONTCLAMP and sends the original value onward. In that case, it continues to the next COPY to X and test.

Every time it does not have to clamp it jumps back to that initial DONTCLAMP mark and gets another free go in the loop. If it does have to clamp it passes the FJMP, uses the clamped COPY, and goes down another layer. The FJMP seems to take one cycle whether it needs to jump or not, but since we don't need an extra JUMP statement to handle the case where FJMP doesn't trigger, it gives us basically free repeats, unless we get an unclamped value followed by 3 clamped values within the same EXA.

In fact, this doesn't ever happen. It turns out I can reduce the code significantly and still get a 155 cycle solution:



Cycles = 155, Size = 32.

So, it turns out unrolling the loop doesn't speed up the second EXA at all. Huh. It does matter for the first EXA though, but not for the reason I thought. There's no situation where you got two > 50 inputs in a row. Instead, if I remove one of the additional COPY - TEST - FJMP - COPY blocks, the number of extra cycles within a single test is equal to the number of times a < -120 input directly follows a > 50 output. Apparently without the unroll, the EXAs have to wait an additional cycle for the next M transmission in this specific case.

I did some more testing and learned some more things. Nothing to get me a lower cycle count directly, but maybe it'll help the thread find the next optimization.
- Removing BOTH of those repeated blocks in XA increases the cycle count to 184, consistently for all tests. Apparently then there's always a wait happening, and it's the same as in my earlier solution.
- Switching all FJMPs for TJMPs in XA and swapping COPY 50 M with COPY X M also increases the cycle count to 184, showing that this optimization truly depends on the free loop repeats in case of a DONTCLAMP.
- Swapping the 50 and -120 checks between the two EXAs has no effect on the cycle count whatsoever.

Anyway, that's how far I got, I'll leave it to the thread to find further optimizations. Score to beat: Any of 155 cycles; 22 size; 5 activity.

By the way, there's the first part of some sort of story in the Zine. Thought I'd share it with you all.

Click the images for higher resolution.






I'm done with this assignment.

This hotfix should keep you useful, at least for a little while longer.
I'm glad I don't have a body.




And the intro for the next assignment.

You like snacks, don't you?
You don't have to answer that.
I know you like snacks.
That's why we're going to hack a snack factory.




Two questions to vote on.

Adbot
ADBOT LOVES YOU

Inexplicable Humblebrag
Sep 20, 2003






"you get used to it"

and

:geno: ok

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