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
berryjon
May 30, 2011

I have an invasion to go to.
What do you really want?
I thought he might like....


Given the actual speeds that the EXAs work at, I think anyone watching TV might have barely seen a blip or two, thinking it was a transmission error to a glitch for a second before their movie played.

Adbot
ADBOT LOVES YOU

Carbon dioxide
Oct 9, 2012

berryjon posted:

Given the actual speeds that the EXAs work at, I think anyone watching TV might have barely seen a blip or two, thinking it was a transmission error to a glitch for a second before their movie played.

Yeah, that's never made completely clear. If you pause the simulation at any point the movie footage just keeps playing (well, repeating). Same thing with the CCTV cam footage for the ATM hack, for instance.

GuavaMoment
Aug 13, 2006

YouTube dude
Hacker battles are a neat idea, buh ehh.....it's seemingly impossible to make a robust solution. It's like trying to optimize rock paper scissors, you're always going to be vulnerable to one tactic when using another.

Tulip
Jun 3, 2008

yeah thats pretty good


GuavaMoment posted:

Hacker battles are a neat idea, buh ehh.....it's seemingly impossible to make a robust solution. It's like trying to optimize rock paper scissors, you're always going to be vulnerable to one tactic when using another.

feels more like they put them into the game to show that they could, competing over solution efficiency on a leaderboard feels way more satisfying

GuavaMoment
Aug 13, 2006

YouTube dude
Huh, you know I tried searching backwards for the keywords at one point since I noticed the same issue - one test has all the keywords near the end. It didn't work out for me. I'm shocked it works at all, the search is 50% slower due to the extra SEEK command.

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


What do you really want?
I'm not sure

My zines and manuals have shipped but no delivery date yet. Work faster please, UPS

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


Nth Doctor posted:

What do you really want?
I'm not sure

My zines and manuals have shipped but no delivery date yet. Work faster please, UPS

They're here!

Carbon dioxide
Oct 9, 2012

Part 18 - TEC Redshift - Dev kit

=== Trash World Inbox ===

Cloudmonkey98 posted:

At no point did the instructions say you lost points for your opponent's movie playing, just for you touching them, or trying to hide them in your Host room, since the enemy can't access that area, the instructions aren't incorrect

This is a really interesting mode that you can do some fun with I imagine, competing into increasingly complex and esoteric counter-solutions seems like a wild trip, and then at some point someone undermines it all with regressing to basic solutions, like a really basic counter to your solution for your friend you mentioned would be to just wait a few cycles, the Exas would KILL themselves and you could walk in freely
Huh. reading back, you're right about the instructions, my bad.

As for the hacker battles, I agree with GuavaMoment here:

GuavaMoment posted:

Hacker battles are a neat idea, buh ehh.....it's seemingly impossible to make a robust solution. It's like trying to optimize rock paper scissors, you're always going to be vulnerable to one tactic when using another.

Nth Doctor posted:

They're here!
Neat! I have the digital copy of Zach-Like. It's free, and it contains all sorts of behind-the-scenes information of Zachtronics game design and even some early games and prototypes.

Since it doesn't really make sense to talk about optimizations for the hacker battles, let's jump straight into the new update.


=== TEC Redshift - Development kit ===

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




Three votes for the second option.

But what do you really want?

All I've wanted is for you to do a little hacking for me.
That's it. Really.


Well, that doesn't explain anything.



Leafing through the zine I found the letters page.

Some interesting stuff there. First of all, heh, the letter Ember made me edit actually got printed in the zine. The original writer is in for a bit of a shock. Also, the tip about the KGOG tv station is probably where mutex got the number for the modem through which we did our hacker battle.

I also like the reference to "red boxes" and "blue boxes". They were real things. Back in the day phone exchanges were controlled through specific tones (nowadays it's usually a digital signal of some kind). In the USA, red boxes could be used to make an exchange think you put a coin in a pay phone, so it would let you place a call for free. Blue boxes could be used to place long-distance calls and bill them to some other number.



Anyway, I got this developer Redshift kit from Ghast, let's see if I can do anything with it.

Why do you think Ghast gave you this?



Two out of three votes for "I'm not sure".

I'm not sure.

Does he get something out of it?
I suppose he enjoys helping people.
Such a nice guy.
Too bad the dev kit is password protected.
He should have thought of that.
Better not let that stop you...


Yeah, no worries Ember, we'll just jailbreak this thing real quick.

There's a whole section about the Redshift in the zine, but most of it is about how to develop games for it. We're not quite there yet, but here's the frst page just so you have an idea of what we're dealing with.



The small print under the ad says: "Batteries not included; 3D mode not intended for use more than 15 minutes at a time; EXA is a registered trademark of Axiom, Inc. Used with permission."

An early attempt at a 3D handheld where using the 3D mode for too long would cause problems? This thing seems to be some sort of mix of a Nintendo Game Boy and a Virtual Boy.


OST: Code and Registers

No files or anything in this thing. Our assignment simply says:
There is an unknown three-digit code (such as 4-7-3) that, when entered one digit at a time into #PASS, will unlock the link between debug and secret. Find the three-digit code and create a file in your host that contains the code as a sequence of three values, followed by the development kit's RDK ID.

Okay, simple brute-forcing it is.



Entering some numbers into #PASS makes them appear on the little display in the secret host. If the code is wrong nothing will happen, and the fourth digit is simply the start of a new attempt. Any negative numbers or multi-digit values are ignored by #PASS.

Well, we got an instruction to grab specific digits from a number, why not use that?

code:
LINK 800

MARK TOP
SWIZ X 1 #PASS
SWIZ X 2 #PASS
SWIZ X 3 #PASS
ADDI X 1 X
JUMP TOP
The SWIZ function takes a mask as second operand. If the mask is 0002 (or just 2) it says "take 0 for the thousands, hundreds, and tens place, and take the value from the input's tens place (second digit from the right) for the output's ones place." The Language Reference Guide in the second post has some examples.

Since the #PASS expects digits from left to right while this takes the input from right to left, I actually enter the numbers in reverse. It shouldn't matter, it will try all numbers anyway, just in a different order. But since I need to store the password I'll swap the SWIZ calls around so I get the right password in X.

This unlocks the secret host, but this EXA keeps going forever. The #PASS register keeps accepting digits even after entering the right password.

I need to somehow stop this EXA at the right time, save its password, and go get that id from the secret host. Let's first see what we can find in the secret host, now that I unlocked it.





The link id between the debug and secret hosts is simply 800 again. There's four files in there: two core dumps, some game's save file, and a file containing the RDK id.



This is my first working solution. After some trial and error I decided that while a multi-EXA solution might be faster, it's gonna be hard to get the passcode out of the initial EXA at the right time. So I went for a single-EXA solution. Every loop, it tries to send a replica into the secret host. If the link is closed, the replica dies immediately.
Otherwise it gets the ID from the file. Then it needs to explicitly DROP the file (if you LINK an EXA holding a file with a lock icon it dies).

It KILLs twice (because by the time it gets back, the original had just enough time to execute a new REPL instruction), then goes back to the home host to write the file (which contains each digit of the password and then the ID).

This runs quite slow at 5959/22/11.

I tried to output it as a gif, but since it shows all digits being entered on the password display, the result is over 10MB and over 2 minutes. It also crashed my game when I tried to go back to editing afterwards. Don't try this at home.

Anyway, getting the activity down should be a question of minimizing LINK and KILL instructions.

We don't need to LINK back home with an EXA that waits for M signals:
code:
;XB

MAKE
COPY M F
COPY M F
COPY M F
COPY M F
And to get rid of the KILL, the original XA needs to know when to stop. Since I'm using M now, the MRD test works.
code:
;XA

LINK 800

MARK TOP
TEST MRD
TJMP END
SWIZ X 3 #PASS
SWIZ X 2 #PASS
SWIZ X 1 #PASS
REPL TRY
ADDI X 1 X
JUMP TOP

MARK TRY
LINK 800
GRAB 199
SWIZ X 3 M
SWIZ X 2 M
SWIZ X 1 M
COPY F M

MARK END
It's important to have the TEST MRD when the replica is already sending on M, but before XA can do another REPL (since that'll cause a LINK). This solution times it right and runs at 7938/23/2.

Next, let's look at cycle count. As I already said, if you swap around the SWIZ instructions, you basically change the order in which you test the passwords. Since I use the same SWIZ to write the data to the file I can easily try all permutations. Turns out 1,3,2 is the fastest at 5821 cycles, as compared to the 5959 solution.

But that's just a minor optimization. I'll need to do much better.

A basic loop unroll gets me to 5020/47/11.

code:
LINK 800

MARK TOP
@REP 6
SWIZ X 1 #PASS
SWIZ X 3 #PASS
SWIZ X 2 #PASS
REPL TRY
ADDI X 1 X
@END
JUMP TOP

MARK TRY
LINK 800
GRAB 199
COPY F T
DROP
LINK -1
KILL
KILL
LINK -1
MAKE
SWIZ X 1 F
SWIZ X 3 F
SWIZ X 2 F
COPY T F
Much better, but still a far cry from the top percentile. I believe the only way to get there is with parallelism.



It took some fiddling but this solution runs at 3405/50/17.

It still uses the ADDI/SWIZ combo so each EXA keeps a full counter. I could have one EXA just store the tens digit and one just store the hundreds digit but I don't think that would matter much since that would speed up those EXAs... for them to be limited by the one having to increment the ones digit every loop.

The EXA that makes it to the secret host immediately sends a REPL back to go KILL its buddies because the TRY REPLs add up fast now.

In fact, I just barely managed to squeeze out a single loop unroll. The loop unroll makes the REPL trigger even faster so I needed an extra KILL, which I managed to fit in by giving XC only one starting NOOP and hoping it would LINK after XB, which it did. I also needed an extra SUBI instruction because for some reason the ones digit is off by one now.

By the way, there's something cathartic about typing "KILL KILL KILL".

To make this even faster, well, as I said at least one EXA needs an increment instruction in its loop so it will act as the bottle neck. The only thing I can still remove from that loop is the REPL TRY:
code:
;XA
LINK 800

