|
my favorite level is coming up! I'mma vote for 'you get used to it' and 'this is silly'.
|
# ? Dec 31, 2021 15:25 |
|
|
# ? May 5, 2024 03:12 |
|
You get used to it This is silly
|
# ? Dec 31, 2021 19:36 |
|
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. The range of signals goes from -120 to 50. Adding 35 makes that -85 to 85. Multiplying that by 117 will make a value of 85 be 9945, but 86 be 10062 - clamped to 9999. So, the transmission of signals can be performed without using any conditional logic. The transmitter adds 35 and multiplies by 117; the receiver divides by 117 and subtracts 35. Finis! code:
code:
(you could probably get better efficiency at expense of size by unrolling the main loop some, but I'm happy with this) Quackles fucked around with this message at 01:04 on Jan 1, 2022 |
# ? Jan 1, 2022 00:50 |
|
You get used to it This is a lovely haiku This is so silly 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. My best is 123/14/6 by adding and subtracting 9949 (and then subtracting and adding 9879) to every number. However, some of my wizard steam friends have scores of 36 cycles - that's about how fast you could simply feed numbers from one location to the other, so I imagine there's some kind of state-machine-esque solution here. Carbon dioxide posted:Interesting. I attempted this but couldn't make it work. You could start with an EXA that stores the first two values in X and T, then REPLs, write those two into a file, and meanwhile another EXA grabs the "Cheese" from file 280. But no matter what I tried it would take more than 13 cycles. 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. code:
|
# ? Jan 1, 2022 01:57 |
|
GuavaMoment posted:My best is 123/14/6 by adding and subtracting 9949 (and then subtracting and adding 9879) to every number. Oh, I can get 96/50/6 by unrolling some loops, I guess I never went back to this one to try advanced concepts.
|
# ? Jan 1, 2022 02:01 |
|
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:code:
All of the superfluous LINK 1 interlaced in the logic was because I kept running into problems with race conditions and/or having too many EXAs pile up in a host. I guess 38 is okay, and as a plus it looked really stupid in motion: Quackles posted:If a number goes above 9999 or -9999, it is set to 9999 or -9999. Ah, yeah this is what I was missing. Uggggh. code:
code:
...and as the other world-weary burnouts have said, "you get used to it" and "this is silly" silentsnack fucked around with this message at 02:28 on Jan 1, 2022 |
# ? Jan 1, 2022 02:26 |
|
Fifty Bucks for a modem?! My god this really is some kind of 90's cyberfantasy.
|
# ? Jan 1, 2022 05:52 |
|
Gideon020 posted:Fifty Bucks for a modem?! My god this really is some kind of 90's cyberfantasy. I used to occasionally see $20 modems in the store during the late 90s. Yes, the box listed basic functionality as if it was advanced features. No, I never bought one to see how bad it was.
|
# ? Jan 1, 2022 08:25 |
|
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 |
|
The exact handling of overflow can depend on the instruction used and the particulars of a give microprocessor. Though usually its just a difference between signed and unsigned, I don't recall it ever clamping. I don't get it, no. He's an old friend.
|
# ? Jan 8, 2022 17:38 |
|
Carbon dioxide posted:If there are further improvements possible, I don't know them. 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. You can save one more cycle by not having the line COPY M X and testing over M every time. One exa grabs file 300 and constantly sends PEANUTS over M. But how does that exa know when to stop? It doesn't. You have a third exa wait exactly 21 cycles and KILL your transmitting exa. Five cycles later you complete the level, worst case scenario. 26/45/3 There's a really good pun over the name Snaxnet but that should come into play in the next Snaxnet level.
|
# ? Jan 8, 2022 18:49 |
|
Kind of...? and I help people when I can.
|
# ? Jan 8, 2022 19:01 |
|
I don't get it, no.; I help people when I can
|
# ? Jan 8, 2022 20:36 |
|
AweStriker posted:I don't get it, no.; I help people when I can Seconding this.
|
# ? Jan 9, 2022 02:21 |
|
idhrendur posted:The exact handling of overflow can depend on the instruction used and the particulars of a give microprocessor. Though usually its just a difference between signed and unsigned, I don't recall it ever clamping. Some MMX/SSE intrinsics/vector instructions saturate rather than overflow (including one with a very bizarre name: maddubs)
|
# ? Jan 9, 2022 02:44 |
|
ColTim posted:Some MMX/SSE intrinsics/vector instructions saturate rather than overflow (including one with a very bizarre name: maddubs) Is *that* what saturate is about. I kept seeing it while reverse engineering some firmware years ago and didn't have a clue. It wasn't really relevant to what I was trying to learn, but remember being a little confused.
|
# ? Jan 9, 2022 06:44 |
|
So, when I originally played this game I was playin with a friend who knows as little about coding as me, when we got to the nut free peanut bars we both broke out laughing the moment I read off the objective. We nearly died. And now we're at the level I'm too stupid to figure out so I will 100% be copying some code from the LP...
|
# ? Jan 9, 2022 13:19 |
|
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 |
|
I don't Know I doubt it. I can't make heads or tails of programming, so I'm just along for the story.
|
# ? Jan 15, 2022 21:18 |
|
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 |
|
They're zebras, but they're also brothers. just because we may not find it funny, doesn't mean we have to pretend we don't understand it. Maybe what's the time frame of this game? I was expecting to see some outcome from the poor x10x10x just wanted some peanuts
|
# ? Jan 15, 2022 21:30 |
|
Carbon dioxide posted: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. Dunno, kinda vague but also Doubtful 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 code:
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 code:
code:
|
# ? Jan 15, 2022 21:51 |
|
I vote for zebras and also brothers and maybe.
|
# ? Jan 15, 2022 23:07 |
|
NullBlack posted:what's the time frame of this game? I was expecting to see some outcome from the From that last cutscene, the phage is probably messing with the protagonist's memories, so who knows how much time is passing.
|
# ? Jan 15, 2022 23:55 |
|
silentsnack posted:For whatever reason, the distribution of file lengths and position of the target line make the longest solution faster to find by jumping to the end and searching backwards, even with the added time to get the file pointer into the right position this one runs 55/50/4. 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 code:
|
# ? Jan 16, 2022 04:11 |
|
Zebras but also bro(ther)s I doubt it
|
# ? Jan 16, 2022 05:18 |
|
Zebras but also brothers, What kind of slogans?
|
# ? Jan 16, 2022 07:01 |
|
1 zebra bros 2 what kind of slogans?
|
# ? Jan 16, 2022 14:57 |
|
Brother and Zebra are a printer brands.
|
# ? Jan 16, 2022 19:05 |
|
biosterous posted:2 what kind of slogans?
|
# ? Jan 17, 2022 01:14 |
|
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 |
|
Carbon dioxide posted:93/43/3 You can have one exa feeding in the row data: code:
code:
code:
code:
GuavaMoment fucked around with this message at 23:00 on Jan 22, 2022 |
# ? Jan 22, 2022 22:58 |
|
Carbon dioxide 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.
|
# ? Jan 22, 2022 23:07 |
|
Looking up my old solution, I was able to get 94/34/1 with some tweaking of macros.code:
|
# ? Jan 22, 2022 23:45 |
|
GuavaMoment posted:You can have one exa feeding in the row data: 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) code:
This is about where the game starts throwing puzzles at you with enough complexity where it becomes more relevant that when an EXA tries to write to the M register, even if one is already waiting to receive, the sender still has to waste a cycle in the "I'm waiting to send!" state. Also the @REP in XC needs to be any number that isn't 3 or 9 because if the loop trying to JUMP then XC doesn't crash until another cycle later when trying to arithmetic a nil due to EOF. edit: it can actually be 24 lines instead of 26 if you don't mind being harder for human readers to parse, since if XA and XB are both trying to LINK 800 then XB goes first, drop XA's NOOP and COPY setup and swap the ADDI and REPL lines. ...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. code:
...which turns out to be an even cruder approach, forgoing loops in favor of recursion and bruteforce @REP spam silentsnack fucked around with this message at 05:50 on Jan 23, 2022 |
# ? Jan 22, 2022 23:57 |
|
Carbon dioxide posted:Can friendship exist without self-interest?
|
# ? Jan 23, 2022 00:07 |
|
Yeah, Why couldn't it?
|
# ? Jan 23, 2022 00:14 |
|
Why couldn't it?
|
# ? Jan 23, 2022 01:59 |
|
|
# ? May 5, 2024 03:12 |
|
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 |