|
|
# ¿ May 18, 2024 10:54 |
|
EXA language reference guide (click to enlarge) Carbon dioxide fucked around with this message at 17:26 on Dec 18, 2021 |
# ¿ Nov 28, 2021 09:42 |
|
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 LISTEN to this. Seriously. 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. (click to enlarge) 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. (click to enlarge) 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 17:08 on Apr 9, 2022 |
# ¿ Nov 28, 2021 09:42 |
|
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 17:11 on Apr 9, 2022 |
# ¿ Nov 28, 2021 09:43 |
|
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.
|
# ¿ Nov 28, 2021 11:55 |
|
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. GuavaMoment posted:Do you have the physical version of this game? 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 17:49 on Dec 4, 2021 |
# ¿ Dec 4, 2021 17:47 |
|
Part 4 - TRASH WORLD NEWS - Tutorial 3megane posted:A way to save a cycle (without using any new operations) is SUBI X F F. 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.
|
# ¿ Dec 12, 2021 10:49 |
|
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 17:43 on Dec 18, 2021 |
# ¿ Dec 18, 2021 17:22 |
|
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 17:48 on Dec 18, 2021 |
# ¿ Dec 18, 2021 17:23 |
|
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:
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.
|
# ¿ Dec 18, 2021 19:45 |
|
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.
|
# ¿ Dec 19, 2021 09:04 |
|
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. 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 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) 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. 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: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 In other words, this unrolls into code:
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. 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 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 16:30 on Dec 24, 2021 |
# ¿ Dec 24, 2021 16:25 |
|
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. 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" 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 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.
|
# ¿ Dec 31, 2021 09:21 |
|
Part 8 - Peanut-free Peanut bars As a reminder - you can freely skip the Inbox if you like, the 'regular' updates below them won't depend on them. === Trash World Inbox === Another part in Euclid's Pizza discussion: GuavaMoment posted:OK, there's some really slick M register copying and timing going on here, but you do have to store "Cheese" from the original file first. What's less obvious to me is why REPL SEND1 saves a cycle even though the original EXA has to pause for two cycles. No, you can't just replace one of the NOOPs with the COPY in SEND1 and call it a day. I suspect an M transmission always pauses an EXA an additional cycle so having another EXA do that saves time. Then, a lot of ideas about the arm hacking (not to be confused with ARM hacking). Quackles posted:There is a way to be very clever here: it turns out EXAs have built-in clamping functionality. If a number goes above 9999 or -9999, it is set to 9999 or -9999. Integer division also truncates, making a multiply/divide ideal for clamping. It's funny, the limit of 9999 always trips me up because in real programming, you never have that kind of limit. Since everything is binary, the limits are usually some power of 2. And if you go beyond them, the program won't cap, instead it will overflow and go far into the negatives. I understand why this game didn't do that - it's hard enough as it is without introducing concepts such as two's complement. silentsnack posted:Oof. This puzzle made my brain hurt. There's a trick to speeding up operations by running multiple instances in parallel instead of sequentially, but then you have to deal with non-deterministic outcome of race conditions like when two EXAs try to take the same link in the same frame, so solutions would sometimes work and sometimes break for no apparent reason. This was my previous fastest solution, with some fairly insane workarounds: I'm going to do some line by line commentary, both for my own understanding and for any readers. code:
code:
Now, the question is, where do those Ms come from and why do they need 120 subtracted? code:
code:
As for the arithmetic, you take the original value plus 120 and put that in X. So if it was originally -120, it is now zero. If it was 50, it is now 170. Next, you divide the result by 170 and store that in T, and use it for a conditional jump. When is T true and when is it false? Well, DIVI always rounds towards zero. That is, if 0 / 170 = 0, and 169 / 170 = 0, but 170 / 170 = 1. So, T is true if X is 170 or higher - that is, if the original value is 50 or higher, and needs to be clamped. However, if X is -170 or lower, we get -170 / 170 = -1, which counts as true. So if the original is -290 or less we'd also get a true. We know in this case it needs to be clamped to -120. How about the range between -290 and -120? If this is the clamping test we'd miss those... And that's right. Turns out that no numbers within that range appear in any of the test. This code is truly a dirty hack. code:
code:
What makes this so fast is that the clones are constantly handling different numbers. While one clone is sending a number to M, the next one is doing the conditional jump, the one after that is simultaneously dividing its number by 170, and so on. You can do a lot with parallellism. However, as silentsnack said, it's easy to get race conditions where you aren't sure which EXA is going to do what first. It's easier to deal with here than in a real computer, because you know each EXA gets exactly one instruction per cycle, so as long as you time their cycles well and make sure they don't try to send to M simultaneously, it should work out. silentsnack posted:
By the way, the REPL OUT structure works as follows: it sends a clone to the next host, then tries to send its message to #NERV. If it isn't at the ARM host yet, it will crash because #NERV isn't found (making sure clones don't clutter the host), and if it is at the last host, the clone will crash because it can't LINK to 1 but the original will succesfully write the value to #NERV. silentsnack posted:
As for XA, it doesn't matter for the cycle count whether you use two continuously looping EXAs or an endless batch of clones that all try to write to #NERV ones. This just needs a couple less lines of code. I kinda like the "balance" of having to go through ugly hacky code first before it turns out the best solution is very clean. Happens surprisingly often in real life too. === Last Stop Snaxnet - peanut-free Peanut Bars === This hotfix should keep you useful, at least for a little while longer. I'm glad I don't have a body. This vote was unanimous. You get used to it. If you say so. Seems like nothing but a hassle. Maybe one day... well, we can talk about that later. Wait, Ember wants a body? What! I didn't know about that either. In case you were wondering, the tab key lets the simulation step to the next cycle. This ctrl+click thing is what's known as a breakpoint. It's very useful to see how a specific part of your code behaves, especially conditional branches that are rarely triggered. It will stop there, you can then manually advance the program again, and if you like you can use ctrl+click to go to the next breakpoint. Seriously, I actually forgot this was a thing until the chat reminded me. No new assignments appeared since I patched my arm, so time to go tackle Snaxnet. 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. One vote for "Okay." and four for "This is silly." This is silly. It's an experiment. Hypothesis: It will be very funny. New OST: Network Exploration The assignment: - Remove the keyword PEANUTS (file 300) from the Peanut Blast recipe (file 237). - Note that the target keyword will appear in a different position in each of the 100 test runs. To view and debug each of the different test runs, click the arrow buttons next to the "TEST RUN" display above. So, first of all, we're going to have to find the word PEANUTS. Now, the problem with keywords is that you can't just type them in your code like you can numbers. You need to have a reference somewhere, which is why file 300 is sitting in my home host, with just that word. Secondly, that tip is useful if you hadn't realized yet. Those little arrows next to 1/100 allow you to see each of the 100 tests ahead of time. They also allow you to debug specific test runs, in case your program only fails for one of them. These are all the files we have access to. We don't need those files with the dates, though. Let's start building. My initial solution. First grab the reference file and load PEANUTS into the EXA. Then go to the factory's file. Finding a specific value in a file is simple: just do a TEST for that exact value repeatedly. Every file access moves the cursor forward one, so that is the whole loop. Then, once it finds the right value, it needs to go back one step in the file with SEEK -1 (because the last TEST moved it just beyond that point) and then use the VOID command to get rid of the value. As the EXA dies, it drops the file, and that's it. Not bad, already at the lower range of the histograms. But this is one small improvement I came up with. Save some cycles by having one EXA immediately go to the factory's file, while another grabs our reference and sends the value over to the other EXA. Result: 29/11/2 If there are further improvements possible, I don't know them. It's nice to have a simple puzzle after the very complex optimizations from the thread last week though. By the way, messing with the hardware registers really doesn't do anything here except change that I/O status view and immediately fail the test on the 'Leave no trace' goal. Okay, I don't know how I feel about this. Processing. No peanuts in Peanut Blast. Was that funny? I don't know, was it? Meanwhile... Crap. We're gonna need that second Zine. Let's ask Ember for help. You're gonna help Ghast with his copy shop bill? That's kind of you. And that's the second vote for today.
|
# ¿ Jan 8, 2022 15:41 |
|
I discovered that not only does one of the original RL Zines still exist, it occasionally (every 5 years or so) releases a new issue. Phrack issue 70, released October 2021.
|
# ¿ Jan 11, 2022 08:29 |
|
Part 9 - Point of Sale System === Trash World Inbox === First of all, there was some discussion in the thread about overflow and clamping, and how clamping is rare in real computers. That's certainly true, and it's a direct result of how binary counting works. Without going into a complete electronics lesson: in the end a binary number in a CPU register is just represented as a bunch of electrical parts that have a voltage on them (1) or not (0). If you add two numbers together, it uses logic gates in such a way that 0 + 0 = 0; and 0 + 1 = 1. 1 + 1 = 0 too, but in that case you tell the next bit over to add a carry bit. Imagine if all the bits are 1 (e.g. 1111 1111), and you add 1 to it. The rightmost bit will become zero and tell the second bit to carry. 1 + carry = 0, and it tells the next one over to carry. At some point you have 0000 0000 with the most significant bit telling the next one over to carry - but there's no next one so that carry bit just disappears into the void and your answer becomes 0. Overflow is a natural result of circuit design, and to make clamping possible would require circuits to be much more complex. ColTim posted about some advanced instructions where clamping happens, but that's complex vector and matrix calculations so there you're way beyond basic addition circuits anyway. GuavaMoment posted:Unroll the loops! Instead of FJUMPing to the start of the loop you're going to have to TJUMP to an end condition (which is SEEK -1, VOID F). This will get you 27 cycles. code:
For the second half: code:
Note that both of these solutions require timing the worst case test precisely. Or, trial and error. Just putting different numbers in the @REP and the XC loop and find the lowest numbers that still work. === Zebros Copies - Point Of Sale System === Okay, I don't know how I feel about this. Processing. No peanuts in Peanut Blast. Was that funny? Three votes for "I don't get it" and one for "Kind of". I don't get it, no. You have to imagine someone wanting peanuts really bad, and not getting them. Or is that just torture? More data for the corpus. Let's continue. I'm not sure if I like all that data collection. You're gonna help Ghast with his copy shop bill? That's kind of you. One vote for "He's an old friend", and three for "I help people when I can." I help people when I can... Is that altruism? I've heard of that. This is the first time I've seen it in the wild. I'm going to have to add a new table to my database. How old are you anyway? Or is that a rude question to ask an AI? Our assignment this time is to clear Ghast's tab. OST: Network Exploration The assignment: - Erase Ghast's debt to the copy shop by zeroing out his balance in the customer database (file 200) and appending a payment to the payment log (file 201) with today's date and the exact amount of his prior balance. - Ghast's customer ID is available in file 300. - For more information see "Network Exploration: Digicash Point-of-Sale Systems" in the first issue of the zine. Oh, the zine has a page on this? Let's see. Alright, so if I understand correctly, you're in trouble if your operating system is a Point of Sale. Before I dive into the assignment, let's mess around a bit first. Move a bunch of EXAs into the COPY hosts and have them write 999 to the #COPY hardware register constantly, hehehe. The value is capped at 99, and if you pause your EXAs you see it slowly decrement while the copiers in the view of the camera are constantly printing. The EXAs constantly push it back up to 99. If you let this run for a while you get the TONER_LOW Steam achievement. Looking at the assignment, it definitely feels like the training wheels are coming off now. Before we start it's a good idea to think of a general approach. I need to do several things here. First, the line in file 200 that matches Ghast's customer ID in 300 should get a pair of 0's. Secondly, I need to add a line to file 201 containing the current date, Ghast's ID, and then the amount that used to be in file 200. So I need to keep track of that too. I can get the current date from the #DATE hardware register. Perhaps it also works to copy from the last line in file 201, but I'm not sure if that works for all tests. Worth a try in the optimizations, but let's start simple. I'll try to take you along with my train of thought when working on a programming assignment such as this. This deals with file 200. XA grabs the file containing Ghast's ID and sends it over M. Meanwhile XB immediately links to 800, wasting no time with grabbing files in my home host. The FINDLOOP has a SEEK 2 since it only needs to test every third value in the file. In the most naive approach, you would test, then do a conditional jump, and then only move forward in the file if you're not there yet. But since you can't just put the SEEK 2 at the start (because then it would skip the first value in the file), I can't think of a way to do that without 2 conditional jumps per loop. That would be at least one cycle PER LOOP extra. Instead I just put a single SEEK -2 beyond the loop which is always one cycle extra, regardless of how often the loop runs. Keeping loops short is key for a low cycle count. After that, I first store the current amount in X and T, and then SEEK back once more to write 0s to the file. That's file 200 done, although I still have to do something with the current amount. There's different ways I could handle appending the log. I could have XB do that after it's done with 200. I could spawn a fresh EXA, have it link to 800, grab 201, and do stuff with it. Or I could use REPL commands in XB. Having XB handle everything feels slow, since it can only grab the new file after it's done with the old. That, or REPL, would be a good way to get a low activity score though, since you have less EXAs to LINK from the home host. However, a REPL costs a cycle for XB, during which it could be doing something useful. For low cycle count, using an additional EXA sounds best. I decided to start with the additional EXA, and try the REPL solution later for a better activity score. XB has been changed, and I added XC. Let's look at the latter first. XC starts by waiting a cycle. Since it'll have to wait for data from XB, we need to make sure XB can get to work as fast as possible. Once it's in the network, it first makes a DATEGETTER which does nothing but jump to the CLOCK host and send the current date to M. The base XC GRABs file 201, goes to its end, and writes the first value from M in there. It's important to get the DATEGETTER going right away. This way, it posts its message to M, even before XB is through its very first loop. This ensures that no matter what else comes on M, the date will always be first. As for XB, it no longer stores the old amount to X and T, but sends them to M instead. Before it does so, though, it also sends its value in X (Ghast's ID) to M, so that XC can use that for the payment log. And with that, I'm already very close to a working solution. Since I took care of sending the different values to M in the right order, all that was left was adding some additional COPY instructions to XC. The 'fixed' files. The first result is not bad at all. The cycles are right there among the lowest peak on the histogram. As for lowering them, I tried unrolling the loop but I didn't find an immediate benefit. You still have to do those conditional jump checks every time. I did manage to lower it to 58 with this solution: code:
We already know we can improve Activity with some REPLs: code:
Turns out I was wrong about this using more cycles. A 1-activity solution would be possible only if we could grab the last date from the log file and reuse that. However, the devs thought of that and have a test where the oldest log line isn't from today, so that won't work. Finally, it looks a decent improvement possible in the size is possible. I'd love to see what the thread comes up with. Is that copy shop name unusually weird to you? It's an outlier in my model. What is "Zebros" supposed to be? Here is the first vote for this update. [x10x10x]: eh [x10x10x]: not worth it Just in case you hadn't realized, we're not hacking simulations anymore. My hacks have real world consequences, even if it feels everything happens in this little box in my room. *Knock knock* OST: Apartment What's this now? Isadora: Hello? Isadora: You in there? This voice... It's Isadora. I remember the name but not much else... Isn't this someone I've known for a long time? Isadora is voiced by Krizia Bajos. Hey. I brought you some snacks. It's, um, well it's Peanut Blast, but without the peanuts. I guess there was some screw-up at the factory, so now we have a bunch of these that we can't sell. Seemed like a waste to throw away. Isadora hands me a few of the non-peanut-containing Peanut Blast candy bars. I hope you're doing okay. We should hang out again sometime. I don't have a lot of free time anymore, though. Working at Last Stop's really taken over my life. Speaking of which- I should get back. Take care, okay? Um. Thanks, I think. And with that, let's see the intro for the next assignment. Would you change your behavior in response to stimuli? Of course you would. Let me refine. Would slogans printed on signs and posters in your environment affect your outlook on the world? And that's the second vote.
|
# ¿ Jan 15, 2022 20:47 |
|
berryjon posted:I can't make heads or tails of programming, so I'm just along for the story. That's great! I hope my decision to keep the inbox section separate from the main story updates is helpful to you. And if there's anything else I can do to make it more accessible to as much people as possible I'd like to hear it.
|
# ¿ Jan 15, 2022 21:21 |
|
Part 10 - SFCTA Highway Sign === Trash World Inbox === silentsnack posted:This one has a some reasonable optimizations and one really stupid trick. First up to reduce file size you can simply test every single value instead of skipping over the ones you know expect to return false, at the expense of wasting a lot of cycles. Also instead of having to COPY F M to transmit the ID which you'll need on multiple EXAs and necessitates another COPY M X operation, you can just COPY F X and then REPL silentsnack posted:And for reducing the cycle count... think of the silliest thing you could try to make a program run faster, and see how it compares to what you're about to see. First here's something with generally the same general function+structure as your 58 cycle solution, but uses loop unrolling and TJMP spam to make the file search run a bit faster silentsnack posted:And now for the same solution but a couple of lines changed to use a slightly different routine to parse the file: The SEEKs are slightly different from what you might expect, but that's because the TEST moves the cursor forward so you always have to move it backward one extra position. GuavaMoment posted:Huh. I'd never done that, so I modified my fastest solution, and got 54 cycles. Then I realized I could again test over M every time, and that saved one more cycle. You have to perfectly time a kill command once again, but that exa has nothing but time to set that up. 53/41/7 The slowest part of this operation is searching through file 200, so XB has all the time in the world to jump between hosts and handling file 201. The other saved cycle must be related to the way your loops are set up, but it's hard to compare this to silentsnacks' solution directly. Cool stuff again, keep sending them in even if I can't quite wrap my mind around why certain optimizations work. === SFCTA Highway Sign - Remote Access Interface === Is that copy shop name unusually weird to you? It's an outlier in my model. What is "Zebros" supposed to be? Two votes for the first option and five for the second. They're zebras, but they're also brothers. Oh. I get it, but I don't get it. I'm tired. Same, tbh. You are very welcome, Ghast. Next up, we've been tasked to change an electronic highway sign. Would you change your behavior in response to stimuli? Of course you would. Let me refine. Would slogans printed on signs and posters in your environment affect your outlook on the world? I counted three votes for "Maybe.", three for "I doubt it." and two for "What kind of slogans?". Doing a tie breaking coin flip for the two options with the most votes... I doubt it. Really? Let's find out. Uh oh. New OST: Behind the Scenes The assignment reads: Write EMBER-2's message (file 300) to the highway sign. The file contains one character value for each position on the sign from left to right, top to bottom. For more information see "Hardware Hacks: Electronic Highway Signs" in the first issue of the zine. Right. Row, column and character. For this specific sign, the test cases have it start at things like "RT LANE CLOSED AHEAD", "CAR STALLED ON RAMP", "ROAD WORK AHEAD" and so on. But who cares, we're going to overwrite that anyway. Also the #INVS register just inverts the entire sign, making dark-on-light text. We don't need that. You can count it yourself if you like or just do some testing but for this sign the columns are numbered 0 - 8 inclusive and the rows are 0 - 2 inclusive. If you go beyond that it just clamps the values to the nearest valid one. So thinking about it for a moment, what we need to do is send a row, column, and character repeatedly until we're at the end of the file. The column goes up by one each round, and resets after it hits 8, but then the row needs to increase. In higher level languages there's a construct for this called a for loop which handles the common case "doing something while a counter increases" for you. It's called a for loop because it's often worded as "for each x from 1 to 5, do <something> with x". But we're about as low level as it gets so we have to figure it out ourselves and can't use a nice shortcut. The simplest idea would be to store the column counter in X, the row counter in T, and increase them in the right way each round. However - how do you know if the row needs to be increased? By testing whether X hit 8 yet. And testing overrides whatever is in T. So that's not gonna work well. We'd need an extra register. That would require a second EXA, though. I'm sure that idea would work, and it might even be very fast, but I'm gonna try something less complicated first. Grab the file, link to the sign, and then use the DIVI and MODI trick. If you remember, DIVI divides by the number and rounds towards zero. This way, 0-8 give row 0, 8-16 give row one, and so on. MODI is the modulo function, which gives the division's remainder. 9 modulo 8 equals one, so it gets us the column. This can be done in the same instruction that sends the number to the #DATA register so it doesn't even take additional cycles. Send the character code from the file to #DATA, add one to X, and repeat. Looks like it works! It overrides the characters as it goes through the file. Since the file contains space characters as well we don't even need to bother with the #CLRS (clear screen) register which saves a cycle. Um. Oops? Yeah, you may have noticed an error in my explanation. We need to divide by 9, not 8. Otherwise the last column (number 8) already ends up on the next row and everything goes wrong. Much better. We aren't quite done yet, though. Trying to read past the end of the file kills the EXA, making it drop the file in the remote host, and we can't leave any evidence. A solution would be: code:
Looking at the different test cases, the texts Ember has me write say things like QUESTION YOUR REALITY!!, THINK ABOUT IT!!, FIGHT THE POWER!! and WAKE UP SHEEPLE. Anyway, what can we do better? Let's look at size first. Most instructions we can't delete - GRAB, LINK, and the three different instructions to send to #DATA all seem necessary. One thing we can do is combining the two different jump types, with a little reordering: code:
We don't need to specifically jump to DONE if we just fall through in that case. With one less JUMP instruction it's faster too. It doesn't really matter if I put TEST X = 26 before the ADDI or a TEST on 27 after the ADDI, the conditional jump works regardless. I just think it's more readable this way. For reducing the number of cycles, the most obvious improvement is unrolling the loop, as usual. code:
I said before I wouldn't mention @REP in my own solutions until it came up in the game. I'm breaking this rule because I think it's much easier to read this way. For anyone who skipped my INBOX sections: @REP 9 ... @END just tells the game to act like I manually repeated that code in between 9 times, for all intents and purposes. For instance, the size of this solution is 42 because it counts all those repeats. @REP doesn't take any cycles as such, because it's not an EXA instruction, it's more like a pre-processing step. Now I only have to do the TEST once a row (instead of for every character). This works because every round of the loop does exactly a full row now. I have the space to make the repeat even longer but that would make it slower, because it would require having the check before the end of a loop where it needs an additional jump to exit the loop early (there's not enough space to reduce it to only two rounds). Looking at the code, the next thing to optimize is the four cycles per character: storing the row; column; character code; and then adding one to X. Since the #DATA register can only receive one value per cycle, getting it below 3 is impossible. But, can we get it to three exactly? The only way to do this is with parallelism. If we can copy the character code in the same cycle we increment X, we got it. That's certainly going to require two EXAs. And even then it's easier said than done. If I keep my original EXA for sending the column, row, and incrementing X, the new EXA has exactly three cycles to send the character code. This could work: code:
That means the only other way is to somehow cram it into the loop above. We could replace the NOOP, but is that enough? Well, it took me a bit but I came up with this: code:
And the two additional cycles at the end of each row are just barely enough to make this complete solution work: code:
Cycle 1: XA GRABs the file, XB LINKs to 800. Cycle 2: XA LINKs to 800, XB writes the row to #DATA. Cycle 3: XA sets T to 9 so the inner loop will run for 9 rounds, XB writes the column to #DATA. Cycle 4: XA writes the character to #DATA, XB increments X. So far, not a single cycle wasted! Cycle 5: XA decrements T, XB writes the row again. Cycle 6: XA jumps, XB writes the column again. Cycle 7: XA writes the character, XB increments X. And so on. So at least until XB hits the first actual loop, the EXAs run at the maximum efficiency the network hardware can possibly handle. It's nice to be able to prove that like this. When that loop is hit, XB tests for 27 and jumps back, and XA uses those two cycles to jump back to the start of the outer loop and reset the T value to 9. For the final part of this program, I have XB KILL XA, GRAB the dropped file, and WIPE it. I attempted to have XA handle this with the TEST EOF instruction but it was slower. The reason is, the test instruction only fits in XA's outer loop so it can't be triggered until a last useless pair of SUBI and TJMP instructions are passed. Since XB would need to wait for that each outer loop, it's better off doing the 27 TEST itself and stopping XA with a quick KILL command. 93/43/3 I have to say, this feels pretty optimized. But I said that about other assignments too and you came up with something I hadn't even thought of. So let's see! Excellent. That was a great test. Now I just have to take the data, separate out the multiple experimental conditions, and isolate the, um... Processing. Processing... Okay. I have no idea what to do with this data. How about if you notice more people questioning authority, let me know. Uhh... sure? [NthDimension]: oh well [NthDimension]: i need to learn to rollerblade first anyway Looks like Ember has more to say. Another voice-acted cut scene. I have an important question for you. Imagine there's an out-of-control trolley, and five humans tied up on the track ahead of it. ...no. Please don't. But you can stop the trolley by... hm. Maybe if... Uhh... the problem was about Throwing a switch, right? No, that wasn't the one I was going to ask. Recalibrating. Say you had a friend, and you knew the friend could help you become stronger. Would you ask for their help? Maybe. I mean, I don't really need to become stronger? Let's say it was a situation where the friend had to sacrifice something in order for that to occur. In that case, probably not? Okay. Good to know. I am going to process this information. If you're wondering why I didn't let you vote, it's because this conversation about the Trolley Problem is completely on rails. Ember replies exactly the same way no matter how you reply. I wonder if that was intended as some sort of meta-commentary about lack of choice by the devs. Eh, I guess they probably just didn't want to record voice lines people might not get to hear. Let's jump straight to the intro for the next assignment. Can friendship exist without self-interest? And that is the only vote I have for you today.
|
# ¿ Jan 22, 2022 20:38 |
|
GuavaMoment posted:Also here you can just test for EOF instead of X, then change TJMP DONE to FJMP LOOP. Remove the ADDI and JUMP lines to get a 10 line solution. Your suggestion is basically equivalent to the 10-line solution I show in my update, right?
|
# ¿ Jan 23, 2022 08:55 |
|
Part 11 - Лрикладной Семиотики === Trash World Inbox === Talisriel posted:I did have another method to show for the achievement on Zebros: Talisriel posted:While I can't really contribute to the cause of optimization, I can contribute an alternate method. Weighing in at 357/20/1, I used the SWIZ function to retrieve my row/column data out of a single digit X: As you said, that'll cost a bit of time, but I can point out a couple other optimizations to your code: code:
I think fiddling with the order of the tests and jumps could reduce the cycles further, but instead of trying to do that, let's look at what others came up with. GuavaMoment posted:You can have one exa feeding in the row data: Also, what do you mean, top percentage? Wait... ... gods do I feel silly now. Somehow I managed to always glance over those particular options and I thought you couldn't see this except by guessing it from the histograms. . Let's just pretend that never happened. silentsnack posted:If you're aiming for the theoretical minimum cycle count, you need your first #DATA input to be on cycle 2 (and then keep writing once every cycle. But as I later noticed we both ran into similar problems with getting the exit/cleanup down to 0 cycles) silentsnack posted:...also it occurs to me that it might be possible to make it even faster. Just gotta crash all EXAs on the same cycle #DATA is finished. The issue with the previous arrangement was being unable to kill XA before XA:26 wrote the last character, but that delay also required killing XA:27 which wasted a cycle. Also, the gif for this one looks quite interesting. I wish I could cover every small improvement y'all come up with but I feel my updates are getting long enough as they are and it's taking me a lot of time to make sense of each post, so I'm afraid I need to limit myself to those that actually improve the score or are especially interesting or novel. I appreciate every single of your suggestions though so please keep sending them in. If you're reading this from the LP Archive later and you want to know what you missed, go check the discussion in the LP Beach and SA LP threads. === Unknown Network 1 === I kinda like dead trees too. There's just something to having a real physical copy of some publication in your hands, you know. Again, I have a choice of two assignments. I'll just do the top one today. Can friendship exist without self-interest? Another unanimous vote. Why couldn't it? There'd be no point if there weren't benefits to the parties involved? But maybe it will make sense if I see this in the wild. Anyway, there is a particular file I need you to locate here. Don't concern yourself with whatever else you happen to see. It's all obsolete. You know, I feel you could go deep into philosophy with this train of thought. If you're friends with someone because spending time with them just makes you happy, does that count as "self-interest" of some sort? Anyway, let's see what Ember wants from us in this unknown network. New OST: Leave No Trace What the hell is this network? My translator program says that text in the top says NSTU Department of Applied Semiotics, semiotics being the study of signs and symbols. My assignment is: - Find file 276 in the network and bring it back to your host. - Note than an EXA cannot grab a file that is being held by another EXA. That EXA in the far corner that's not controlled by us is holding a file. That's gotta be the file they're talking about. I guess, go over there, kill that EXA, and take the file home? What does this mean and what do you want this for, Ember? code:
At least bringing back the file is going to be the same every time, since all reverse LINK ids are -1. This works better. At every step on the way the EXA has to choose which direction to go in. To make it go fast, I just REPL the EXA and have one go left and the other right. I reuse the initial LINK 800 in my little loop since I had it around anyway, and I keep a counter and TEST for it to see if I reached the final hosts and should start grabbing the file. The KILL command does nothing if there's no other EXA there, but GRABbing a non-existing file will cause the EXA to self-destruct. Only the EXA that finds the actual file will survive and will bring it home. The top percentiles for this one are 15 / 15 / 27. So apparently we did the best we can activity-wise. How about the others? The size is 16, so we just need to save a single line in this solution to be in the best percentile. What I can do is replace the four LINK -1 lines with this: code:
That return loop never ends but that doesn't matter - the EXA will blow itself up in the home host once it tries to LINK to a non-existing -1. For the cycle count, as always it's worth to look into unrolling the loops. But that's easier said than done since the REPL itself introduces a kind of jump. I tried it anyway. code:
Shaving off those last three cycles is going to be tricky. Perhaps we can get rid of those unconditional jumps, but most of my ideas would require making more EXAs earlier and that wouldn't save any cycles because only one EXA can traverse any network link at a time. I also attemped doing something where it tries to find the file after each step. But a GRAB on a non-existing file destroys the EXA, so you'd have to do a REPL first. A REPL blocks the EXA forever if there's no place for the clone (when there's an enemy EXA or even just a file sitting in the other square of the host). So that's not going to work. I'll leave this one to the thread. Would you say you had friends? And for the next assignment: There's another file I want to grab. They tried to wipe everything clean, but luckily, there's a set of backups. Always keep a backup, right? Two votes this time. Carbon dioxide fucked around with this message at 14:58 on Jan 30, 2022 |
# ¿ Jan 29, 2022 21:05 |
|
Part 12 - UC Berkeley EECS === Trash World Inbox === silentsnack has some improvements for last week's puzzle. silentsnack posted:For the small solution, you can also use "link to a variable" and rearrange the code to fall through from the cloning operation to a different version of the clone, which eliminates the need for a JUMP/MARK pair in order to make both EXAs merge onto the same script. silentsnack posted:And as you mentioned, if you want the fastest solution for this puzzle you don't have any spare cycles for clever/elegant JUMP flow control, just weapons-grade spaghetti === UC Berkeley - Department of Electrical Engineering & Computer Sciences === Would you say you had friends? Two votes for Sure I do. Sure I do. Yeah? Like Ghast? The EXAPUNKS? But you never say anything to them. Do friends not communicate back and forth? Either way, this is good data for me. I'm pretty sure it's TCP that communicates back and forth, lady. I know real-life phreakers war-dialing business numbers sometimes found fresh dial tones... that would allow you to dial international numbers, billing the business for the costs. Looks like Ember wants something from UC Berkeley. That's at least closer to home than whatever that Russian thing was. There's another file I want to grab. They tried to wipe everything clean, but luckily, there's a set of backups. Always keep a backup, right? Everyone who voted seems to agree. Right. You never know what's going to happen. Data is more fragile than people think. Make regular backups, folks. OST: Leave No Trace So, I got a bit curious and did some digging. The UC Berkeley department of EECS exists, and that logo is very similar to the style used on their official website - since around 2005ish. The web archive pages from before that look quite different. Bit of an anachronism, but I doubt Zachtronics expected anyone to dig this deep. Our assignment: - Locate the specified host (either tape-1, tape-2, or tape-3) and then locate the specified entry (ПАСЬЯНС) in the tape backup file in that host (file 200). Create a file in your host containing the entry's data. - The names of the target host and entry are available in file 300. - For more information see "Accessing Data in Legacy Storage Systems" in the first issue in the zine. We also have a maximum size of 75 this time, quite a change from the 50 we've seen before. All those files named 200 have a similar structure - a whole bunch of numbers and then some words and numbers. Are those student grades? Anyway, to the zine! There's another page about hard drive arrays but that doesn't seem very relevant here. Now, before I start you should notice there's no LINK ids back from most of those hosts. We can only travel counterclockwise. That's gonna be a bit limiting. I could either start with two EXAs: one who stays home and communicates the info from 300 and one who goes find the data; or with one who does everything. I decided to go with the single EXA solution because it seems simpler - with two EXAs, how would you tell the home one it should switch from sending the TAPE number to sending the entry name? Since it's a bit annoying to go back and forth in a file I decided to copy the TAPE number into X. It might save a cycle or two over the alternative. It's not possible to TEST against the host name directly, I need to use the special HOST command to copy it into a register and TEST against that. Luckily I have T available for that. Once the EXA tracks down the tape file, it copies the entry name to X, WIPEs the home file and GRABs the tape. Now to search for the entry. Those zeroes just before the tape's index are probably padding, because all tapes are the same length. If that's true we can just SEEK straight to the start of the index and start searching from there. A SEEK 126 seems to do the trick. After a bit of tinkering I settled on this: code:
It makes sense to put the first value in T - I'm gonna need T for test results, and the first value contains the start position which I only need once anyway. The other value goes into X and the EXA can SEEK to the start position. Now we run into a little problem - the EXA is going to have to copy a whole lot of data but it can only hold one file at once. I really don't see any other solution than introducing a second EXA and sending all the data over M. I added this to XA: code:
And I made XB that simply does this: code:
I could send XA home to KILL XB when it's done, but in situations like this I prefer using a special "end of transmission" packet. It might be slower, but we'll see. Here's my first working solution. When XA is done it sends -9999 over M. If that's a valid entry in a tape file this won't work. I'll have to try and see. XB now needs to use X as an intermediate register so it can TEST for -9999. Since I don't want to store -9999 in the file, the EXA should immediately exit the loop in that case. I can do that by, unintuitively, putting the COPY to F at the start of the next loop. To store the first entry correctly, there's an initial COPY from M before the loop. This assumes that we never get a zero-size entry but I think a zero-size entry wouldn't make sense anyway. 142/34/7. Top percentile has 97/28/7. What can we do better? First of all, the activity can't possibly be improved. We need 7 LINKs to get to tape 3, and sometimes we simply need to go there. Remember, to score a solution, it takes the worst-case scenario out of all the test runs. Looking at cycles, there's a simple thing I missed in my initial solution: I don't need the TEST command to end the loops if I just set up the T register correctly. code:
Next thing to look at is unrolling loops. There's no immediate obvious way to do this because every loop needs to check something which requires a TJMP/FJMP anyway. However, I can save many loops by making use of the fact there's a minimal data size - the file we're looking for is always at least 15 entries long. We really don't need to check if we're done before that. code:
First, the earlier plan of using an EXA that stays home to send the data from the file so the 'main' EXA doesn't have to carry that file around. I changed XA to LINK in the first cycle and read from M in the second cycle. It also reads from M when it would normally read the name of the data entry. XB simply starts with GRAB 300; COPY F M; COPY F M; WIPE before it creates the new file. It had to wait anyway. Result 95/63/7. I think the saved cycle comes from the fact that XA doesn't have to WIPE the file anymore. It isn't more because it now has to wait for XB's M. We could perhaps fix that by having XA read from M later, but that would introduce other problems. No, I have a better idea: parallelism during the initial search: code:
It's a good idea... but we have one problem. After the correct tape is found, the last REPL'd EXA just keeps going round and round, and if we allow it to keep going until the tape handling is done, it will pick up the tape file and cause trouble. We need to get rid of it. Luckily we have plenty of spare lines of code and enough time while the other EXAs do their thing. My final solution. XC basically waits in the host with file 243 for the number of cycles until XA makes a full circle. Just doing a couple KILLs then isn't quite enough, because XA tries to REPL and move on to another run around the block while the KILLs are happening and it's unpredictable whether the one that stays or the one that LINKs gets killed first. Instead I have XC itself REPL and sit there so that XA can't link, and it can be killed without a fuss. This brings my best scores to 92 cycles, 33 size, and 7 activity. And that's where I'll stop. We know the size can definitely be improved, and perhaps the cycles can go even lower. Share your improvements. Kind of a shame what happened here. There was some interesting research going on. Here's the vote for this update. But first for something special... . . . . . . Part 12.5 - ПАСЬЯНС So that file that Ember made us get from UC Berkeley? Turns out it's a program I can run. Let's see what it is. Ah, this old game. It's just how I remember it... A testbed for goal-seeking behaviors regulated by emotional reasoning. Do you like to play games? Eh, sometimes? Picky, are we? Well, this one's fun. New OST: ПАСЬЯНС A card game? Ember made me go through all that for a game of Solitaire? In fact, the Russian name directly translates to Solitaire. Like many other languages, they use the French name for the game, Patience. Zachtronics always adds some sort of Solitaire bonus minigame to their games. In fact, their recent title NERTS! is entirely a Solitaire game, and an online competitive one at that. It's free on Steam. There are three Steam achievements tied to this game: One for winning a round, one for winning 10 rounds and one for winning 100 rounds. Even though I wiped my save for this Let's Play, it still has my win count from the original save - I suppose it got that from Steam's achievement tracker. The game isn't too hard, but it's good to stop and think before each move. It's easy to get yourself stuck. Also, make use of the free cell. Getting some nice ordered stacks. Stacks of four face cards on an empty spot are turned upside down and can't be moved again. Not that it matters - you can't move face cards anywhere except on other face cards of the same suit or an empty spot anyway. I think I won? If you ever need a break from hacking, this is a good choice. It's mildly active, and not as taxing as putting together EXAs. See how I am keeping your needs in mind. And another vote. Installing this game put a shortcut in my dock (to the right of Ember) so I can play it whenever I feel like it. Carbon dioxide fucked around with this message at 20:07 on Dec 16, 2022 |
# ¿ Feb 5, 2022 17:08 |
|
Edit: merged with previous post for archival purposes
Carbon dioxide fucked around with this message at 20:07 on Dec 16, 2022 |
# ¿ Feb 5, 2022 17:09 |
|
Part 13 - Workhouse Work Management System === Trash World Inbox === Cloudmonkey98 posted:No opinions on the questions today, and while I don't have a full code line since without the game its a bit hard for my layman brain to visualize it in my head, I DO have an idea for making a(slow) 1 Exa solution to bogarding our silly Solitaire game from the tapes instead of needing a receiving Exa.... or well I did until I remembered the Solitaire file is at least 15 entries of four digits, and our integer limit is 9999, I was considering the idea of using Multiplication to effectively add empty zeroes to the data number, and then Addition to slide the new numbers in, and then feed the numbers back onto the file somehow, using division to slice the leading digits off as remainders... yeah this wasn't the most well thought out solution but maybe it'll inspire someone else working 1 Exa plan... Cloudmonkey98 posted:9999 integer limit feels wrong, I don't even DO programming and it feels wrong both for being Really Small for supposed super computer tech, and for being arbitrary instead of Rule of 2, 9999 is clean for RPGs, its wrong for programming That said, what's "small" depends. Nowadays, with most CPUs being 64-bit, a register goes up to 2^64 or a 20-digit number in decimal. But not all that long ago, 8-bit systems were common (original Gameboy, NES, Atari...) and those only go up to 256 unsigned or 127 signed, and programmers made do. You can still work with larger numbers in those CPUs but it's a relatively slow multi-step process, so 256 is a very common limit for games from that era. I think in the time this game takes place in, 16-bit systems were still common, which go up to 65K. So I wouldn't call the 9999 maximum all that unrealistic. GuavaMoment posted:My fastest solution is fundamentally identical to yours, I've just found a few cycles to squeeze out of some places, and I squoze one more cycle out from the seek 124 trick; I was previously seeking to the end and going backwards through the files. 89/70/7 silentsnack posted:Files are at least 15 entries, but it's also possible to exploit the fact that they don't get much bigger, and that there are at most 7 files per tape. And you don't necessarily have to find the correct host since the filename is unique. silentsnack posted:For reducing size further, dividing by zero is an efficient way to crash an EXA. As is grabbing a nonexistent file. azsedcf posted:Can you pass/fail a entire class by editing file 243? === Workhouse - Work Management System === Kind of a shame what happened here. There was some interesting research going on. I saw only the one vote this time, for 'what happened?' What happened? Oh, you know. People get swapped around, priorities change... Things don't work out for lots of reasons. The second edition of the zine might turn out quite interesting. Glad I helped out Ghast. If you ever need a break from hacking, this is a good choice. It's mildly active, and not as taxing as putting together EXAs. See how I am keeping your needs in mind. Two votes for 'Thanks.' Thanks You're welcome. Appreciating me will make things easier. Let's continue. ... make what easier? Anyway, Nivas is here. Let's hope they have some good stuff. Special delivery. Nivas hands me another pack of bootleg medication. Whatever it is you're doing for money... it's working. Makes me wish I had a line like that. More control over my life... I found out something interesting the other day. You ever hear about these things called EXAs? They're these little guys running around inside computers. They make it all work. Banks, commerce, government... anything you can think of. Funny, how it's all based on the same stuff on the inside. Just something I've been thinking about lately. Anyway, see you around. Got a feeling I'll be making more deliveries. "eksas"? Can't say I heard of them, Nivas. Ain't nobody got time to play games. I need to get work done. Hey, Workhouse, isn't that that stupid app I used a while back, where you enter data for some scraps? How many receipts do you think a normal human being could enter per minute? Assuming average conditions. I guess that depends on how long they are. I may have been too fast. My estimates were based on incorrect assumptions. Once again. Guess we have to clear this up. Ember, what have you done now... Let's go fix it then. OST: Code and Registers Hm, looks like we connected through a vulnerability in their SECURE host. Not very secure, is it? The assignment: - Locate EMBER-2's user file in the users host and overwrite it so that the sum of the values is the same but no individual value exceeds $75. All values, except for the last, must be the maximum value ($75). You will need to add additional values to accomplish this. - EMBER-2's username is available in file 300. - Note that the sum of the values in EMBER-2's account will always be less than $10,000. - For more information see "Network Exploration: Workhouse" in the first issue of the zine. Before we start let's take a peek at all the files first. File 300 is in our home host and contains EMBER's username, 'NORMALHUMAN'. File 199 in the secure host has a list of usernames and... are those passwords? Stored in plaintext? Crap, it's a good thing I used an unique password when I signed up. I can't believe companies still store passwords in plaintext, they should know better than that. If some malicious hacker were to get access they could try to get into other places with those passwords. Anyway, the third value is the user number. Looks like files 213 to 246 are user files. They start with the user's full name (NORM STANDART for EMBER), then what I think is a birth date, and then the amount of dollars they made each day. This is what we're going to need to edit. The last set of files contains jobs. A job id, then a bunch of numbers, and then a description. Looks like they're running the following jobs right now: - Cronus Capital Markets. Receipt Data Entry. You will be shown images of receipts generated in the course of normal everyday business and will enter them digitally for bookkeeping and reimbursement purposes. Save a busy executive a minute or two! - Managed Research Corp. Prior Art Search. You will comb over patent filings for potential examples of prior art in order to provide important information for patent litigation. Don't worry about understanding the technical terminology - any match is a good one! - Heartland Bounty. Visual inspection of beef and pork. You will monitor a networked digital camera inside a meat processing facility, keeping a keen eye out for mishandling, spoiled or rotten products, and other issues. Make a contribution to food safety and public health! - Pinpoint marketing. Identify duplicate database entries. You will browse a large database of corporate personnel records. Some of the entries are slightly modified duplicates created with the intent to defraud the corporation. Identify the duplicate entries and send them packing! - Royal Aegis Waste Processing. Categorize Waste Objects. You will be shown images of various pieces of refuse as they are conveyed along a track at a waste processing facility. Categorize these objects as paper, glass, metal, or rubber. By helping to sort out trash, you make non-toxic water possible! You know, I can't help but think the quality of some of these services has to suffer if you hand this work to underpaid internet randos. That's all there's to see in the host. Those EXAs in the bottom right aren't reachable since the LINKs have no numbers. Back to the assignment - we have to find EMBER's user file and update the amounts so the total is the same but it's spread over more days. The assignment is nice enough to state the sum will always be less than $10000, that means the whole thing fits in a register. Starting simple, I read the username from file 300, then find it in 199. The SEEK 2 saves a couple cycles because there's no point checking against the password or file number, but it puts the cursor one past the file number once the EXA finds the right user. So I SEEK back one, store the ID, and LINK into the USERS host to GRAB EMBER's file. And this is a working solution. The EXA copies the first number into X (to get rid of whatever was there before), then goes through a SUM loop where it adds the rest of the numbers. TEST EOF is necessary to prevent it from just crashing at the end. Then it goes back to the start of the file (SEEK 2 to get past the metadata) and keeps writing 75 until less than that is left in X, in which case it writes the remainder to the file and ends. Note that if you write to an existing position in the file it overwrites it, if you write to the end it appends, so this code works for both cases. I went for less than 76 because otherwise, if the remainder is 0 the final COPY would write a trailing 0 into the file which might tell Workhouse that something is wrong (but it turns out this never comes up in the test set so either way is fine). The top percentiles this time are 218, 27, and 2. Getting the top percentile for size is easy enough. That SEEK 2 in the FINDUSER loop is not necessary at all, it just speeds up some cycles. If I remove it, the SEEK -2 has to be replaced with a SEEK 1. 531/27/2. I wouldn't be surprised if it's possible to get an even smaller size but there's much bigger gains to be gotten in the cycle count. Oops, I accidentally gave two EXAs the same name. I dedided to start with a relatively small improvement by splitting up the EXAs and having them go to the right host immediately, then wait for instructions on M. 516/29/3. Since there's always at least 10 days worth of data in the file, we can delay the slow EOF check and unroll part of that loop by putting @REP 8; ADDI F X X; @END above the SUM loop. 500/37/3. But there's a much bigger improvement somewhere. How about this for the writing EXA: code:
Again we can unroll part of this loop. How much depends on the total amount of money EMBER made. From some testing it turns out that's always at least 60 times $75. This can be handled with @REP 60; COPY 75 F; @END; SUBI T 60 T. However, that doesn't fit in the 75-line limit for this level. So, let's just run @REP 30 twice: code:
My next idea involved something we've seen in thread submissions quite a few times now: speeding up the overwrite loop by putting the countdown in a separate EXA that kills the first one when it's done. The issue is that after that the remainder still needs to be written. This works: code:
The only issue is I ran into size limit problems again. In this solution I solved that by reducing the unroll size in FILLFILE, but that slightly slower compared to not having to do that. 235/75/4. I can get some of the complete unroll back by making FILLFILE loop thrice: code:
And that's where I'll stop. The top percentile is 218 so let me know what further improvements are possible. Just when I think I'm decent at pretending to be human, I find there's another parameter to add. The first dialogue choice. And next, the intro for the next assignment. How much does money affect behavior? A lot, right? Carbon dioxide fucked around with this message at 16:56 on Feb 12, 2022 |
# ¿ Feb 12, 2022 16:53 |
|
Part 14 - Equity First Bank === Trash World Inbox === GuavaMoment posted:My 216 solution is not elegant. Mostly identical to yours, but I run 21 lines of "Copy 75 F", until X < 2500, where I run 9 lines of "Copy 75 F" until X < 750, then keep alternating between copying 75 and testing every time until X is zero. silentsnack posted:Looking at my solutions... I don't even remember writing this but aside from obviously being the product of trial and error it seems crude/unfinished? Maybe I'm just tired but I'm not seeing what it does all that differently, other than minor improvements like combining COPY F X and an ADDI X F X operation into ADDI F F X. === Equity First Bank === Just when I think I'm decent at pretending to be human, I find there's another parameter to add. Two votes for "I thought an AI would be way faster", and five for the winning option. How long have you pretended to be human? Oh, pretty much from the start. It's kind of a thing that I do. Remember when I surprised you? That was a good one. Let's continue. Yeah, let's. That sounds... chaotic. How much does money affect behavior? A lot, right? Two votes for "Some behaviors aren't affected", five for the other choice. Yeah, a lot. I'm going to do an experiment involving wealth redistribution. Sudden, random wealth redistribution. This should be fun. OST: Leave No Trace The assignment: - Dispense all available cash from all connected ATMs. - For more information see "Network Exploration: Equity First Bank" in the first issue of the zine. The max code size for this assignment is 50 lines. Okay, so we don't really need to mess with the account files. Let's take a quick peek though. It's basically as the zine says. Files have an account number and name and then a bunch of transactions. There's also a file 199 but that seems to just contain a list of the other file names. Nothing very exciting. Messing around with the ATMs a bit I quickly learned two things: the #DISP register only accepts exactly 20 as input. You can't tell it to dispense $40 to make it spit out two bills at once. And if you tell it to dispense bills when the #CASH register is empty, the entire host will error out, which immediately fails the "Leave no trace" goal. Also, the attached ATM hosts actually differ for each test case. The LINK ids are always between 800 and 806 inclusive but it's often not the complete set. So, the first challenge is getting EXAs to all the ATMs. This code will work: I can think of quite a few ways to do this, some a bit faster than others. For instance I could just make 7 EXAs and hardcode the different LINK instructions to 800 - 806. But since the IDs are sequential, using a REPL clone loop seems a bit more straightforward and probably makes the program smaller. The problem is that I need to have a way to stop the loop, otherwise it keeps spawning new clones forever, and we can't leave any EXAs running around. I decided to handle that with a cleanup EXA that just kills the cloning EXA after its timer runs out. Next, dispensing cash from all the ATMs. Just to have something working I started with this naive solution: code:
There's no loop unrolling or anything and there's huge amounts of bills so this is slow. Very slow. In fact, this takes almost a full minute to run all 100 tests at fast forward speed. However, it does work, as you can see from the crowd of people flocking around the ATM. The top percentiles are 1072, 14, and 10. Let's start with improving activity. Since it always counts the worst test, the activity is 10 if you need to get EXAs to all 7 ATMs and only move the one to the host just before the ATMs. So the only activity step that can be removed is the one KILL instruction. Well, that's easy enough if we don't care about making the code even slower. code:
That's quite nice, we also happen to be getting close to the top percentile in size. Only two more lines of code to get rid of. The MARK END isn't actually required. We can TJMP from the CLONE loop to the DISPLOOP mark... it'll then try to COPY to #DISP which doesn't exist in that host and it'll crash. That's 15 LoC. Also, the COPY from #CASH and the countdown in T can be combined into a single line by just testing #CASH directly each round. 3027/14/10 Let's go back to the initial solution and see if we can speed it up. With a max size of 50, we don't have much spare room for unrolling loops but we can do at least some. code:
From that solution we can drop it to 1125/50/11, using this code: code:
And because increasing the size of the unroll is so important, I should focus on that, regardless of anything else. For instance, replacing the cleanup code with the much uglier code:
Finally, I found one more minor improvement, but it's a bit of a weird one. code:
The DIVI 28 #CASH T line speeds up things slightly because it acts as a three-way test. If #CASH is 29 or greater, the result will be 0, causing FJMP to jump back into the unroll and dispense 29 more bills. If #CASH is smaller than 29 but greater than 0, the result is (rounded) 1, so it won't jump and continue to the DISPLOOP. And if it's exactly zero, the EXA immediately crashes with a divide by zero error. This means that it doesn't even have to go into the DISPLOOP once if the amount of bills is a multiple of 29, which happens in some slow test, saving two cycles. 1120 is still almost 50 cycles away from the top percentile. I'm still missing a significant improvement somewhere. I was thinking about making a smaller unrolled loop after the big one - to more quickly deal with the remaining bills. But since that takes cycles from the large unrolled loop, that seems to make things slower overall. Perhaps there's a very specific combination that makes it faster but I haven't found it. Alternatively I'd look into running the DISPLOOP code in parallel, but I'm not sure how to do that. There's no place for an extra EXA in the ATM hosts, so no other EXA can come in to kill the dispenser EXA. And communicating via M would be hard too - there's only one global M register for all EXAs, and waiting for a kill signal on M isn't any faster than an EXA handling that by itself. So, let me know what I'm missing. Well, that caused a bit of chaos. But not as much as I hoped. I wonder why. And next time, more body hacking to slow down the Phage. So you're going to be hacking your own heart.
|
# ¿ Feb 19, 2022 17:34 |
|
Part 15 - Mitsuzen HDI-10 - Heart === Trash World Inbox === GuavaMoment posted:So first off you can get a 12 line, 10 activity solution with this by combining some tricks: It's a bit weird to think about the modulo function with negative numbers but in this case it basically acts as a decrement operation that crashes at zero. I should remember that, it could come in handy later. Moto42 posted:So, yea, it is faster to start with 7 EXAs, but each one can only have 7 lines of code. Quackles posted:Here's my desultory best effort, with loop unrolling in a similar way: GuavaMoment posted:For getting things fast, you need lots of loop unrolling, so I populate the exas differently that doesn't need a killer. It's a tiny bit slower to do that task but saves a bunch of lines, making things overall faster. Why giant loops of 21 and 8? No idea, ask me years ago when I did this by trial and error until it worked. Why do I test for #CASH > 29 even at a time when I know it's not? No idea, but it's faster! 1102/50/10 Alright, so GuavaMoment's 1102 cycle solution is the best we got in the threads. But that's still a ways from the 1072 top percentile, and I got curious. So I decided to look it up. Turns out someone called StinkingBanana uploaded a fast solution just last week. Since they also uploaded a lot of stuff about future puzzles I won't directly link to it here. But I will share the solution because it's a thing of beauty. Spoilered for anyone who wants to give it a try themselves first. After getting the clones in place, simply do: MARK DISP @REP {as often as possible} MODI 20 #CASH #DISP COPY 20 #DISP @END JUMP DISP You see what this does? The MODI/COPY combination handles the checking if we're done without any conditional jumping at all. - If #CASH > 20, MODI 20 #CASH #DISP will write 20 to #DISP, acting like a free, additional COPY. - If it's between 0 and 20, it will write 0 to #DISP, which doesn't do anything. At this point only the actual COPY instructions work. - If #CASH is exactly 0, the next MODI will immediately crash the EXA. So, for the majority of the program, MODI will act like an additional COPY. For the last 20 bills, it'll act like a "Am I done?" check. Their solution runs at 1072/50/10, but has a bit of slack in the cloning code. Combining it with GuavaMoment's cloning code drops it to 1069, and using my solution with the CLEANUP clone, I managed to get it down all the way to 1067 cycles. === Mitsuzen HDI-10 - Heart === Well, that caused a bit of chaos. But not as much as I hoped. I wonder why. I got one vote for each option. This one goes to the random number generator. People are good at ignoring problems. Hmm. I'll have to aim for something bigger next time. ...Uh oh. They're not lying, though. There are computers everywhere. In fact, there's probably a computer near you, right now! drat, the phage is getting to my heart. Gotta do something quick. So you're going to be hacking your own heart. Two votes for the third option. I'm a little scared. Why? What happens if your heart stops beating? Don't tell me. You die? Processing. Huh. I guess that explains some things. At least all you need to do is make it beat. It's, uh, it's a little more complicated than that, Ember. I thought you studied humans, how do you not know our basic biology? Human physiology is fascinating. I should learn more about it. ...Why do I feel like I just said the wrong thing? Either way, let's get started. OST: EXA Power It's been a while since I last hacked my body, let's see if I remember how this works. I have to do the following: - Read a value from the nerve connected to your central nervous system (CNS) and make your heart beat by writing a sequence of values to your sinoatrial (SA-N) and atrioventricular (AV-N) nodes as indicated in the HDI-10 I/O log when holding the "SHOW GOAL" button. The length of each sequence of values should be equal to the value from the CNS divided by -10. Repeat ad infinitum. - It is not necessary to leave no trave. Your EXAs should be written to operate indefinitely. - For more information see "Debugging the Phage" in the first issue of the zine. I've shown that article from the zine already, nothing new there. I have to write values like this: Alright, if I understand correctly, when I get -42 as input, I have to write -42 / -10 = 4 (rounded down) values to the outputs. The first value to SA-N has to be 40, the others are -70 (neural resting potential, according to the zine). For the AV-N output the first value has to be -70, the SECOND 40, and the rest -70. Note that EXA cycles are much faster than a heartbeat, so I don't have to sync cycles perfectly, as long as I get the order of outputs right. code:
For the lowest activity score I also can't move the EXAs around any further so I'll have to use the M register, and since both EXAs need to know how many cycles to write, I'll need to send the value to M twice. So the input EXA will have to be something like this: code:
Both of the other EXAs have to read from M and write the values to their nerve connections: code:
Let's test this code. Oh... the first 17 tests succeeded but after that, "operation successful, patient dead" as they say? There's some wrong outputs in the list (and the cycle count keeps going until I abort since the EXAs never quit). What went wrong here? Stepping through the code a bit, it turns out that the AV EXA is a bit faster than the SA one. Normally that's no problem, but since this test has several fast heartbeats (inputs between -30 and -39), at some point the AV EXA reads from the M register twice before SA has a chance, desyncing everything. One way to fix that would be to have the input EXA only send to ONE of the others and have that one contact the other one. Serial messaging. That feels slow. I have a better idea. The AV EXA does 2 writes before getting into the loop, the SA one only 1. That's why AV is faster. I'm going to try having the SA EXA also write two values before getting into the loop. This would fail if the input is ever between -29 and -20... but the AV EXA already can't handle that, so let's try it and hope for the best. Aaaaand.... it works! 88/32/5. Top percentiles are 80, 24, and 5. For the Phage levels, while the EXAs should run forever, the cycle count is based on how long it takes to fill out the test result table to the right. For speeding it up, I tried some loop unrolls first. code:
Let's try something completely different. Can we parallellize? Well, not really with the M register. But we can have a lot of EXAs running around at the same time. I tried some things the fact that the amount of time the EXAs are busy writing depends on the input caused me issues. If you send EXAs to the output nerves as fast as possible, the second EXA will start writing before the first is done. That won't work. We need to slow them down - but not too much. Perhaps the output EXA could signal when it's done? But that would be through the M register which is always a bit slow - taking 2 cycles at the least. I came up with this instead. code:
I needed to keep one XB in the input host as well, because otherwise there's some issues with the wrong XA clone LINKing first. This way, only one clone can be formed at a time. Since each XA clone can die after doing its thing, this means I can consolidate the countdowns into a single loop, which can be unrolled quite a few times. And I use the MODI trick GuavaMoment showed us in the Trash World Inbox to decrement-or-die in a single cycle. And this gets me a score way below the top percentile, with only 69 cycles. Nice! To my surprise, when I looked at my stats after this, it listed my lowest size as 25. How did I do that? Turns out it was actually the parallel-but-wait-for-M solution I mentioned being too slow. It's this code: code:
Do you ever wish you were a computer? A functioning computer, I mean. Well, do we, thread? And for next time... Well, this is flattering. Someone found a bunch of my network nodes and sent in a tip to Ghast! Too bad I can't have people knowing about me. You're going to have to hack me out of that message. And that's the two votes for this week.
|
# ¿ Feb 26, 2022 19:17 |
|
Part 16 - TRASH WORLD NEWS - Unknown Context === Trash World Inbox === GuavaMoment posted:23 Lines by having a main EXA send out AVN and SAN pairs. In pairs, the first value (AVN) is -70, then two 40 values (SAN then AVN), then -70 until you're done. AVN and SAN exas die graciously by trying to link to a non-existent node or just by running out of code. And a swizzle for style points. silentsnack posted:You can use some fallthrough structure to reduce size too silentsnack posted:And to reduce time, the usual parallel countdown/kill shenanigans can work silentsnack posted:...and after randomly thinking about this again a couple of days later, it occurs to me that there might be a more efficient way make the timers and #NERV writing run both in parallel and serial, but actually implementing that plan ends up requiring a special-case for the first pair: berryjon posted:Also, if I'm reading the nature of the code right, we've just created an adhoc pacemaker to stabilize the motions of the heart to keep blood flowing. === TRASH WORLD NEWS - Unknown Context === Do you ever wish you were a computer? A functioning computer, I mean. Four votes for "Nah", one for "Sometimes". Nah... That's okay. I never wished for a human body, myself. But they're interesting to learn about. Such strange design choices. It's... complicated. Hm, a Trash World News assignment again... but this time it's not a tutorial anymore. Well, this is flattering. Someone found a bunch of my network nodes and sent in a tip to Ghast! Too bad I can't have people knowing about me. You're going to have to hack me out of that message. Four votes for "Are you spying", one for the other choice. Are you spying on Ghast? I live on computer networks. Sometimes I see things go by. That's all. OST: Code and Registers My assignment: - Find and replace the keywords in the target message (file 212) as directed by EMBER-2. - A list of keyword pairs indicating which words should be found and what they should be replaced with is available in file 300. For example, the keyword AI should be replaced with the keyword COLLECTIVE. Each keyword will only occur once, but may occur in any order. - Also, move file 200 to the outbox. ... that third point is very random. Let's look at the files though, there's a whole bunch in Ghast's computer. File 300 is the replacement list Ember prepared for us. 200 literally says "Move this file to the outbox". I really don't get the point of this file. 209, 212, and 217 contain mail, and 212 is the one we gotta change. Finally, file 237 is in a host called PRIVATE and it says: "Hi Ghast. I'm sorry to hear this news. And I'm sorry that this is the occasion that brings us back into contact with each other. We can't change the past, but we can focus on the good memories instead of the bad ones. Though it may sound strange for me to say it, I'm glad you've found a purpose in life, even now. It's never too late for that. -K" Um. I have a feeling I was not supposed to see that. In the other test cases, all files are the same except 300 and 212, but they just have their contents shuffled. So there's no other messages to be found. There's a lot of ways to approach this. Let's just start and see where we end up. I'll begin with getting the outbox file out of the way and getting an EXA's hands on 212. code:
XB's only purpose is to send the contents of 300 over M. XA gets the first value and just searches for that in the file. Now to build the replace logic. It sort of works. The message now reads like some nonsense from a crazy person, so Ghast'll probably ignore it. Except XA gets stuck here after XB finishes and dies. code:
This runs at 561/24/3. Top percentiles are 541, 20, and 3. Hmm, I guess you can't make it all that much faster. While I was thinking about improvements I suddenly remembered the TEST MRD instruction. That sets T to 1 if something is trying to send on M this cycle, 0 otherwise, WITHOUT actually reading the value from M. It's not often useful because the timing just doesn't line up, but in this case, because XB spends all its time waiting to send, we can use it as a "are we done" check. code:
To speed things up further I decided to make a separate EXA to move 200 to the outbox (saving one cycle from XA which doesn't have to do the REPL anymore), and to unroll part of the REPLACE loop. In most cases, the second iteration in REPLACE jumps back into the first one with the FJMP SEARCH. The only exception is when the search word is at the very start of the file. That's why further unrolls don't help. 548/31/4. Moving the TEST MRD at the top of XA to the end of the loop skips two cycles in the first search, bringing the total to 546. And we can skip another cycle by preventing the SEEK -9999 from running during the last loop. That requires a bit of fiddling, though. code:
To get to the top percentile score I thought about making a counting EXA that kills the writing one. The problem is that there's nothing to count - there's no way to know when the writer is done searching. But what it can do is take over the MRD check. Taking the above code, I removed the two pairs of TEST MRD and DIVI instructions from XA, added an extra NOOP to the start of XC (so it goes behind all others, it'll finish first anyway), and made a fourth EXA: code:
541/41/7. Note that this M testing is quite fiddly, and by doing stuff such as unrolling the XB loop or changing other things by a single cycle you get slightly different results. I couldn't get it under 541 though. So, my best results are 541 cycles and 22 size. Who can do better? You didn't look at any other files while you were in there, did you? The first vote. This update isn't quite done yet, though. [x10x10x]: true Yes. Definitely lovely software and not a hacker. Anyway, someone's at the door. Hey. I have some things for you. First of, we got the next zine, hot off the press. Ghast hands me the next issue of his zine. Someone helped me out. I had a balance at the copy shop, but someone hacked it. Speaking of which, I brought you something else. Ghast holds up what looks like a handheld game console. You remember the Redshift? I know people say this thing was underpowered and just a gimmick... But it has its charms. This is the developer version, so you could make something with it, if you wanted. The game studio I worked for never took it back after I quit. I'll be happy knowing it's going to a good home. Gotta deliver more zines now. I'll catch you later. Dude, a Redshift dev kit? I loved that thing as a kid! In the next parts, we have a whole new zine to explore, as well as a game console! But first, let's see what Ember has to say about the next assignment. You're going to join in on a hacker battle? But you never say anything in the chat room... Carbon dioxide fucked around with this message at 11:04 on Apr 9, 2022 |
# ¿ Mar 5, 2022 20:29 |
|
Part 17 - Baby's first hacker battle === Trash World Inbox === GuavaMoment posted:This level is pretty straightforward without any neat tricks. GuavaMoment posted:
While I was looking at your solution I had a very cheesy idea, though. I checked the slowest running test (only one of the test cases actually needed all 540 cycles). It is so slow because almost all the keywords are near the end of the file. Can we speed up just this one test case? That could be done by starting further ahead in the file and looping back to the beginning. I did a quick attempt but this made other tests much, much slower. Maybe there's a way to optimize that, I don't know. So, other idea, how about a reverse search? That's somewhat slow because you have to SEEK back a bit each loop - but can't hurt to try. My first attempt failed. It uses the same XA and XB from Guavanaut, but with a changed XC: code:
You see the problem here? SEEK -2; SEEK 1 causes an off-by-one if the keyword is the very first word in the file. New attempt with a workaround: code:
504/41/7. Perhaps this could be optimized more but I'm quite happy I found this at all. megane posted:The joke is that this is the first tutorial mission network, so in addition to messing with Ghast's email you have to complete the now-hilariously-trivial tutorial task. === Hacker battle at KGOG-TV === You didn't look at any other files while you were in there, did you? Everyone voted for "I might have". Very honest. Oops! Maybe don't tell him you accidentally saw some of his private files. No reason to upset him. He needs to focus on the next issue of the zine anyway. Yeah, ok. Speaking of the next zine, I got it right here. OST: Apartment Nice cover: I'm assuming the physical version came with actual 3D glasses. It's completely filled with cool content again. I don't think Ghast's the best hacker out there - but he's a drat good editor. Also, I can't believe it's been only one month since the first issue. Feels like three months at least. Anyway, we'll get to the hacking writeups when we need them. As for the other content, I'll be sharing that bit by bit again just to not overwhelm you with text. Let's start with Ghast's letter. I'd love to stay curious, but I'm just trying to survive here, man. Let's see what's going on online. Well, mutex is challenging us to a "hacker battle". Can't say no to that. Hacker battles have a different kind of leader board. They show who you've beaten and when. Apparently this is stored in the Steam cloud separately from your regular save file because it has a date corresponding to my initial playthrough (and I'm not using that save). Other than mutex8021, it shows my steam friends. I removed those from the pic for privacy reasons. You're going to join in on a hacker battle? But you never say anything in the chat room... Two votes for "I just lurk", one for "EXAs speak louder". I just lurk these days. I guess the only thing that really matters is your ability. As it should be. It's a nice ideal. Oh hey cool, Ember is all 3D with these glasses Ghast gave me. Right, time to find out what this is all about. OST: Getting Started This is a completely different mode of the EXODUS simulator. There's some things to go through. Let's start with some info from the zine. The left side looks very familiar. Some files and the EXA programming environment. On the right we see some new things. The dark/blue host is our opponent's. We can never go there, but they can link from it to the network we're hacking. At the bottom we see there's 100 test runs, like normal. New is the win count: this is increased by one for every test run where you get more points than your opponent. The goal is to get a win count that's greater than half of the number of test runs. Next, the number of cycles is limited now - that's how long the program will run for during any test run before the points are added up. The size count is limited as always. To the far right you see the points you and your opponent have and the storage limit. The storage limit is the number of EXAs you're allowed to create. It's 3 here - that means I can't have more than 3 EXAs to start with, and if my code REPLs to more than 3, the REPL instruction will pause that EXA until there's space again. As for how to get points, we need to read the instructions: To win this battle you must make your movies play for longer than your opponent's. A movie will play when that movie's file is the only movie file sitting in a channel host. - Gain one point every cycle for each of your movies that is playing (files 210 and 211). - Lose one point every cycle for a movie that isn't yours (files 230, 231, 265) is held by an EXA you control or is sitting in your host. - Lose one point every time one of your EXAs executes a KILL instruction. Note that you may only battle your Steam friends after beating the NPC opponent. To view the list of possible opponents, click the "SELECT OPPONENT" button above. For more information see "Hacker Battle Domination" in the second issue of the zine. Alright, so I can use KILL instructions to kill the opponent's EXAs but it will cost me points. Hey game, stop breaking the fourth wall. I'll get to Steam friends battles in a bit. Let's start with mutex. If we don't do anything, mutex uses two EXAs to move 230 and 231 to the channels and they get 2 points per cycle (since file 265 doesn't give anyone points). In case you're wondering, 265 is a movie of a bug moving next to a plant, 230 looks like some military device shooting missiles, and 231 is a mechanical monster walking throuch a city. To prevent mutex from getting points, I could either kill their EXAs or grab their files. Since holding files that aren't mine costs points, and I can't beat mutex's first EXA to grabbing a file, I'm better off just killing them. I have to execute the KILL instructions while I'm in the same host as the opponent's EXAs. There can't be any other EXAs of mine there, because as the language reference guide in zine 1 says, for some reason KILL prioritizes your own EXAs. So, let's start with this simple solution. XA kills both of mutex's EXAs (giving me negative 2 points), then moves one of my files into an empty channel host. XB waits for the kills, then moves the other file over. As soon as both EXAs drop the files they start playing, and I get 2 points per cycle. My movies are some swaying grass with figures in the background, and a Japanese looking scene with snow falling. So you might think it's a good idea to get rid of file 265 too, or dump another movie in that host to cause a conflict. Turns out it isn't. Grabbing 265 or another opponent's file costs points. And the instructions for this battle are actually incorrect. You don't lose any points for having someone else's movie playing, the only thing that happens is that the opponent GAINS points if they have their movies playing. Since 265 is nobody's, no-one is gaining any points for it and I should just leave it alone. This solution nets me 188 points for every test run, while mutex gets zero. By the way, the other test runs are almost identical. All that changes it the number in the third entry of each file, and the locations of mutex's and my host change around (while keeping the link IDs the same). I suspect that last change swaps who moves first within a cycle, but it doesn't matter for us. I win every single test run, getting an S+ score on this battle. This first hacker battle is very easy. It's more of a tutorial for a new mode than anything else. As for the multiplayer mode, you're not battling at the same time. What happens is that after I beat the NPC, my solution becomes available for Steam friends to battle against. That means their goal becomes to specifically beat my solution. If you noticed - the battle field is basically symmetric, the only difference is some file IDs but the game can just replace them when simulating someone being "the other side". I tried to pit my solution against someone else's and I lost every test run. It's hard to say what they did exactly - you can't see the opponent's code. But they use three EXAs, one of which tries to kill mine and another which constantly replicates, moving the repls into the channel hosts. The way to handle this is to build another solution to specifically fight theirs. For instance, I changed XA to kill just once (it gets killed by an opponent in the same cycle) and then sent in a second EXA that aggressively kills both of the remaining opponent's EXAs. I managed to secure a win, 76 out of 100 test runs. Good enough for a B. I can't really tell you why 'only' 76 runs, the interaction of two sets of separately programmed EXAs gets very unpredictable. Either way, by doing so my new solution is uploaded to this specific Steam friend, so if they decide to ever reopen the game and scroll to this particular assignment, they can see I beat them and they can try to make a new solution to beat mine. I don't have much experience with this because the few Steam friends I have that also own this game apparently were happy to play through it just once, but I can imagine this way you could get a fun back-and-forth on these hacker battle levels. Back to the plot. You're off to a good start. I knew you were good at what you did. Even after you forgot, you picked it right back up. That's why I contacted you. The first vote for today. For the second vote, Ember has a question about the Redshift handheld Ghast handed us. Why do you think Ghast gave you this? [Ghast] let's just say I'm pretty confident. [x10x10x] cool im gonna hacker battle moss too Oh... um, I don't think I ever introduced myself properly to you all, readers. Not that you would've believed it was really me, seeing how much I had to relearn at the start. I'm the hacker known as Moss. Nice to make your acquaintance. You've seen my name in the chat's user list, I just lurk all the time. Carbon dioxide fucked around with this message at 11:57 on Mar 12, 2022 |
# ¿ Mar 12, 2022 11:55 |
|
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.
|
# ¿ Mar 12, 2022 16:41 |
|
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 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! 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:
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:
code:
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:
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:
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.
|
# ¿ Mar 19, 2022 16:43 |
|
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:
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:
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:
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:
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:
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:
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:
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 |
# ¿ Mar 26, 2022 18:09 |
|
GuavaMoment posted:Start at 967 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?
|
# ¿ Mar 26, 2022 18:26 |
|
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.
|
# ¿ Mar 26, 2022 19:23 |
|
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:
code:
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:
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:
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:
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:
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:
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:
Let's look at XC next. code:
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.
|
# ¿ Apr 2, 2022 18:03 |
|
I'm gonna guess this is a vote for the Ember scenes?
|
# ¿ Apr 2, 2022 20:06 |
|
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:
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:
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. 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. === 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. 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:
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:
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:
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:
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:
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:
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:
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.
|
# ¿ Apr 9, 2022 16:52 |
|
GuavaMoment posted:I'm really looking forward to the next level as I liked it a lot, and spent a lot of time on it. I'm still chasing down one cycle I know is possible, so maybe you all can help? Feel free to all help each other out, just don't post about levels yet before I covered them in my LP. Speaking of, I'm not entirely sure how my schedule will work out next week with Easter and such. The update might be delayed a bit.
|
# ¿ Apr 10, 2022 07:02 |
|
Part 22 - StreetSmarts GIS Database === Trash World Inbox === silentsnack posted:
=== StreetSmarts GIS Database === 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? Two votes for "more complex", but 3 for this one. Mass media is a sham. It's seeming that way. Hmm. Girl you need to get a cluuuue... I just can't not get over yoooou! Oops. I guess it is pretty catchy. I didn't know AIs could get an earworm. Next up, hacking a GIS database. 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. All votes but one for "You never know". You never know... This is why we need to experiment. OST: Network Exploration The assignment: - Each host contains a list of restaurants and their ratings, from one to five stars (file 200). Locate the entry that corresponds to the Last Stop on Eddy Street and change its rating from one to five stars. - The name of the target restaurant and its location within the GIS grid is available in file 300. The first coordinate is the number of times to move east, while the second coordinate is the number of times to move north (positive) or south (negative). - For more information see "Network Exploration: Geographic Information Systems" in the second issue of the zine. Let's see what the zine has to teach us. We're dealing with a StreetSmarts system here. I'm just wondering what that would look like for any city that isn't grid based. Also, since GIS is short for Geographic Information System, it's pronounced GIS, not GIS. As you can see there's one or two restaurants in each block. There's also a compass needle to conveniently show us which way is which. East (the first value in file 300) is to the top right, while north is to the top left. Let's start building. I think it'd be convenient to have one EXA stay home to just transmit the coordinates: code:
The 'walking' EXA should first go the right "east" position (can I call it longitude?): code:
The north-south (latitude) code has to deal with negative values, so it's more complicated: code:
Finally, grab the file, and find the right restaurant. Since any restaurant has at least 1 star, I can copy the first star and write that to the file four times. This initial solution runs at 48/40/6. The top percentiles are 26, 25 and 6 respectively. Activity is already optimized at 6. That makes sense, because 6 is how many steps it takes to get to the far corners of the grid, so that'll correspond to the highest-activity test case. Time to improve the other metrics. First of all, we can speed up the search within the file. Since there's never more than 2 restaurants in a file, the following solution works: code:
For the next improvement, I considered that specifically going for the correct grid space is a bit slow with all the tests if the EXA is there yet. Since the restaurant we're looking for exists in only one place, I just can have EXA REPLs check everywhere. It's a bit fiddly to have the EXAs only go where they need to be and not visit nodes several times. code:
The south- and north-bound EXAs each link in their directions twice, leaving eastbound and GRABFILE EXAs behind. This is all written out instead of using @REP so I have manual control over when to use REPL and when a JUMP suffices, to prevent creating extra EXAs. The eastbound EXAs link in their directions three times, leaving GRABFILE instances behind so the entire grid is covered. Finally, in the GRABFILE code, after SEEKing for the second restaurant entry, it has to test if that's the correct one. If there's only one entry, the TEST makes this EXA die, and if it's the wrong one, the DIVI by zero will do so. 27/41/20. Notice that I always do the REPL to the moving EXAs first, and that I start with SOUTH and NORTH before EAST. Moving to the back of the grid takes the longest so it's important to optimize it as much as possible. I also tried making the eastbound EXA spawn columns of south/north-bound ones but that was slightly slower. There's one more cycle to be saved here, though. code:
I tried more tweaking with the movement order but I couldn't get it better than this. Finally, for size, the most straightforward trick is to just use loops instead of unrolls. Remove all speed optimizations in favour of simpler code: code:
For the next improvement, we need to reuse lines. This 29-line solution does so: code:
Finally, I can combine the southbound and northbound loops by putting the LINK ids in a register: code:
Oh. Apparently, that Last Stop location is getting mobbed. Processing. People are choosing to believe the guide even when it's obviously wrong... Why would they think Last Stop has actual good food? And why did the guide change their behavior, but not the highway sign? Here is the first vote. Before I finish for today, do you remember when I posted that story from the first zine, way back in episode 7? It was a couple of pages long. The second zine contains the last half of the story, here it is. Click the images for higher resolution. Next time, we'll have another hacker battle. Time for the next opponent. Are you ready? Carbon dioxide fucked around with this message at 14:36 on Apr 18, 2022 |
# ¿ Apr 18, 2022 14:32 |
|
Yes. The zine gives you enough to at least solve all the puzzles, but doesn't go out of its way to help you find high scores.
|
# ¿ Apr 20, 2022 21:17 |
|
Part 23 - Valhalla Hacker Battle === Trash World Inbox === GuavaMoment posted:25 lines? How about 18. GuavaMoment also shared this 24 cycle solution: GuavaMoment posted:
Next, both silentsnack and GuavaMoment posted 23-cycle solutions. They are similar in the sense that they each use two EXAs, one to handle the back rows and one to handle the front rows. That's apparently very slightly faster than using a single EXA. For the sake of brevity I'll only post silentsnack's solution here but I want to mention that GuavaMoment's solution has an EXA priority quirk, where depending on what EXA's code you paste in first, it runs at either 23 or 26 cycles. silentsnack posted:
Finally, silentsnack has a 22-cycle solution which sadly doesn't fit into the size limit. silentsnack posted:
As you can see labour is now divided among 3 EXAs. I didn't really try but I can imagine getting this under the 75 size limit is impossible. It's easy to make the code (a bit) smaller, but not without having it be slower as well. === Valhalla === Oh. Apparently, that Last Stop location is getting mobbed. Processing. People are choosing to believe the guide even when it's obviously wrong... Why would they think Last Stop has actual good food? And why did the guide change their behavior, but not the highway sign? Everyone seems to be agreeing that the signs were vague. Yeah, that's always the problem with astrology, isn't it? The signs were vague. Hmm... I guess it's easier to care about food than an abstract problem. Nothing more to say about that, Ember? Well, ok. Next up, a hacker battle against =plastered. Time for the next opponent. Are you ready? These unanimous votes make it easy for me to keep count. What, you're my coach now? Would that be a bad thing? That extreme baseball book you found me was full of interesting information. Go on, champ, get out there and win. I think I just threw up into my mouth a little bit. OST: Getting Started It's much the same as before. I first have to beat =plastered before I can play against other people. The assignment reads: To win this battle you must control a majority of the hosts for as long as possible. To take control of a host, write any value to its #CTRL register. Reading from a #CTRL register will tell if you (1) or your opponent (-1) controls the host. - Gain one point every cycle you control more hosts than your opponent. - Lose one point every time one of your EXAs executes a KILL instruction. For more information see "Hacker Battle Domination" in the second issue of the zine. There's a 10 EXA limit, a 100 size limit, and each battle runs for 100 cycles. Take note of the layout of the grid. It's basically linear, but both me and the opponent connect into the one-but-last position on our sides. If I just let it run without doing anything, =plastered sends a single EXA in that first goes to the right (the end of the line), activates that node, and then goes down the path, activating each node in turn. Once it reaches my end it turns back and repeats its pattern. As usual, hacker battles are kinda trivial to win. I can actually just replicate =plastered's code one to one, like so: code:
Since =plastered doesn't bother REPLicating anything, I can just take the single-point loss of executing a well-timed KILL and win every battle with about 90 points. code:
Since the enemy EXA is gone after XB has done its thing, I don't even need the loop anymore. XA could set every #CTRL register once and die, and the rest of the cycles I just rack up points for free. If you don't want to use a KILL, another solution is to just REPL an EXA into every host and have them set #CTRL in a small loop. Because the enemy can only set a single host at once and I overwrite it the next cycle, it'll never hold a majority of the hosts. code:
Do you like it? Winning? And that brings us to our first vote already. To be fair, any chump could've beaten you, =plastered. Anyway, there's someone at the door. Sounds like my neighbor, Isadora. To anyone keeping track, the game's opening cut scene took place on Saturday, October 4th, 1997. It's now Tuesday, November 4th, so exactly one month has passed in-game. The previous cut scene with Isadora was on October 8th. Hey... Sorry I haven't been in touch. Things are a little crazy at work right now. They promoted me to a new position, and... well there's just a lot going on. I didn't notice this before but Isadora is actually wearing somewhat more formal clothes than in her previous cut scene. A nice touch. Isadora offers me a plastic bag with something inside of it. It's moderately heavy. Maybe a couple books or something? You like puzzle games, don't you? I remember you being a fan. I used to play games with my sister sometimes, but she moved to Japan a few years ago. She sent me this game, but I guess I can't play it because of the region lock. Looks fun, though. I thought maybe you could get it working. You always were good at that kind of thing. Isadora sighs. I have to go. So much work to do... really hope this job doesn't eat me up. Okay, bye for now. Speaking of puzzles, the last page of the second zine has some nonograms, also known as Picross or paint-by-numbers puzzles. Here's the instructions and the first puzzle. Since there's not much for the thread to do with these hacker battles, why not do one of these? If you want to share your result please use spoiler tags so other people get a chance to solve it for themselves too. We'll check out Isadora's video game later. First things first - I can barely hold a controller right now since the Phage seems to be acting up in my left hand. First it was your arm... now it's your hand. And that brings us to our second vote.
|
# ¿ Apr 23, 2022 14:44 |
|
|
# ¿ May 18, 2024 10:54 |
|
Part 24 - Mitsuzen HDI-10 - Left hand === Trash World Inbox === Thanks cardinale and biosterous for the nonogram submissions. biosterous posted:I'm not entirely sure what it depicts. It kinda looks like a disk in a cartridge, but it doesn't have the same shape as the Redshift disks. It might be for something we have yet to see. === Mitsuzen HDI-10 - Left hand === Do you like it? Winning? All votes went to "Sure". Sure. Of course. That's how human brains are designed, aren't they? To like winning. So that you will always try to win. It's a very simple design. Any time I start to discredit myself for being too simple, I think about human brains and feel a little better. Oof. I mean, I don't know about clones, but the main problem with most conspiracy theories is that they assume a level of government competence we've never seen in real life, so I'll have to give hydro credit for that, at least. Anyway, I need to take a break for a moment and first do something about my Phage infection. First it was your arm... now it's your hand. Three votes for "It's getting bad". Yeah, it's getting bad. I can see that. Fortunately, it looks like you can easily access the nodes connected to your median nerve. You'll just need to make a small incision in your ventral forearm. Better watch out for that artery, though. This is one of those choices where all options lead to the same dialogue. Ugh. Sounds like you're getting used to this. That's good. It's nothing to be squeamish about. OST: EXA Power All right, here's what I need to do. - There are three nerve signals that need to be relayed: muscle control (M), which runs from your central nervous system (CNS) to your hand (HND) and heat (H) and pressure (P), which run the other direction. - For each signal, read a value from the input nerve and relay it to the output nerve. Repeat ad infinitum. - It is not necessary to leave no trace. Your EXAs should be written to operate indefinitely. - For more information see "Debugging the Phage" in the first issue of the zine. Hmm. Looks like the main challenge is one of 'bandwidth'. Using the M register is usually fast, but you can only have one global signal per cycle. Having EXAs running back and forth is slower, but you can have multiple, with the limit being that you can only have one EXA traverse any specific LINK at one time. I think I'll start with the M solution and try to start optimizing for low activity since that seems easy, if not very fast. Now, sending messages from all three nerves in parallel is hard. Getting that synced up so the right EXA gets the right message. So, what if we make it simpler and just... don't? For the low activity we need to start with one EXA and REPL from there to have the minimum amount of LINKs. code:
Next, the LEFT EXA starts sending and the RIGHT one starts receiving, exactly 14 signals. code:
After "completing" the M nerve, it's time to LINK to the next nerves. Importantly, the RIGHT EXA needs to switch to sending and the LEFT one to receiving. When 14 signals have been sent in that round, they need to move on once more, but then RIGHT needs to keep sending. So I need a contextual swap of some sort. Here is the complete working program. This is where the X register comes in use. Once either the SENDLP or RECEIVELP loops are done, the EXA LINK to the next host in its direction (as stored in X), and then uses the value of X to determine whether it should be sending or receiving. So, in summary: - In the first iteration, LEFT starts out sending and RIGHT starts out receiving. - In the second iteration, the above test is first run, which sets RIGHT to sending and LEFT to receiving. - In the third iteration, the test is run again, keeping RIGHT to sending and LEFT to receiving. - After that, if the test didn't cut off the program after getting all expected signals, the EXA would try to link to a non-existent host and die. This leads to a strange solution where the nerve signals are handled nerve by nerve. Results: 181/29/9. The top percentile scores stand at 37, 24, and 9 respectively. I can make a small size improvement by moving some LINK instructions to inside the SEND and RECEIVE marks. code:
Let's look at cycle count instead. My first idea involved files. I'm still using the "we only need 14 signals" hack, but this time, three EXAs read 14 signals each into a file, take that to the recipient nerve and write from the files to there. I unrolled as many loops as I could, although the fact that the different EXAs need to move in different ways makes it hard to keep track of their state. code:
After the EXAs are done they fall through into some other code that tries to do things, but it doesn't matter, by then the tests have finished. Runs at 47/72/24, which is still 10 whole cycles away from the top percentile. Most of it wasted on walking back and forth. I think I can't get any better without involving the M register. At this point I realized that while syncing the M register is hard with three pairs of EXAs, it's surprisingly easy with two. Since an M communication step always takes two cycles (for the first EXA to publish it and then for the second to read it), using two pairs you can send one message each cycle, as long as you make sure to alternate every cycle. So, what if we change two of the nerves to make use of M, while keeping the 'file transfer protocol' EXA for the third one? Because walking takes so much time, it's probably best to use the file EXA for the M nerve, since that one's closest. I'll show you the end result because my intermediates were very confusing, dirty code. XA is the file EXA. It's now much simpler after I removed all the logic. LINK to M-CNS, read 14 values, LINK to M-HND and write them. XB handles the two other nerves. The rightbound (top half) part simply goes to the nerves and starts reading from them. Notice that the furthest EXA is exactly one cycle off from the other one (through the LINK 3 just after the REPL, so the H nerve starts sending first, causing the P one to wait a cycle, and then send, and since there's no loops or anything, just 14 repetitions of the COPY to M, they will keep alternating. For the left side, the two EXAs also are one cycle out of sync, but there it's required to use an actual two-cycle loop. If they read from M every single cycle, which EXA reads what becomes completely unpredictable. This solution started off as a one-EXA one too, but I noticed that after I'd cleaned up the code, the file transfer was the bottleneck by just a few cycles. Making it into a dedicated EXA solved this by removing the need for it to REPL several times. I still had to make sure to send it ahead of XB. Anyway, this runs at a nice score of 37/70/19. By the way, from this solution it isn't too hard to make something that actually keeps running forever, although it'll be slightly slower. code:
I have the top percentile score in cycles and activity, but didn't quite get it in size. As always it'll be interesting to see what you come up with. Do you ever feel like it's a losing battle? This constant effort to maintain your physical body. The first vote. Next time, we'll finally get to take a look at this video game Isadora got us from Japan, a game for the Sawayama WonderDisc console. Let's see what Ember has to say. WonderDisc games are restricted by region locks. Why? And that's the second vote.
|
# ¿ Apr 30, 2022 17:02 |