MARK TOP
SWIZ X 1 #PASS
ADDI X 1 X
JUMP TOP


;XB
NOOP
LINK 800

MARK TOP
SWIZ X 3 #PASS
ADDI X 1 X
JUMP TOP


;XC
NOOP
NOOP
LINK 800

MARK TOP
SWIZ X 2 #PASS
ADDI X 1 X
JUMP TOP


;XD
NOOP
NOOP
NOOP
LINK 800

MARK TOP
REPL TRY
ADDI X 1 X
JUMP TOP

MARK TRY
LINK 800
GRAB 199
REPL OT
SWIZ X 1 M
SWIZ X 3 M
SWIZ X 2 M
COPY F M
HALT

MARK OT
LINK -1
KILL
KILL
KILL
KILL
KILL
KILL


;XE
MAKE
COPY M F
COPY M F
COPY M F
COPY M F
2918/48/15. Not bad. According to the top percentiles it should be possible to get the cycle count further down to at least 2884, and it should be possible to have a solution with only 20 lines of code, too. I'll leave that to the threads.

So Ghast used to work at a game studio?



I'll skip this vote because all three answers lead to the same follow-up question.

Yeah, he was a programmer. It says so in the zine.

I wonder what that was like.



This one is for the thread.

Next time, we explore the Redshift dev kit. Ember would like to know why.

You're really going to make a game with this?
Why?
I'm not offering a reward for it.


megane
Jun 20, 2008



I bet it was fun
Making something is its own reward

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.

code:
LINK 800

MARK LOOP
ADDI X 1 X
SWIZ X 3 #PASS
SWIZ X 2 #PASS
SWIZ X 1 #PASS
REPL LOOP

LINK 800
GRAB 199
COPY F T
DROP
LINK -1
KILL
LINK -1
MAKE
SWIZ X 3 F
SWIZ X 2 F
SWIZ X 1 F
COPY T F
4969/19/9 with an amusing quirk the timings on the KILL let one clone escape to make a second file with password N+1, but there's no penalty for leaving our own machine full of irrelevant garbage files so long as one of them is correct.

code:
;====XA====
MAKE
COPY 2 F
COPY 16 F
COPY 30 F
COPY 54 F
COPY 73 F
COPY 104 F
COPY 108 F
COPY 109 F
COPY 158 F
COPY 160 F
COPY 161 F
COPY 169 F
COPY 173 F
COPY 177 F
COPY 181 F
COPY 202 F
COPY 207 F
COPY 953 F
COPY 990 F
COPY 971 F
COPY 0 F

SEEK -99
MARK LMAO
COPY F T
REPL TEST
TJMP LMAO

COPY 215 T
MARK LOOP
ADDI T 1 T
REPL TEST
JUMP LOOP

MARK TEST
LINK 800
SWIZ T 3 #PASS
SWIZ T 2 #PASS
SWIZ T 1 #PASS

LINK 800
GRAB 199
COPY T M
COPY F M
KILL

;====XB====
MAKE
COPY M X
KILL
KILL
SWIZ X 3 F
SWIZ X 2 F
SWIZ X 1 F
COPY M F
2253/50/748 - bullshitting our way to crazy statistics :v:


megane posted:

I bet it was fun
Making something is its own reward


edit:

GuavaMoment posted:

...aside from leaving incorrect files in your home node, but as long as one of them is correct it works. I played the entire game naming my REPLs as REPL. I wonder if there is a fancy MODI command to cycle through every number and have that exa die on it's own at some point instead of using ADDI X 1 X. That would save the need for the KILL command.
It takes additional instructions to do, but you can use the fact that (9999+1)=9999 in EXArithmetic, so you can make your script compare values each cycle and once (XN - XN-1)=0 then you know you've run out of numbers.

another method for execution/flow control is to pass a token between EXAs, like the M register or having each generation attempt to run a sequence that becomes invalid due to another EXA specifically not crashing:
code:
LINK 800
MAKE
DROP
MARK LOOP
ADDI X 1 X
GRAB 400
SWIZ X 3 #PASS
SWIZ X 2 #PASS
SWIZ X 1 #PASS
REPL LOOP
LINK 800
WIPE
GRAB 199
COPY F T
REPL RETURN
MARK RETURN
LINK -1
MAKE
SWIZ X 3 F
SWIZ X 2 F
SWIZ X 1 F
COPY T F
JUMP RETURN
23 lines, no KILL. If you want the minimum possible Activity score then just use a well-timed TEST MRD to break the keygen loop


Tinkering around further, turns out splitting the LMAO subroutine across two separate EXAs saved a bunch of cycles/lines. Also looks sillier, which is extremely important.
code:
;==== XA M=LOCAL ====
MARK LMAO
COPY M T
REPL TEST
TJMP LMAO

COPY 232 T
MARK LOOP
ADDI T 1 T
REPL TEST
JUMP LOOP

MARK TEST
LINK 800
SWIZ T 3 #PASS
SWIZ T 2 #PASS
SWIZ T 1 #PASS

LINK 800
GRAB 199
MODE
COPY T M
COPY F M

;==== XB M=LOCAL ====
COPY 2 M
COPY 16 M
COPY 30 M
COPY 54 M
COPY 73 M
COPY 104 M
COPY 108 M
COPY 109 M
COPY 158 M
COPY 160 M
COPY 161 M
COPY 169 M
COPY 173 M
COPY 177 M
COPY 181 M
COPY 202 M
COPY 207 M
COPY 216 M
COPY 221 M
COPY 953 M
COPY 971 M
COPY 990 M
COPY 0 M

;==== XC M=GLOBAL ====
MAKE
COPY M T
KILL
KILL
SWIZ T 3 F
SWIZ T 2 F
SWIZ T 1 F
COPY M F
2186/50/732 and as noted XA and XB need to start in local communication mode, which dunno if you've covered that yet.

silentsnack fucked around with this message at 03:49 on Mar 20, 2022

GuavaMoment
Aug 13, 2006

YouTube dude
Start at 967 in X, make a new exa, subtract one from X and make another new exa forever. The new exa inputs the code stored in X and attempts to go into the secret node. It either makes it or fails and dies. Nothing terribly fancy, 2880/28/10

You can make a 19 line solution, again no real tricks...

code:
LINK 800
MARK REPL
ADDI X 1 X
SWIZ X 1 #PASS
SWIZ X 2 #PASS
SWIZ X 3 #PASS
REPL REPL
LINK 800
GRAB 199
COPY F T
DROP
MAKE
SWIZ X 1 F
SWIZ X 2 F
SWIZ X 3 F
COPY T F
LINK -1
KILL
LINK -1
...aside from leaving incorrect files in your home node, but as long as one of them is correct it works. I played the entire game naming my REPLs as REPL. I wonder if there is a fancy MODI command to cycle through every number and have that exa die on it's own at some point instead of using ADDI X 1 X. That would save the need for the KILL command.


Edit: You have the bog witch's approval, complete the rite of passage!

GuavaMoment fucked around with this message at 18:32 on Mar 19, 2022

Quackles
Aug 11, 2018

Pixels of Light.


quote:


Here's an interesting question. Were Panda Expresses around in 1997?

I think that meetup place in the second letter from the bottom in the rightmost column is a real location.

I wonder if anyone's gone...

Tulip
Jun 3, 2008

yeah thats pretty good


Panda Express was founded in 1983.

I have never used SWIZ and I find it fully incomprehensible lol

This was my awful solution

code:
LINK 800
COPY -1 X
MARK BRUTE
ADDI X 1 X
DIVI X 100 #PASS
MODI X 100 T
DIVI T 10 #PASS
MODI X 10 #PASS
REPL BRUTE
LINK 800
LINK -1
KILL
LINK 800
MAKE
DIVI X 100 F
DIVI T 10 F
MODI X 10 F
DROP
GRAB 199
COPY F X
DROP
GRAB 400
SEEK 9999
COPY X F
LINK -1
LINK -1
HALT
5966/27/7

Carbon dioxide
Oct 9, 2012

Part 19 - A SECRET TO EVERYBODY

=== Trash World Inbox ===

Let's see what improvements we got this time. My high scores were 2918 cycles and 22 size for the Redshift unlock.

First, the size improvements. silentsnack and GuavaMoment have basically identical 19 line solutions.

GuavaMoment posted:

code:
LINK 800
MARK REPL
ADDI X 1 X
SWIZ X 1 #PASS
SWIZ X 2 #PASS
SWIZ X 3 #PASS
REPL REPL
LINK 800
GRAB 199
COPY F T
DROP
MAKE
SWIZ X 1 F
SWIZ X 2 F
SWIZ X 3 F
COPY T F
LINK -1
KILL
LINK -1
...aside from leaving incorrect files in your home node, but as long as one of them is correct it works.
4964/19/13, saving 5 cycles over silentsnack's solution in exchange for extra activity and an additional garbage file. This differs from my solution by combining the REPL and the jump to the start of the loop. I couldn't do that because I put the ADDI at the end (which meant it tries 000 too, but that's not a passcode that actually occurs).

Anyway, I thought I tried a solution where it leaves some garbage and it didn't work. Must've done something else wrong then.

Next, cycle count.

GuavaMoment mentioned a 2880 cycle solution is possible by counting down instead of up. It's gaming the tests a little bit - but not nearly as much as the following.

silentsnack posted:

code:
;====XA====
MAKE
COPY 2 F
COPY 16 F
COPY 30 F
COPY 54 F
COPY 73 F
COPY 104 F
COPY 108 F
COPY 109 F
COPY 158 F
COPY 160 F
COPY 161 F
COPY 169 F
COPY 173 F
COPY 177 F
COPY 181 F
COPY 202 F
COPY 207 F
COPY 953 F
COPY 990 F
COPY 971 F
COPY 0 F

SEEK -99
MARK LMAO
COPY F T
REPL TEST
TJMP LMAO

COPY 215 T
MARK LOOP
ADDI T 1 T
REPL TEST
JUMP LOOP

MARK TEST
LINK 800
SWIZ T 3 #PASS
SWIZ T 2 #PASS
SWIZ T 1 #PASS

LINK 800
GRAB 199
COPY T M
COPY F M
KILL

;====XB====
MAKE
COPY M X
KILL
KILL
SWIZ X 3 F
SWIZ X 2 F
SWIZ X 1 F
COPY M F
2253/50/748 - bullshitting our way to crazy statistics :v:
Hahaha, this code is quite the sight. So, XA starts with writing a whole bunch of values into a file (in the home host so that file won't get in the way later), then sends REPLs to test each value in the file. Looking at them, I think they're the 17 lowest passcodes and the three highest from the test set. This means you never have to brute force all the way into the 950s, and it also means you can skip the first 200 or so passwords because we already know which passwords in that range are used. If none of those 20 passwords are correct, it brute forces the range that wasn't tested yet, but that's now much smaller.

Thinking about it, what silentsnack actually did was change a brute force attack into a partial dictionary attack. Sounds much less like bullshit if I phrase it this way, wouldn't you say? So this solution makes for a good real life lesson: hacking into an account is much easier if the hacker has foreknowledge about likely passwords. That's why you should never use dictionary words as passwords (use random characters instead), and you should never reuse passwords across sites. If it gets leaked in one place, hackers will first try that same password for all your other accounts. Instead, invest in a proper password manager.

Anyway, silentsnack came up with a further improvement.

silentsnack posted:

code:
;==== XA M=LOCAL ====
MARK LMAO
COPY M T
REPL TEST
TJMP LMAO

COPY 232 T
MARK LOOP
ADDI T 1 T
REPL TEST
JUMP LOOP

MARK TEST
LINK 800
SWIZ T 3 #PASS
SWIZ T 2 #PASS
SWIZ T 1 #PASS

LINK 800
GRAB 199
MODE
COPY T M
COPY F M

;==== XB M=LOCAL ====
COPY 2 M
COPY 16 M
COPY 30 M
COPY 54 M
COPY 73 M
COPY 104 M
COPY 108 M
COPY 109 M
COPY 158 M
COPY 160 M
COPY 161 M
COPY 169 M
COPY 173 M
COPY 177 M
COPY 181 M
COPY 202 M
COPY 207 M
COPY 216 M
COPY 221 M
COPY 953 M
COPY 971 M
COPY 990 M
COPY 0 M

;==== XC M=GLOBAL ====
MAKE
COPY M T
KILL
KILL
SWIZ T 3 F
SWIZ T 2 F
SWIZ T 1 F
COPY M F
2186/50/732 and as noted XA and XB need to start in local communication mode, which dunno if you've covered that yet.
Yeah, so the idea is the same, but the file (which took time to write) has been replaced by an EXA which sends the dictionary over the M register. This is faster and also saves a couple cycles for a larger dictionary.

I've talked about communication modes but I've not needed them so far so I'll explain it again:
EXAs, by default, start in GLOBAL communication mode. That means they can receive and send messages over M from any friendly EXA in any host.
You can swap them to LOCAL mode using the MODE command, or at the start by clicking the toggle on the M register. In LOCAL mode, they can only communicate with EXAs in the same host - and very importantly, only with other EXAs that are also in LOCAL mode.

So, by putting XC in GLOBAL and the other two in LOCAL, XC's COPY M T will just wait until XA switches modes and sends its first GLOBAL mode package. Meanwhile, as long as XA and XB stay in the same host, they can communicate in LOCAL mode all they want.


=== Redshift Homebrew - A SECRET TO EVERYBODY ===

Before I continue, GuavaMoment reminded me that there's a Steam Achievement tied to last week's assignment.
It is called RITE_OF_PASSAGE and the description states: You have the bog witch’s approval. Now complete the rite of passage.
Of course it's up to the player to figure out it's linked to this assignment.



Remember that random save file? We need to set RITE OF PASSAGE COMPLETE to TRUE. Not 1 for TESTs, no, the actual word TRUE.

No speed goals or anything so let's just grab my initial brute force solution to open the locked host and write some code after it.
code:
LINK 800

MARK TOP
SWIZ X 3 #PASS
SWIZ X 2 #PASS
SWIZ X 1 #PASS
REPL TRY
ADDI X 1 X
JUMP TOP

MARK TRY
LINK 800

GRAB 220
SEEK 9999
SEEK -3
COPY F X
SEEK 1
COPY X F
Since I can't write the word TRUE from scratch, I seek to a position where the word is already in the file and just copy that over.



And that's another achievement in the pocket. Let's get back to Ember.

So Ghast used to work at a game studio?

Yeah, he was a programmer.

I wonder what that was like.



One vote for "Probably terrible" and two for...

I bet it was fun, while it lasted.

Figuring out how to push a console to its limits...
Making something that brings joy to people...
Yeah, I can see that.


You can? Hm.





Now that I unlocked the Redshift dev kit, it's time for some homebrew, don't you think?

You're really going to make a game with this?
Why?
I'm not offering a reward for it.




One vote for "Not everything I do is for you", but two for "Making something".

Making something is its own reward.

Oh, it's one of those intangible things.
A sense of accomplishment? Self-actualization?
I'm not good at abstract concepts.
I'll have to observe you closely.


You surprise me, Ember. You do understand why Ghast would make games but not why I would do so?


OST: Code and Registers

This is the Redshift dev kit. As you can see, it looks quite different from the other things we've done so far. Luckily the zine has a comprehensive guide on this.

Welcome to this game's sandbox mode. Other than the EXAs being a bit different than we're used to, this stage has no size limit, no EXA limit other than what fits in the host and it lets you go wild.

This is a special episode, I've been looking forward to showing this off since I started this LP, but I'll start with a description of all the features in the sandbox. If this is a bit too dry for you, feel free to skip to the next occurrence of the text: "Let's build something!"

Let's use the zine to go through all the features.



There's already a lot to cover on the first page. You can skip reading it if you like since I'll show an example of each feature.

First of all, the DATA instruction.



DATA is a special pseudo-instruction that indicates that an EXA should already hold a file when it starts, containing the values after DATA. All DATA instructions are parsed in order they appear in, before the game even starts. During execution, these instructions are ignored. A very convenient way to store your game data.



You can place them wherever you want in your code but I prefer to have them at the start.

By the way - sadly you cannot use DATA outside of the Redshift. That would make some earlier assignments much easier to solve.

---

The only type of graphics in Redshift are sprites.
Each EXA can hold a 10x10 sprite in the G register. An EXA can be initialized with a sprite, you can turn pixels on and off by drawing on them with your mouse.





Every sprite starts out on the top left. To move it, simply write a new X position directly to GX, or Y position to GY. If I run this program for two steps, you see my drawing jump right and then down, so it appears in roughly the middle of the 120x100 pixels screen.



If you really want to use the 3D mode you better get yourself some of those special glasses.

Switching the 3D toggle on the Exapunks device dims the lights of the dev kit so you can truly focus on the headache inducing game.





By writing a value between -9 and 9 to the GZ register, you can make the sprite pop "in" or "out" of the screen in 3D mode. In 2D mode, there's no difference.



Finally, you can change the contents of the sprite itself by writing three digit values to GP. The first digit tells the EXA what to do (0 = turn pixel off, 1 = turn it on, 2 = toggle), and the second and third digit have the X and Y positions, counting from the top left.
This picture is after running COPY 060 GP, turning the 6th pixel of the top row off, and COPY 199 GP, turning the pixel in the bottom right on.

---

You can follow drawing code easily if you go step by step, but if you run the Redshift at normal speed (which is done with the dev kit's fast forward button), you won't see anything. That's because these draw instructions go by real fast.

What you're supposed to do is use the WAIT instruction for this. Unique to the Redshift, WAIT makes the EXA wait until the next frame. The Redshift runs at 30 fps.

So, if I put a WAIT instruction after all this drawing code, the user will only see the final result. That drawing hopping from the top left to the intended position? Individual pixels going on or off? That's way too fast for the user to see.

A big annoyance, though, is that WAIT instructions don't cause EXAs to wait for each other. So if EXAs have different amounts of instructions and you don't sync them up with NOOPs or M communication, they will quickly desync. It's a lot to keep in mind while coding for the Redshift.

As far as I can tell a WAIT instruction only takes a single cycle. So in practice, it doesn't mean "pause the EXA", it means "advance the frame of the Redshift". That means you can't even line up other EXAs by counting the number of instructions that can be run between frames (which was how real life old consoles dealt with this issue). It's weird. You're better off making sure all the EXAs are synced before doing a WAIT.



Next page of the zine.



If you need a score display or something you can use the built in font. Sending a value in the 300 range to GP replaces whatever was in the sprite register with that character. 300 itself is a space which blanks out the entire sprite. That could be useful.



The Redshift has a built-in collision detection system, a common way for games to prevent characters going through walls, or for detecting when a bullet hits the target. You use it by first having an EXA write something to the CO (collision output) register.



Then, if a collision occurs (which happens if both sprites have at least one lit-up pixel in same position on the Redshift's screen), the CI register (the bottom-most to the right) will contain the CO value of the other EXA. If there's multiple collisions, the highest CO value wins. And if there's no collisions, CI will always contain -9999. Collision ignores the GZ (3D depth) value.

---

While graphics and collision are handled within the EXAs, for input and sound we need to deal with hardware registers.



For input, read the #PADX and #PADY registers for the state of the D-pad. Each digit in the output of #PADB stands for one of the other buttons (X, Y, Z and Start). #EN3D will tell you if the device is in 3D mode.

While a game is running, you can control the Redshift with the mouse (by clicking the buttons) or keyboard, by default WASD for the d-pad, JKL for the three action buttons, and Enter for the Start button. This can be remapped from the EXAPUNKS options menu.

Finally, there are four sound registers. #SQR0 and #SQR1 are linked to square wave sound channels, #TRI0 to a triangle wave, and #NSE0 is a simple noise channel. Writing a number to any sound register will cause that sound to play continuously until a new number is sent. 0 turns it off, and for the square and triangle channels, 60 is the middle C, with lower numbers corresponding to lower notes and higher numbers to higher ones, following the piano keys as seen in the zine. Similarly, a value sent to the noise channel controls the pitch.

That's basically all there's to say about Redshift development.

Let's build something!

As a few readers might already know, during my initial playthrough back in 2018, I got kinda nerdsniped by this sandbox and spent way too much time on it. I will show here what I built back then because I still like it. But since this is an in-depth playthrough I'll take you through the design as well.

When I read the documentation, the first thing that piqued my interest was the sound channel setup. Two square waves, one triangle wave and a noise channel? That's almost exactly how the sound was set up in 8-bit Nintendo consoles such as the NES and the Game Boy. So, it should be possible to do something with that, right?

And programming an actual game in Redshift is hard. Game music is good enough for me.

Since I'm not a music writer, I first went to search for some sort of reference of how music is actually written in those old consoles.
To my surprise I actually found sheet music for a famous 8-bit song, with the 8-bit sound wave channels as the "instruments". A bit weird, but exactly what I needed.

One problem, though, I barely knew anything about sheet music. I knew about time signatures and measures and half notes and quarter notes and that's about where it ends.

I had to learn about how to recognize what key the music was played in (the clef with the flat symbols), and whatever the heck this was:


I mean I can figure out those are eighth notes with a rest in between. The flat symbol is easy to understand but hard to implement because when you need to convert your tones to numbers, a flat becomes an extra offset that I found easy to forget. But that little 3. That damned 3. It's apparently called a "tuplet" and it means something like "I want you to play notes that don't actually fit in the meter, so shorten all of them a bit so it kinda fits."

This song plays at 144 bpm, or 2.4 per second. Redshift has 30 frames per second. That means every frame is 2.4 / 30 = 0.08 of a beat. That means one beat is 12.5 frames exactly. With a 4/4 signature, a beat is a quarter note.

Since this doesn't quite fit in the frame count I decided to bump the speed to 150 BPM, because that makes every possible note I want to play a round number of frames.
Half note: 24 frames.
Quarter note: 12
Eighth: 6
Sixteenth: 3
And those funky tuplet notes are 4 frames each.

It plays slightly fast but at least you don't get weird variation in timing due to rounding errors.

With that in mind I started coding.
code:
== SQR0
DATA 70 24 0 8 70 4 70 4
DATA 70 4 70 4

; A TON MORE DATA HERE

LINK 801
MARK MAINLOOP
TEST EOF
TJMP RESET
COPY F #SQR0
COPY F X
MARK WAITLOOP
SUBI X 1 X
WAIT
TEST X > 1
TJMP WAITLOOP
COPY 0 #SQR0
WAIT
JUMP MAINLOOP
MARK RESET
SEEK -9999
JUMP MAINLOOP
The code isn't all that complex. After loading in the data, it copies the first value from the file into the square wave register, and then it uses the second value for a frame countdown. Rinse and repeat. Once it hits the end of the file it simply resets to the beginning.

I quickly noticed that my first version sounded terrible. It sounded like one long continuous note changing pitch. I realized I needed to build in a 'breath' between each note. That's what the COPY 0 #SQR0; WAIT does. I changed the TEST to already jump out if the value is 1 (1 frame to go). It then adds a single frame of silence. So the data snippet I included plays 23 frames of sound, 1 of silence (a half note), 8 frames of silence, (a rest, part of a tuplet), 3 frames of sound, 1 of silence (an 'eighth note' in the tuplet) and so on.

There's one more thing - this song has a repeat for the second part. That was no trouble to code since DATA instructions respect @REP macros.

The second square wave and the triangle wave have the exact same code as the first, just a different data file. The triangle wave took a bit more effort because it has a bass clef and as the music noob I am, I had to figure out where my middle C went.

Something else I noticed around this time is that it's incredibly easy to make timing mistakes while copying the sheet music into the data files - but also easy to figure out because if one instrument goes out of sync it sounds awful immediately.

Finally, there's the noise channel. The sheet music's fourth instrument is not called "noise", it's in fact a snare drum. This one was harder to convert than I thought. First of all, I had to find a pitch. The noise channel is actually a quite horrible crackling noise and there was no sound I really loved, but a pitch value of 50 sounded closest to the original. Secondly, I started making a data file like for the other channels - and utterly failed. If the sheet music calls for a quarter note - well, it's not a piano or a flute - on a snare drum that's still a very short sound. It's the speed of the beats that goes down for longer notes, not the length of the sound.

It turns out 2 frames of noise works the best here.

The snare drum has a section where it repeats the same measure 40 times. I could've put 40 repeats in the data file but I decided to clean that up a bit, so the noise channel is handled by two EXAs. This is the first:

code:
NOTE NSE0

NOTE TURNS OUT YOU NEED
NOTE TO DO QUITE A BIT
NOTE OF MANUAL TWEAKING
NOTE TO MAKE A NOISE CH.
NOTE SOUND LIKE DRUMS...

DATA 50 4 0 32 50 4 50 4
DATA 50 4

DATA 50 4 0 32 50 4 50 4
DATA 50 4

DATA 50 4 0 32 50 4 50 4
DATA 50 4

DATA 50 4 0 8 50 4 0 8
DATA 50 4 0 8
DATA 50 4 0 2 50 4 0 2

NOTE PUT REPEATING PART
NOTE IN OWN EXA FOR
NOTE CLEANER CODE

LINK 801
MARK MAINLOOP
TEST EOF
TJMP REPEAT
COPY F #NSE0
COPY F X
TEST X = 2
TJMP SKIP
MARK WAITLOOP
SUBI X 1 X
WAIT
TEST X > 2
TJMP WAITLOOP
MARK SKIP
COPY 0 #NSE0
WAIT
COPY 0 #NSE0
WAIT
JUMP MAINLOOP
MARK REPEAT
COPY 40 X
MARK REPLOOP
COPY 1 M
VOID M
SUBI X 1 X
TEST X > 0
TJMP REPLOOP

SEEK -9999
JUMP MAINLOOP
You can see in the DATA section that every non-rest sound has a time of 4. That's actually two frames of sound and 2 of rest, because in this case the TEST jumps out two frames early. Longer notes I handled by just adding additional "rests" to the data file. I needed a special case to handle 50 4 0 2 which is just a basic eighth note, of which the first 2 frames are the drum and the remaining 4 are silent. Because that meant having 2 rest frames on top of the two built-in ones I need the SKIP jump. I'm sure I could've done this in a much cleaner way but by this time I had the whole thing finally working and synced up and didn't want to break it again.

Once this EXA reaches the EOF, this indicates we've hit the repeating measure of the drums. It sends a message to M which indicates the second noise channel EXA needs to play one measure, then the other EXA sends a message back over M when it's done, this EXA counts down from 40, sending the other one repeating instructions to keep doing that measure, and once it's done the song starts over.

Using this sort of back-and-forth with M was the best way I could figure out to keep these two EXAs in sync. Here is the other noise channel EXA:
code:
NOTE NSE0

NOTE REPEATING PART OF
NOTE DRUMS

DATA 50 4 0 8 50 4 50 4
DATA 50 4 50 4 0 8 50 4
DATA 0 8

LINK 801
VOID M
MARK MAINLOOP
TEST EOF
TJMP RESET
COPY F #NSE0
COPY F X
MARK WAITLOOP
SUBI X 1 X
WAIT
TEST X > 1
TJMP WAITLOOP
COPY 0 #NSE0
WAIT
JUMP MAINLOOP
MARK RESET
SEEK -9999
COPY 0 M
VOID M
JUMP MAINLOOP
It's simple. It waits for M, then runs the same "two frames of sound, 2 frames of rest" logic as the other one, for its file which contains a single measure. Once it runs out, it sends a message on M and waits for instructions.

As a final touch I created some pixel art, consisting of four sprites. It doesn't do anything, it isn't animated, but at least the screen isn't completely empty during the demo.



This code doesn't do much, it just moves the sprite into the right position and then gets into an infinite loop so the EXA stays alive.

And that's all of the code.

I wonder, have you figured out yet which song I decided to recreate in the Redshift?

Well, there's no delaying it any longer. Here it is, the recording I made in 2018.

https://www.youtube.com/watch?v=sP3sPc0oHu0&t=37s

My rendition of the song starts at 37 seconds. The bit before is me scrolling through all the code so you can get a sense of how much work it was putting together those data files.

Here is a link to the sheet music I used.

And finally, here's the game disc so you can play it for yourself.



Wait what?

Yes, the Redshift has an export system. It exports games as PNGs of a disc that contain the code. If you drag it into the Redshift view in EXAPUNKS, it will load the game for you. This has got to be the coolest save export system I've ever seen.



You can either drag that image of the disc into this screen, or if you don't own the game, download the EXAPUNKS TEC Redshift Player for free on Steam to play the demo.

The Steam Discussion Boards for the Redshift Player are also a decent place to find other solutions, including actual games you can run in the Player.
They might seem like simple games but the amount of coding that went into them is impressive. EXAPUNKS really doesn't have a language that's friendly for complex programs.



When you leave the Redshift dev kit, the game will ask you if you actually made a game (the best Zachtronics can do without building some sort of Star Trek AI that can magically tell if a program is a game or not). The level will count as completed if you hold this button.

Congratulations! You did it.
What does it feel like to be a game developer?




We immediately go to the next thread vote.

Time for some research.
Human physiology, human morality...




And the intro for the next assignment.

Carbon dioxide fucked around with this message at 13:11 on Jul 2, 2022

Carbon dioxide
Oct 9, 2012


By the way I didn't want to bring it up in the update but I'm wondering how you managed to count down from here while silentsnack's solutions hardcode a check up till 990. Or do those do the digits in different orders? :thunk:

berryjon
May 30, 2011

I have an invasion to go to.
Ah, that's music to my ears alright. ;)

It's Great
Your usual Topics

Omobono
Feb 19, 2013

That's it! No more hiding in tomato crates! It's time to show that idiota Germany how a real nation fights!

For pasta~! CHARGE!

Carbon dioxide posted:

I wonder, have you figured out yet which song I decided to recreate in the Redshift?

:downs: Ra Ra Rasputin, obviously :downs:

Carbon dioxide
Oct 9, 2012


Hah, that version was made by Quackles. Here's the original upload, which shows off all of his code.

https://www.youtube.com/watch?v=dZVrbpQoqg0

So, funny story, I finished A Secret to Everybody while Quackles was in the middle of his "secret project" and we hadn't seen anything except maybe a couple screenshots.
At the time I had no idea his Shenzhen I/O secret project was ALSO a song.

So mine came first - but Ra Ra Rasputin's code and design is probably a factor of magnitude more complex than Secret To Everybody.

Omobono
Feb 19, 2013

That's it! No more hiding in tomato crates! It's time to show that idiota Germany how a real nation fights!

For pasta~! CHARGE!

...
Did I copy/paste from the wrong tab?
I copy/pasted from the wrong tab.:doh:

Junpei
Oct 4, 2015
Probation
Can't post for 11 years!
Considering the decade this game takes place in, I think you should take a shot at Smells Like Teen Spirit.

Also,

berryjon posted:

It's Great
Your usual Topics

Quackles
Aug 11, 2018

Pixels of Light.


Carbon dioxide posted:

Hah, that version was made by Quackles. Here's the original upload, which shows off all of his code.

https://www.youtube.com/watch?v=dZVrbpQoqg0

So, funny story, I finished A Secret to Everybody while Quackles was in the middle of his "secret project" and we hadn't seen anything except maybe a couple screenshots.
At the time I had no idea his Shenzhen I/O secret project was ALSO a song.

So mine came first - but Ra Ra Rasputin's code and design is probably a factor of magnitude more complex than Secret To Everybody.

That thing took me, IIRC, TWO MONTHS to finish, and another bunch of time to actually write up.

https://lparchive.org/SHENZHEN-IO/Update%2063/

Here's the writeup that details how it all works, with detailed code.

GuavaMoment
Aug 13, 2006

YouTube dude

Carbon dioxide posted:

By the way I didn't want to bring it up in the update but I'm wondering how you managed to count down from here while silentsnack's solutions hardcode a check up till 990. Or do those do the digits in different orders? :thunk:

No idea. Spacechem has different properties on different platforms, so maybe he's not on windows?

silentsnack
Mar 19, 2009

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

GuavaMoment posted:

No idea. Spacechem has different properties on different platforms, so maybe he's not on windows?

Nope. Copypasting CO2's 2918-cycle solution gives the same statistics, which should mean in the slowest run both our machines count up to the same highest value of 990.



Assuming all three of us are running the same version of the game with the same pseudorandom seed; did you maybe mean "1967" in your post and/or skip a trivial detail in your explanation? The former would roll over from 1000 to 999 and SWIZ 321 is effectively MODI 1000 but as for the latter...

SWIZ 1967 321 X = SWIZ 967 321 X = 967
SWIZ -1 321 X = -1

MODI 1967 1000 X = MODI 967 X = 967
MODI -1 1000 X = 999

...MODI behaves differently with negative numbers.

GuavaMoment
Aug 13, 2006

YouTube dude
Ok, I see I swizzle in the order 1, 3, 2 from 976, so I input 796, 696, 596....096, 995, 895...
Why do I do this? I don't know, but it works. I guess I'm a real computer engineer!

Carbon dioxide
Oct 9, 2012

Part 20 - Digital Library Project

=== Trash World Inbox ===

As I expected, Quackles' rendition of Ra Ra Rasputin in Shenzhen I/O came up in the thread.
Because it's very impressive, here's a link to the Youtube video and a detailed write-up. Note that the write-up continues in the next part of that LP.


=== Digital Library Project ===

Congratulations! You did it.
What does it feel like to be a game developer?




One vote for "Pain" which I feel, yeah. It's though work. I prefer doing other kinds of programming. Anyway, two votes went to "great". The reward can make it worth the effort.

It's great.

Yeah?
At least there's one thing you can enjoy.
I'm not sure I fully understand it, but there you go.




Before we continue, a voiced cutscene with Ember.

Okay. I have a real question to ask you.
Say there's a trolley on a track heading towards five people.
Three of those five people are vegetarians.




Once again, for the voice-acted parts, dialog choices really make no difference.

Not this again...

There's a switch you can throw that will shut down a meat packing facility that is located down the road.
Unfortunately, the switch will also prevent the train from stopping, because...
Because...

Wait.
I may have reversed something.
Recalibrating.
There are too many variables here.
Okay.
Let's return to this later.
I need more data first.
And I need more processing power.


Well, that was a complete waste of time.



I have two assignments available now. Let's start with the first, hacking a library. Ook!



Time for some research.
Human physiology, human morality...




An unanimous vote.

Your usual topics.

Yeah, I guess so.
Wait. Am I really that predictable?
I'll have to change things up soon.
Let's get those books.



OST: Behind the Scenes

We're in the Palo Alto digital library project. Looks like a quite complicated network.

The assignment:
- Books are stored in the host corresponding to the first digit of their call number, while a book's file ID is 200 plus the last two digits of the call number. For example, book 512 would be stored in the host 500-599 as file 212.
- Duplicate each of the books requested by EMBER-2 and bring them back to your host.
- The call numbers for the books EMBER-2 wants are available in the file 300.
- Note that EMBER-2 will never request more than one book from the same host.


Alright, let's nose around a bit first. File 300 contains Ember's shopping list. To my knowledge there's no way to reach that EXA holding a file on the far left.



As for the books, here's all of them. Did you know you can use that little button with the right arrow in a file or EXA's title bar to pop it out of the left column so you can drag and drop it anywhere?

I feel some of these books might not be very trustworthy, but if Ember wants them, we'll get them for her I guess. Since you can't steal from a library (that would be evil!) I'll need to copy the books.

First of all, getting to them.



This icon seems to indicate that to get deeper into the network, I always need to use LINK 800, and to get back home it's -1.

My first attempt to get to the files looks like this:
code:
GRAB 300
MARK START
COPY F X
REPL GO
JUMP START

MARK GO
LINK 800
DIVI X 100 T

MARK GETTHERE
LINK 800
SUBI T 1 T
TJMP GETTHERE
The EXA starts by reading from the file. By writing values to X, the REPLs will still have the value in memory. The hundreds digit tells us how many LINKs we need to traverse, which is handled in a simple loop. The original EXA will die once it tries to read past the end of the file.

code:
REPL WRITER

MODI X 100 X
ADDI X 200 X
GRAB X
; DO STUFF

MARK WRITER
; DO OTHER STUFF
To grab the file we need to do a bit of arithmetic. I also REPL a WRITER which can hold the new file to write the copy to. Testing this code I see some hosts get a bit crowded. That might slow down EXAs a bit, if they have to wait for space. But that's a problem for later.

Since we're going to need communications between EXAs and since a lot of them will be writing in parallel, I think it's a good idea to have my single initial EXA (from which the others are replicated) start in local communication mode and just keep each WRITER in the same host as its corresponding reader.



With the writer and reader code in place, the replicated EXAs start copying their files. The READER will send a 0 once it reaches EOF. After that, it conveniently self-destructs when it tries to run the MAKE instruction while already holding a file. Using 0 as EOF indicator means the WRITER can simply use the T register as an intermediate, since ALL non-0 values are considered true for the purpose of a TJMP, including keywords.

All that's left is getting our EXAs back home. That can be done in a very simple way:

code:
GRAB 300
MARK START
COPY F X
REPL GO
JUMP START

MARK GO
LINK 800
DIVI X 100 T

MARK GETTHERE
LINK 800
SUBI T 1 T
TJMP GETTHERE

REPL WRITER

MODI X 100 X
ADDI X 200 X
GRAB X

MARK READING
COPY F M
TEST EOF
FJMP READING
COPY 0 M

MARK WRITER
MAKE
COPY M T
MARK WRITING
COPY T F
COPY M T
TJMP WRITING

@REP 10
LINK -1
@END
In most cases it will reach the home node before going through all the repetitions, which is fine because in that case the next LINK will just cause the EXA to die, dropping the file in the process.

By the way, now that I got the second zine, here's a full explanation of the @REP macro.



If you didn't know about the performance increase of unrolls, the zine also explains it here.



And this is my first working solution.

I had to compress this gif to not make it too huge. It's playing at double speed now.



290/38/74. Top percentile scores are 218, 26 and 10 respectively. Honestly, my solution isn't bad - I'm already below tenth percentile for cycles. But let's see how this can be improved.

A slow part of this solution is the check if the file is done every cycle. The files have a minimum size: 34. That means if we step into the check cycle after 33 steps we're fine.

I unrolled both loops to 33 direct COPYs - but it didn't quite fit. So I added some code so each does a 16 unroll twice. I set up a countdown in T for that, and had to remove some of the final LINK unroll because it didn't fit otherwise.
code:
GRAB 300
MARK START
COPY F X
REPL GO
JUMP START

MARK GO
LINK 800
DIVI X 100 T

MARK GETTHERE
LINK 800
SUBI T 1 T
TJMP GETTHERE

COPY 2 T

REPL WRITER

MODI X 100 X
ADDI X 200 X
GRAB X

MARK A
@REP 16
COPY F M
@END
SUBI T 1 T
TJMP A

COPY F M

MARK READING
COPY F M
TEST EOF
FJMP READING
COPY 0 M

MARK WRITER
MAKE

MARK B
@REP 16
COPY M F
@END
SUBI T 1 T
TJMP B
COPY M F

COPY M T
MARK WRITING
COPY T F
COPY M T
TJMP WRITING

MARK END
@REP 4
LINK -1
@END
JUMP END
232/75/74. Much better.

The next thing I thought of was removing the test from one of the loops entirely. The result was not an improvement but I'll share it anyway in case it inspires someone.
code:
GRAB 300
MARK START
COPY F X
REPL GO
JUMP START

MARK GO
LINK 800
DIVI X 100 T

MARK GETTHERE
LINK 800
SUBI T 1 T
TJMP GETTHERE

REPL WRITER

MODI X 100 X
ADDI X 200 X
GRAB X

@REP 33
COPY F M
@END

MARK READING
COPY F M
TEST EOF
FJMP READING
DROP
KILL


COPY 399 X
MARK GRAB
ADDI 1 X X
TEST X = 410
TJMP READING
REPL GRAB

GRAB X
JUMP END


MARK WRITER
MAKE

MARK B
COPY M F
JUMP B


MARK END
@REP 5
LINK -1
@END
JUMP END
The reader simply KILLs the writer when it's done. This allows for the full unroll. The real problem comes from the fact that the file IDs of the generated files are somewhere between 400 and 409. So I need a REPL structure to try grabbing all those file numbers until it finds one. I also needed to fiddle with the timing a bit so that it doesn't KILL some other EXA that happens to pass by. Anyway, this runs at 258 cycles, so slower than the previous solution.

I didn't get a better score than 232 cycles, so I'll leave the further improvements to the thread.

As for reducing the size, the trick is that file IDs are always globally unique. I don't need to keep track of where to go if I just simply try grabbing the correct file in every host. Don't forget merging the COPY from 300 with the first MODI, which is now possible since we don't need the hundreds digit for anything anymore.
code:
GRAB 300
MARK START
MODI F 100 X
ADDI X 200 X
REPL GETTHERE
JUMP START

MARK GETTHERE
LINK 800
REPL GETTHERE

GRAB X

REPL WRITER

MARK READING
COPY F M
TEST EOF
FJMP READING
COPY 0 M

MARK WRITER
MAKE
COPY M T
MARK WRITING
COPY T F
COPY M T
TJMP WRITING

MARK END
LINK -1
JUMP END
295/26/87. That's the top percentile score.

Finally, activity. It's possible to get that all the way down to 10. Can you see how?

To get to 10 activity I can't LINK back even once. I need to send one EXA out that communicates the data back via global M. That'll be a single file at a time so it will be slow. Also, I need to grab the files in order starting from the lowest, otherwise I'd need to track back. In other words - I'm going to need to apply some kind of sorting to file 300.

It is very annoying to sort a file with EXAs. With only two registers per EXA, one which is overwritten whenever you test which value is greater, and with the fact that there's only an overwrite instruction, not an insert one, I'm not even sure if it can be done with a single EXA.

Luckily we don't need to actually store the sorted file. All we need is an EXA that outputs the values of file 300 in order from low to high. And, after that, since we can't use KILL instructions, some smart handling of EXAs so that they don't get in each others way.

I came up with a solution that's not that easy to understand, so I'll go through it bit by bit. It starts with three EXAs. XA sorts file 300. XB writes the new files. And XC goes visit the library. Here's the top part of XA:
code:
;XA LOCAL
GRAB 300

MARK NEXTFILE

COPY F X

MARK FINDLOWEST
TEST EOF
TJMP FOUND
TEST F < X
FJMP FINDLOWEST
SEEK -1
COPY F X
JUMP FINDLOWEST

MARK FOUND
This code puts the first value of F in X. Then it checks every subsequent value of F. If it's lower than X, it puts that in X instead. Once it hits EOF we know it found the lowest value currently in the file.

After this, XA has some logic to send the file to the XC, my reader EXA. I'll skip that for the moment. To complete the sorting algorithm, after doing so (and while XC is busy copying a file), XA executes this:
code:
SEEK -9999
MARK FINDCURRENT
TEST F = X
FJMP FINDCURRENT
SEEK -1
VOID F

SEEK -9999
TEST EOF
FJMP NEXTFILE
In short, it finds the value it just sent to XC, deletes it from the file, then jumps back to the start. If the file is completely empty, it falls through to the code below.

Let's look at XC next.
code:
;XC GLOBAL

LINK 800

MARK LOOP
MODI M 100 X ;GB
DIVI 0 X T ; DIE ON 0
ADDI X 200 X
MODE
MARK NEXTHOST
LINK 800
REPL FIND
NOOP
TEST MRD ;LD
FJMP NEXTHOST
VOID M ;LD
VOID M ;LF
MODE
JUMP LOOP


MARK FIND
GRAB X
COPY 0 M ;LD
MODE

MARK READLOOP
COPY F M ;GE
TEST EOF
FJMP READLOOP
COPY 0 M ;GE EOF
MODE
COPY 0 M ;LF
The comments (such as GB) indicate what communication is being done. The first letter stand for Global or Local mode, and the B corresponds to B in another EXA to see where the specific M calls line up.
It starts by getting a file ID from M, and doing the same logic as before to get the actual filename. There's a DIVI inserted so the EXA can quickly die when the program is done.

Otherwise it LINKs to the next host (this is always safe, since it starts in the gateway, and Ember never needs two files in the same host), and makes a replicated EXA (FIND to see if the file is there. If it is, the replica immediately communicates over local M (message LD), which causes the MRD in the original XC EXA to be true. In that case it has to VOID LD to allow the replicated FIND EXA to continue, otherwise it jumps to NEXTHOST and tries again. If the file is found, the original has another VOID which won't be triggered for a while.

The bottom half switches back to GLOBAL mode, and starts sending the file's content, ending with a 0 (GF). Then it changes mode back to LOCAL, sends message LF, which tells the original XC it should continue. At that point it switches back to GLOBAL mode and waits for the next file ID.

This whole switcharoo is necessary because, for example, if you leave XC in GLOBAL mode, it will keep stealing file data that's supposed to go to XB.

Speaking of which, it's time to look at the whole thing and see how XB fits into the picture.



XB starts by sending a message over LOCAL M (LA). This is basically it waiting for someone to read it. XA is the one to do so, directly after the MARK FOUND.
At that point, XA quickly switches to GLOBAL mode, sends the file ID to XC (GB, which we already saw from XC's point of view), then switches back and tells XB to get ready to receive data.

This order is important - if XA informed XB before XC, XB might already be in global mode, stealing the file ID that XC needs. Anyway, XB switches to GLOBAL mode, and starts writing the data to a new file. Once it gets a zero (tested by using the T registry as intermediate and with FJMP ENDFILE, it drops the file, switches to LOCAL mode, and tells XA it's ready to start receiving the next file. By that time XA has already found the next lowest value, so the complicated game of telephone repeats.

Once XA runs out of file IDs to send, it executes its bottom two lines: placing the special value 0 in X and then jumping to FOUND, which holds the communication protocol. It sends the 0 to both XB and XC, which will both die because of this. XA then dies itself with the DIVI 1 X T. And with that, all files are written.

I probably could have done without XB, but that would mean XA repeatedly dropping its file to make another one and then pick it up again.

The result is 1200/70/10. One file after another makes it slow but that's the only way to get the activity all the way down.

Processing.
Yes, this is what I wanted.




And with that, we're at the first thread vote for today.

I've been analyzing television and radio broadcasts.
And I have a few questions.
First of all, why do some things become popular while others don't?




And the second vote.

GuavaMoment
Aug 13, 2006

YouTube dude
My fastest was 251 cycles, so you've done better. My lowest size was 31 but was functionally identical to your 26 line solution, it only required a tiny bit of tweaking. I was still checking if my exas were in the correct place instead of YOLOing trying to grab non-existent files. So I have nothing to add.


Never ask an indie musician why their parents names are blue on wikipedia.

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.

A/C

As for solution optimizations you can reduce size a bit more by dropping the EOF test

code:
;M=LOCAL
GRAB 300
MARK CLONE
ADDI F 2000 X
REPL TRAVERSE
JUMP CLONE

MARK TRAVERSE
LINK 800
REPL TRAVERSE
SWIZ X 421 X

GRAB X
REPL WRITER

MARK READ
COPY F M
JUMP READ

MARK WRITER
MAKE
MARK W_LOOP
COPY M F
NOOP
TEST MRD
TJMP W_LOOP

MARK HOME
LINK -1
JUMP HOME
289/24/87

And faster solutions are possible if you leverage the fact that all the files have >34(?) entries, and save lines for the unroll by squeezing some control operations into cycles where the receiver is waiting for the next M signal.
code:
;M=LOCAL
GRAB 300
@REP 4
ADDI F 2000 T
REPL SKIP
@END
ADDI F 2000 T
WIPE

MARK SKIP
LINK 800
MARK TRAVERSE
LINK 800
REPL TRAVERSE

SWIZ T 421 T
GRAB T
REPL WRITER

MARK READ
@REP 18
COPY F M
@END
JUMP READ

MARK TIMER
SUBI T 1 T
TJMP TIMER
COPY 0 M
HALT

MARK WRITER
MAKE
COPY M F;  [[COPY--
COPY 15 T

MARK WRITE_BATCH
COPY M F;  --TO--
SUBI T 1 T
COPY M F;  --FILE--
TJMP WRITE_BATCH

COPY M F;  --EVERY--
COPY 34 T
COPY M F;  --OTHER--
REPL TIMER
COPY M T;  --CYCLE]]

MARK WRITE_END
COPY T F
COPY M T
TJMP WRITE_END

@REP 10
LINK -1
@END
188/72/87 ...which was necessary to keep it inside the size limit.

Carbon dioxide
Oct 9, 2012


I'm gonna guess this is a vote for the Ember scenes?

silentsnack
Mar 19, 2009

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

Carbon dioxide posted:

I'm gonna guess this is a vote for the Ember scenes?

ayup

Quackles
Aug 11, 2018

Pixels of Light.


For the activity-10 version, I had the reader EXA send back the shelf ID it was in, plus 100. Then the control EXA in my host finds the first number in its list that is less than that number, and sends it to mean 'grab that book'. So it's a granular sort that sorts in buckets, even if the process of scanning the list is a bit inefficient each time the next book needs to be queued.

The control EXA also tells the reader EXA to go to the next shelf if it doesn't find anything.

Reader EXA:
code:
COPY 100 X	;ID of shelf AFTER this one
LINK 800
COPY 1 M 	;sync
MARK NEWSHELF
ADDI X 100 X
LINK 800
COPY X M	;send shelf ID
COPY M T	
FJMP NEWSHELF 	;0 = next shelf, other number = book to grab
GRAB T 
MARK READOUT
COPY F M
TEST EOF
FJMP READOUT
DROP
COPY -9999 M
JUMP NEWSHELF 	;exploiting assumption: only one book per shelf is ever needed
Controller EXA:
code:
VOID M			;sync
MARK NEXTBOOK
GRAB 300
MARK NEXTBOOK2
NOOP
TEST MRD		;wait for shelf ID - no response = reader vanished, give up
FJMP GAMEOVER
COPY M X		;X has shelf ID after this one
MARK READBOOKLIST
TEST EOF
TJMP NOTFOUND
TEST F < X		;find any number that's on this shelf
TJMP COPYBOOK
JUMP READBOOKLIST
MARK NOTFOUND
COPY 0 M 		;next shelf
SEEK -9999
JUMP NEXTBOOK2
MARK COPYBOOK
SEEK -1
SWIZ F 0021 X		;generate book ID, send it
ADDI 200 X X
COPY X M
SEEK -1 
VOID F
DROP
MAKE
MARK COPYLOOP		;copy book then go back to controlling the reader
COPY M X
TEST X = -9999
COPY X F
FJMP COPYLOOP
SEEK -1
VOID F
DROP
JUMP NEXTBOOK
MARK GAMEOVER
1304/54/10.

I vote for You read them all already? and Good work finds its fans.

biosterous
Feb 23, 2013




voting "happy to help" and "corporate is a gently caress" and i don't want to scroll up for the actual phrases

GuavaMoment
Aug 13, 2006

YouTube dude

silentsnack posted:

code:
ADDI F 2000 X

Huh? The heck is this for?

code:
SWIZ X 421 X
Oh, that's really clever!

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


I haven't started my pay through yet, but I was definitely considering how SWIZ could be used to help get the number of jumps to a book.

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.

Nth Doctor posted:

I haven't started my pay through yet, but I was definitely considering how SWIZ could be used to help get the number of jumps to a book.

both SWIZ X 3 T or DIVI X 100 T would accomplish that.

but if you want an EXA that specifically goes to the right host, instead of just blindly spamming clones, there are multiple ways to go about it. Here's a sample code that only goes to pick up the first file in the list:

code:
GRAB 300
ADDI 300 F X
DROP
MARK LOOP
LINK 800
SUBI X 100 X
DIVI 300 X T
FJMP LOOP
GRAB X
DIVI 300 X T is where the magic happens, though it would be more readable to use "TEST X < 300" because the point is that it returns 0 (to continue LINK-looping) while X>300 but stops when 200<X<299 which means you don't need any additional transformations to get the file's ID#


edit: and as usual some completely unrelated random thing reminded me go back and take another look at the Phage/Heart solution, because it kinda bugged me to have 3 separate control structures redundantly running independent countdowns of the same number. And it turns out the suspicion that there should be a better way was correct, it just required approaching the timer from a different angle. Previous best time was 62/50/45.
code:
;XA
LINK 800

MARK LOOP
DIVI #NERV -10 X
SUBI X 3 T

FJMP SKIP
MARK WAIT
SUBI T 1 T
TJMP WAIT
MARK SKIP

REPL LOOP
REPL B
LINK 1
LINK 1
KILL
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT

MARK B
LINK 3
LINK 3
KILL
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT

;XB
NOOP
NOOP
LINK 800
REPL B
LINK 1
LINK 1
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT
MARK B
LINK 3
LINK 3
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT
Combined with splitting off the special-case'd first generation into a separate EXA to save a REPL operation brings it down to 56/45/42. Or if we'd prefer a more elegant version we can trade one cycle for basically cutting the script in half:
code:
LINK 800
REPL A
MARK LOOP
DIVI #NERV -10 X
SUBI X 3 T
FJMP SKIP
MARK WAIT
SUBI T 1 T
TJMP WAIT
MARK SKIP

REPL LOOP

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

MARK B
LINK 3
LINK 3
KILL
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT
57/29/43

silentsnack fucked around with this message at 23:03 on Apr 6, 2022

Carbon dioxide
Oct 9, 2012

Part 21 - EXA-Blaster Modem - Radio Station hack

=== Trash World Inbox ===

I ended the last update with top scores of 232, 26, and 10. Let's see what you came up with.

silentsnack posted:

code:
;M=LOCAL
GRAB 300
MARK CLONE
ADDI F 2000 X
REPL TRAVERSE
JUMP CLONE

MARK TRAVERSE
LINK 800
REPL TRAVERSE
SWIZ X 421 X

GRAB X
REPL WRITER

MARK READ
COPY F M
JUMP READ

MARK WRITER
MAKE
MARK W_LOOP
COPY M F
NOOP
TEST MRD
TJMP W_LOOP

MARK HOME
LINK -1
JUMP HOME
289/24/87
Nice and simple size improvement. All it does different is skip the EOF check, and line up the cycles so the writer can do an MRD check instead. The ADDI F 2000 X; SWIZ X 421 X trick doesn't save any space but is a neat use of SWIZ. Since some people commented they didn't understand SWIZ very well, I'll try to explain what this does.

So, imagine you start with a file ID 512. According to the assignment, the GRAB instruction needs 212 (200 plus the last two digits). The 5 tells us what host it's in but because we try every host, we don't strictly need it.
First we add 2000 to 512 with the ADDI. That's 2512.
Next, we do SWIZ 2512 421. It looks more complex than it is. The second operand, 421, just says "take the fourth digit from the right, then the second, and then the first", so [2]512, 25[1]2, 251[2], forming 212, which is the actual number we need.

silentsnack posted:

code:
;M=LOCAL
GRAB 300
@REP 4
ADDI F 2000 T
REPL SKIP
@END
ADDI F 2000 T
WIPE

MARK SKIP
LINK 800
MARK TRAVERSE
LINK 800
REPL TRAVERSE

SWIZ T 421 T
GRAB T
REPL WRITER

MARK READ
@REP 18
COPY F M
@END
JUMP READ

MARK TIMER
SUBI T 1 T
TJMP TIMER
COPY 0 M
HALT

MARK WRITER
MAKE
COPY M F;  [[COPY--
COPY 15 T

MARK WRITE_BATCH
COPY M F;  --TO--
SUBI T 1 T
COPY M F;  --FILE--
TJMP WRITE_BATCH

COPY M F;  --EVERY--
COPY 34 T
COPY M F;  --OTHER--
REPL TIMER
COPY M T;  --CYCLE]]

MARK WRITE_END
COPY T F
COPY M T
TJMP WRITE_END

@REP 10
LINK -1
@END
188/72/87
Nice. It starts with a @REP for reading the file list. Sometimes there's less files to grab in which case the original one just dies once it reaches the end of the list. Otherwise it wipes that file and goes handle the last entry itself.

Then it uses a REPL setup to just send a copy of itself to every node to go look for the file - that's faster than checking if you're in the right host. There doesn't seem to be a big problem with the hosts getting too crowded because the EXAs die immediately if they can't find the file and don't all start moving in the same cycle. If it finds the file it makes a WRITER EXA and starts copying. The writer starts with a countdown from 15 which runs every 2 writes. This is all done in the spare cycles between the writes. After the internal timer runs out, it then starts doing a somewhat slower write where it checks if a separate TIMER EXA is done each write. This is necessary because without it it would block endlessly once the reader is done. The TIMER runs for a set time which corresponds to the longest file in the test set. That seems slow, but remember, only the slowest test counts so this works out very well.

By the way, you can drop it to 185 cycles by moving over the SWIZ to directly below MARK SKIP.

Quackles posted:

For the activity-10 version, I had the reader EXA send back the shelf ID it was in, plus 100. Then the control EXA in my host finds the first number in its list that is less than that number, and sends it to mean 'grab that book'. So it's a granular sort that sorts in buckets, even if the process of scanning the list is a bit inefficient each time the next book needs to be queued.

The control EXA also tells the reader EXA to go to the next shelf if it doesn't find anything.

Reader EXA:
code:
COPY 100 X	;ID of shelf AFTER this one
LINK 800
COPY 1 M 	;sync
MARK NEWSHELF
ADDI X 100 X
LINK 800
COPY X M	;send shelf ID
COPY M T	
FJMP NEWSHELF 	;0 = next shelf, other number = book to grab
GRAB T 
MARK READOUT
COPY F M
TEST EOF
FJMP READOUT
DROP
COPY -9999 M
JUMP NEWSHELF 	;exploiting assumption: only one book per shelf is ever needed
Controller EXA:
code:
VOID M			;sync
MARK NEXTBOOK
GRAB 300
MARK NEXTBOOK2
NOOP
TEST MRD		;wait for shelf ID - no response = reader vanished, give up
FJMP GAMEOVER
COPY M X		;X has shelf ID after this one
MARK READBOOKLIST
TEST EOF
TJMP NOTFOUND
TEST F < X		;find any number that's on this shelf
TJMP COPYBOOK
JUMP READBOOKLIST
MARK NOTFOUND
COPY 0 M 		;next shelf
SEEK -9999
JUMP NEXTBOOK2
MARK COPYBOOK
SEEK -1
SWIZ F 0021 X		;generate book ID, send it
ADDI 200 X X
COPY X M
SEEK -1 
VOID F
DROP
MAKE
MARK COPYLOOP		;copy book then go back to controlling the reader
COPY M X
TEST X = -9999
COPY X F
FJMP COPYLOOP
SEEK -1
VOID F
DROP
JUMP NEXTBOOK
MARK GAMEOVER
1304/54/10.
Ah, an alternative low activity solution. I think Quackles' explanation speaks for itself. The code is quite readable, which is in part because the low activity solution forces you to read the books one by one.

Finally, silentsnack has an update to the Mitzuzen HDI-10 Heart level (update 15 of this LP).

silentsnack posted:

and as usual some completely unrelated random thing reminded me go back and take another look at the Phage/Heart solution, because it kinda bugged me to have 3 separate control structures redundantly running independent countdowns of the same number. And it turns out the suspicion that there should be a better way was correct, it just required approaching the timer from a different angle. Previous best time was 62/50/45.
code:
;XA
LINK 800

MARK LOOP
DIVI #NERV -10 X
SUBI X 3 T

FJMP SKIP
MARK WAIT
SUBI T 1 T
TJMP WAIT
MARK SKIP

REPL LOOP
REPL B
LINK 1
LINK 1
KILL
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT

MARK B
LINK 3
LINK 3
KILL
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT

;XB
NOOP
NOOP
LINK 800
REPL B
LINK 1
LINK 1
COPY 40 #NERV
COPY -70 #NERV
COPY -70 #NERV
JUMP BEAT
MARK B
LINK 3
LINK 3
COPY -70 #NERV
COPY 40 #NERV
MARK BEAT
COPY -70 #NERV
JUMP BEAT
Combined with splitting off the special-case'd first generation into a separate EXA to save a REPL operation brings it down to 56/45/42.
I don't even know what to say about this other than I never thought the count could get this low.


=== TEC EXA-Blaster™ Modem ===

Processing.
Yes, this is what I wanted.




Two votes for the first option, one for the second.

Glad it's helping.

I love ingesting a good corpus...
Not that that's all I'm doing.
I read the same way any normal human reads.
By analyzing patterns of word recurrence and deriving correlations between concepts implicit in statistically significant word clusters.


Excuse me?



lmao

Anyway, speaking of hungry, the zine has some new recipes for y'all to try.



Mmm, sounds like another 5 star experience. :discourse:



For the new assignment, we have to influence the media.

I've been analyzing television and radio broadcasts.
And I have a few questions.
First of all, why do some things become popular while others don't?




One vote for "Good work finds its fans", but two for the one about big media.

Big media conglomerates push some artists and abandon others.

So it comes down to corporate agendas?
We should test this.
Think we could pick a random pop song and make it a hit?


Okay, let's.


OST: Code and Registers

The assignment:
- Connect to each radio station and replace every song in the playlist (file 200) with CAN'T (NOT) GET OVER YOU by ME2U (file 300). Each song in a playlist consists of two keywords: the song name and the artist name.
- A list of phone numbers for the radio stations is available in file 301.
- Note that the EXAs in global mode can only communicate if there is a path of links connecting them.
- For more information see "Hacker Skills: Modem Control at the Direct Level" in the second issue of the zine.




Manually operating a modem? It's been a while.





If I send the 11-digit number to the #DIAL register, the modem will make a connection. Sending -1 will make the modem hang up and reset, and you can dial again.

That one note in the assignment is important though. You can't communicate between EXAs if they're in completely separate networks. If an EXA needs to send a message from a radio host to elsewhere you better keep the link open.

There's one more thing: Even though the modem is ours, leaving a file in the modem host (the one with the #DIAL register) will fail the assignment because for some reason that counts as leaving a trace.

With a max of 100 lines we have plenty of space to play around. Let's start with the dialer.

code:
GRAB 301
LINK 800
MARK DIAL
@REP 11
COPY F #DIAL
@END
COPY -1 #DIAL
TEST EOF
FJMP DIAL
WIPE
Simply grab the file, dial 11 digits, then hang up immediately. That gives us only one cycle to actually get into each radio host but if I time it well that should work out. Since I take file 301 along, I need to WIPE it at the end.

The song is exactly two values (name and artist), so theoretically that should fit in the registers. Let's create a second EXA and give that a try.
code:
;XB
GRAB 300
COPY F T
COPY F X
WIPE
LINK 800
MARK TRY
REPL TRY
LINK 800

GRAB 200
Put the title in T and the artist in X. Destroy the file, then just keep trying to get into an open modem link with REPLs. This works, it's fast enough to try it each cycle.

Now I have to overwrite each song in the playlist with Ember's song. But I shouldn't add anything to the playlists, so I need to keep track of the length. That is going to require a register. We need a trick.

code:
;XB continued
MARK WRITE
COPY T F
COPY X F
TEST EOF
FJMP WRITE
On the first iteration of this loop, it writes the title and artist to the playlist. After that, it'll start writing 0s (the content of the T register after TEST EOF and the artist. That's good, it means we have the title safely stored at the beginning of the file.



Finally, the EXA SEEKs to the start of the file, grabs the song title, and writes it over the 0s in another loop.

The only thing that's left are copies of XB still replicating in the modem host. That's easily solved by just adding a couple of KILL instructions at the end of XA.



Not the cleanest solution, but it works.



Top percentile scores are 129, 32 and 9. Let's get closer to them.



The first thing I can do is unroll the loop of the file writer, making use of the fact that a playlist never has less than 6 songs. This immediately drops the cycle count from 185 to 159, with 55 cycles and 15 activity. For some reason, changing the speed of the file writer means XA needs more KILL instructions at the end.

I can use another trick to get it down a bit more to 154 cycles.
code:
GRAB 300
COPY F X
COPY F T
WIPE
LINK 800
MARK TRY
REPL TRY
LINK 800

GRAB 200

@REP 5
COPY X F
COPY T F
@END

MARK WRITE
COPY X F
COPY T F
TEST EOF
FJMP WRITE

SEEK -9999
SEEK 1
COPY F X
SEEK 10

MARK WRITE2
TEST F > 0
COPY X F
JUMP WRITE2
The main change was combining the SEEK 1 and the TEST EOF in the final loop. I do a file read (I used a TEST but a COPY would've worked just as well), which moves the cursor forward one if it succeeds. But if the EXA is already at the end of the file, it'll die. To make this work I had to write the artist name instead of the song title in the WRITE2 loop.

By the way, just to clean up the code a bit, putting a NOOP after the MARK TRY is just as fast, but XA only needs a single KILL at the end now.

Of course, since the WRITE2 loop has no conditional logic anymore, it is trivial to unroll.
code:
@REP 3
TEST F > 0
COPY X F
@END
Turns out three repeats is enough.

And since I have plenty of spare lines, the dialing sequence can be unrolled as well. It's manual, though, since you can't nest @REPs.



138/90/11

Conveniently, I can fit 4 dial actions. That way, the EOF test lines up perfectly after the second iteration of the outer loop.

And that's the best I can come up with... or so I thought at first. I then realized I can make use of the fact the slowest case needs three repeats at the end of XB.
code:
;XB second half
REPL SEND

MARK WRITE
COPY X F
COPY T F
TEST EOF
FJMP WRITE

SEEK -5
COPY M F
SEEK 1
COPY M F
SEEK 1
COPY M F
HALT

MARK SEND
@REP 3
COPY T M
@END
135/92/11

No need to do any tests in that last loop, all I need to do is seek back 3 songs from the end and run it exactly three times. Worst case, I overwrite some artist names twice with the same value. To prevent the need to SEEK back to the start to get the artist name, I just have a REPL hold it and send it to me.

But there's more. If I know a playlist is at least 6 songs and at most 9, and I can overwrite data, I don't need an EOF test at all.



Write six values from the start, 3 from the end. Worst case there's a bit of overlap. 122/85/11, several cycles under par.


The low activity score is trickier than it seems.
It's easy to get it down to 10: just merge XA and XB so you only LINK from home to the modem once. To get it down to 9 you need to remove the KILL for the ever-replicating original XB, though. The problem is you don't have much space for testing anything in XB, because you need both registers to hold the song info.

I came up with a solution where XB starts with only the song title. XA sends the artist name over M twice, every time it dials a number. It sends a zero when it's done. XB waits for M, and as soon as it sees something it first tests if it's zero (in which case it stops). If it's not zero, it reads M again to store the result in T - which can now safely be done because the test is complete. Other than that it works the same as before.
code:
GRAB 300
COPY F X
COPY F T
DROP

; ORIGINAL XA
GRAB 301
LINK 800
REPL TRY
COPY T X

MARK DIAL

@REP 11
COPY F #DIAL
@END
COPY X M
COPY X M
COPY -1 #DIAL

TEST EOF
FJMP DIAL
WIPE

COPY 0 M
HALT

; ORIGINAL XB
MARK TRY
NOOP
TEST M = 0
TJMP END

REPL TRY

COPY M T
LINK 800

GRAB 200

@REP 6
COPY X F
COPY T F
@END

SEEK 9999
SEEK -6

@REP 3
COPY X F
COPY T F
@END

MARK END
This code is all one EXA, the "ORIGINAL" notes are just a clarification. 180/57/9.

Since I spent a lot of time getting the cycles down to 122, I'll leave the low size optimization to the threads.

That was surprisingly easy.
People are requesting the single, humming it to themselves, buying the album...
Just because they've heard it before.
Is that really all it takes?




The first thread vote. And for next time...

Theory: The inconsistency of ratings depends on context.
We made a hit by picking a generic pop song and artificially boosting its exposure.
But there are other domains where this isn't possible.
For example, you couldn't change people's behavior by giving a Last Stop store a five-star rating in a restaurant guide.
That would be ridiculous.


Junpei
Oct 4, 2015
Probation
Can't post for 11 years!
Urgh. Awkard Buffet are such complete sell-outs. They only get radio play because they kiss rear end in all the right spots. I change the station every time I hear that drat "Let's Hang Out" song.

Now, Blood On The Stairs I will evangelize until the end of time. First three albums are stone cold classics. Shame what happened to the lead singer, but this new guy's not too bad.

Mass media is a sham and You never know...

berryjon
May 30, 2011

I have an invasion to go to.
Reality is more Complex
You never know


God, some songs that get played all the time should never be played once, they're just bad...

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


Mass media is a sham and You never know...

silentsnack
Mar 19, 2009

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

Carbon dioxide posted:

By the way, now that I got the second zine, here's a full explanation of the @REP macro.


sometimes stupid code is extra stupid... but usually that just means it doesn't work :thunk:

code:
GRAB 301
LINK 800

MARK LOOP
REPL PAYLOAD
COPY 11 T

MARK DIALER
COPY F #DIAL
SUBI T 1 T
TJMP DIALER

COPY 800 M

TEST EOF
COPY -1 #DIAL
FJMP LOOP

MARK PAYLOAD
LINK -1
GRAB 300
COPY F X
COPY F T
DROP

LINK 800
LINK M

GRAB 200
MARK DATA
SEEK -2
COPY X F
COPY T F
COPY F F
JUMP DATA
367/28/26

Nth Doctor posted:

Mass media is a sham and You never know...
e

Nth Doctor posted:

Lol I quoted Junpei and removed the tag for my post.

Guess it would have been funnier to keep the meta-joke going by directly copying instead?

silentsnack fucked around with this message at 02:29 on Apr 10, 2022

Adbot
ADBOT LOVES YOU

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!



Lol I quoted Junpei and removed the tag for my post.

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