Part 51: CrystalAir International
Part 51 - CrystalAir International=== Trash World Inbox ===
Quackles posted:
Here's the best solution I have.While the code is in one EXA, the EXA becomes three during running the code. This first EXA, the file manager, simply grabs the list of files and REPLs as needed to start recovering the next file in the set, passing in the name and address of the file.code:
;SETUP LINK 800 GRAB 200 MARK NEXTFILE COPY F X REPL FILEBOT COPY F M VOID M ;NOW WAIT FOR ACK TEST EOF FJMP NEXTFILE ;HALTS TRYING TO HOLD TWO FILES
The second EXA sits in the drive controller, holding the file that will be the 'clean' copy of the episode (we also keep the ID of the file to t. It sends out an 'explorer' EXA (using the routine EXPLORER1) to try and gain entry to the drive. If the link attempt fails (killing the explorer EXA), it will retry as often as needed.code:
MARK FILEBOT ;MAKES FILE, SENDS PROBES OUT TO COLLECT DATA MAKE COPY X F COPY M F MODE MARK PROBE801 ;GO TO DRIVE 1, COPY EVERYTHING THERE COPY 801 T REPL EXPLORER1 NOOP NOOP TEST MRD FJMP PROBE801 VOID M MARK COPY801 COPY M T FJMP START802 COPY T F @REP 5 COPY M F @END JUMP COPY801
Once the drive controller EXA is assured of the connection, it copies the contents of the file from the first drive, FAILs and all, to its own file. The value 0 never appears in the video files, so the drive controller EXA can interpret a 0 as a signal to cut the connection. However, we can be clever about this - every file's length is a multiple of 6 values, so we only need to check for 0 on the first value received out of every six! This speeds up the copying procedure.
(I'll detail the EXPLORER1 routine later, but it basically copies over the entire file in a speed-optimized way, using paralellism with REPL.)The drive controller EXA now has to interpolate the values from the other two drives. However, for efficiency, we don't copy the entire file again. Instead, the drive controller EXA sends over an EXA using the EXPLORER2 routine.code:
MARK START802 ;GO TO DRIVE 2, BE JUDICIOUS SEEK -9999 COPY F X SEEK 1 MARK PROBE802 COPY 802 T REPL EXPLORER2 NOOP NOOP TEST MRD FJMP PROBE802 VOID M COPY 0 X MARK COPY802 TEST F > -9999 FJMP WRITE802 ADDI X 1 X TEST EOF FJMP COPY802 JUMP START803 MARK WRITE802 COPY X M SEEK -1 COPY M F COPY 0 X TEST EOF FJMP COPY802
The EXPLORER2 EXA will wait for instructions, then move forward through the file, copying over the value that's in a specific location.
To do its part, the drive controller EXA scans the existing 'clean' copy of the file for FAIL values (TEST F > -9999). It keeps track of the number of value in the file since the last FAIL value in X.
Once the drive controller finds a FAIL, it sends the value of X to the EXPLORER2 EXA. That EXA will move forward that many places in the file and report what it reads over global M. Then, the drive controller can patch the FAIL in its copy of the file with the received value.After sending a 9999 over M to make the explorer EXA in the second drive halt (it will try to read past the end of the file), we repeat this process with the third drive. The third drive's explorer EXA also uses the EXPLORER2 read routine (but takes less time overall, since there are (hopefully) fewer FAIL values left in the drive controller's file).code:
MARK START803 ;ALSO BE JUDICIOUS WITH DRIVE 3 COPY 9999 M ;KILL 802 EXA SEEK -9999 COPY F X SEEK 1 MARK PROBE803 COPY 803 T REPL EXPLORER2 NOOP NOOP TEST MRD FJMP PROBE803 VOID M COPY 0 X MARK COPY803 TEST F > -9999 FJMP WRITE803 ADDI X 1 X TEST EOF FJMP COPY803 JUMP FINISH MARK WRITE803 COPY X M SEEK -1 COPY 0 X COPY M F TEST EOF FJMP COPY803
With the completed file in our possession, the drive controller EXA halts the third explorer, notifies the file manager EXA that the file is fully recovered, clears the file address from where we were storing it at the start of the file, and delivers the file to our host.code:
MARK FINISH COPY 9999 M MODE COPY 1 M ;NOTIFY CONTROLLER FILE IS DONE LINK -1 SEEK -9999 VOID F ;HALTS TRYING TO LINK TO AN INVALID ADDRESS
This is the routines used by the explorer EXAs. The first routine, EXPLORER1 (and EXPLSEND1) copies the entire data of the file over M. However, sending a value over M has a 1-cycle startup delay on the part of the sender (but not the receiver). So, instead, the explorer EXA reads two values into X and T, then REPLs to EXPLSEND1.code:
MARK EXPLORER1 LINK T GRAB X COPY 0 M ;WE MADE IT ACROSS! MARK EXPLCOPY1 @REP 3 COPY F X COPY F T REPL EXPLSEND1 ;SENDS BOTH VALUES @END TEST EOF FJMP EXPLCOPY1 REPL NULL COPY 0 M ;HALTS TRYING TO LINK TO AN INVALID ADDRESS MARK EXPLORER2 LINK T GRAB X COPY 0 M ;WE MADE IT ACROSS! MARK EXPLCOPY2 SEEK M ;WHERE TO READ NEXT? COPY F M JUMP EXPLCOPY2 ;HALTS TRYING TO READ FROM EOF MARK EXPLSEND1 ;SEND VALUES AND QUIT COPY X M COPY T M MARK NULL ;DUMMY REPL - USED TO WAIT FOR OTHER REPL'D EXAS TO CLEAR
While it reads the next two values, EXPLSEND1 sends the first two over M, then quits. There is only enough space for one REPLd EXA in eacha drive, so the next batch of values will wait while the first batch of values is sent.
Once we reach the end of the file, we use REPL NULL to wait for the last file sending EXA to clear. There are no instructions after MARK NULL, so the dummy EXA does nothing, while the explorer sends an 0, indicating end-of-file.
The second explorer routine, EXPLORER2, is much simpler. It reads a value over M telling it how many places forward to move in the file. It then sends back the value it finds there. This loops forever until it runs off the end of the file, which the drive controller EXA does deliberately by sending it a 9999 when it's time to finish with that drive.
4886/124/35. I do think it's possible to get a better result, but it'd involve a lot of paralellism, using REPL and local M to pipeline steps of the data processing.
You could probably find some low-hanging fruit with an approach that reads the entire file from each drive. The first read simply writes it to the file directly. The second read could read in and REPL off to test if a value was FAIL, and then write to the file... anyway, I'm happy with what I've achieved.
Quackles explains it well. The main speed-ups are in only sending values that failed before using the SEEK M trick, and also using a REPL to actually send data over M for the first file.
You need to send one EXA per drive per file across the broken links and I didn't want to deal with that which is why I did one drive at a time, but handling the files serially definitely makes the code easier to optimize.
=== CrystalAir International- Ticketing System ===
And just like that, we're at the last of our currently unlocked tasks.
OST: Code and Registers
The assignment:
- Each host in the network corresponds to a country and contains a list of tickets for flights (file 200) departing airports in that country, bound for airports either also in that country or in a connected country. Each ticket has the following values: ticket ID, departure airport, departure time, arrival airport, and arrival time.
- Book the sequence of flights in deadlock's itinerary (file 300) by deleting each ticket from its file in the network and adding the ticket ID to file 301, choosing the first valid flight that departs after the preceding flight arrives.
- Note that deadlock's itinerary will always begin in the USA, and that flight times may be compared with TEST.
Looks like the USA is always the host we're directly connecting to, and that the network layout is the same for all the tests. I also think the tickets in each country's file are ordered by departure time.
In this first test, our itinerary is DFW -> JFK -> CDG -> IBZ.
Also there's a little thing that confused me in this test case. It says "Remove the tickets from the files (0/2)" at the goals in the bottom left. There's 3 tickets to find, it actually says 2 because there's only two files to remove tickets from, since DFW and JFK are both in the US.
Well, to get started I'll find the first flight from DFW to JFK in the USA's file.
I wrote two EXAs for that:
code:
;XA
MARK START
GRAB 300
COPY F M
COPY F X
MARK SENDAGAIN
COPY X M
COPY M T
FJMP SENDAGAIN
SEEK -9999
VOID F
DROP
GRAB 301
COPY T F
DROP
JUMP START
XB looks like this.
code:
;XB
LINK 800
GRAB 200
COPY M X
SEEK 1
MARK TRYNEXT
TEST X = F
TJMP POSSIBLYFOUND
SEEK 4
JUMP TRYNEXT
MARK POSSIBLYFOUND
SEEK 1
TEST M = F
TJMP FOUND
COPY 0 M
SEEK 2
JUMP TRYNEXT
MARK FOUND
COPY F X
SEEK -5
COPY F M
SEEK -1
@REP 5
VOID F
@END
It goes into the USA host, puts the departure airport in X, then starts looking for flights leaving from there. If it finds one, it requests the arrival airport over M and checks if that's a match too. If not, it sends a zero back and keeps looking. Otherwise, it SEEKs back to the ticket number, sends that on M, and removes all 5 values for the ticket from the file.
The next part is harder. The next airport can be in the same country or any adjacent country (I sure hope it can't be two countries over, that'd make the puzzle much harder). And we have to check the departure time as well. I wrote the last flight's arrival time to XB's X register for now but that won't fit.
Let's ignore the departure time for now and first build the search in adjacent countries.
After deleting the first ticket, XB now makes REPLs going in all four cardinal directions, and the original one stays where it is. They do a KILL, then GRAB the file. Then they all repeat the search code. This works efficiently because only one will have the file with the current departure airport. It's the only one that will ever ask for the arrival airport over M. All others will either reach EOF and die, or they'll stay busy until the next round, which is why I needed that KILL. It'll clear up leftovers from the previous round.
It's possible to shift things here a bit - I don't need the DROP, KILL and GRAB for the EXA that stays in the current country. But this kept the code simpler.
So, this code gets me the earliest known flight for each route. It still ignores departure times.
Also, the EXAs get stuck at the end looking for a final connection that doesn't exist. But let's fix the departure times issue first.
What I need to do is compare the arrival time of the last round with the departure time of this one. That's not going to fit in XB, so I'll have XA handle it as well.
code:
;XA
GRAB 300
SEEK 9999
COPY 0 F
SEEK -9999
MARK START
COPY F M
COPY F X
SEEK 9999
MARK SENDAGAIN
COPY X M
COPY M T
FJMP SENDAGAIN
SEEK -1
COPY F M
COPY M T
FJMP SENDAGAIN
SEEK -1
COPY T F
SEEK -9999
VOID F
DROP
GRAB 301
SEEK 9999
COPY M F
DROP
GRAB 300
JUMP START
XB now sends the ticket number as a third M message, which XA writes to file 301. I had to put in a SEEK 9999 in there because my code kept overwriting the first number.
XB needed significant changes to make this work.
code:
;XB
LINK 800
COPY M X
MARK SEARCH
KILL
GRAB 200
SEEK 1
MARK TRYNEXT
TEST X = F
TJMP POSSIBLYFOUND
SEEK 4
JUMP TRYNEXT
MARK POSSIBLYFOUND
SEEK 1
TEST M = F
TJMP FOUNDFLIGHT
COPY 0 M
SEEK 2
JUMP TRYNEXT
MARK FOUNDFLIGHT
COPY 1 M
SEEK -2
TEST F < M
FJMP FOUND
COPY 0 M
SEEK 3
JUMP TRYNEXT
MARK FOUND
SEEK 1
COPY F M
SEEK -5
COPY F M
SEEK -1
@REP 5
VOID F
@END
DROP
COPY M X
COPY 4 T
MARK SPREADOUT
REPL MOVE
SUBI T 1 T
TJMP SPREADOUT
JUMP SEARCH
MARK MOVE
ADDI 799 T T
LINK T
JUMP SEARCH
The SEEKs changed a bit to handle the extra jumping back and forth in the file.
This code writes the right result, but XA will tell XB to go find a flight from the final destination to... the arrival time, which makes no sense. XB can't find that and XA will wait for a response forever. Let's go fix that.
XA just needs some code at the bottom to check if only the final destination and the arrival time are left.
code:
SEEK 2
TEST EOF
SEEK -9999
FJMP START
COPY 0 M
code:
COPY M X
TEST X = 0
TJMP END
That was a quite nice puzzle, not nearly as hard to figure out as some of the other post-game ones. 345/83/25. Top percentiles are 136, 58 and 8.
For the speed, well, I do a lot of waiting on M. I'm sure that could be more efficient. Looking at the graphs, there's lots of people who somehow needed the full 150 lines of code to solve this. That high peak in the activity is probably what happens if you send an EXA to each country every round. The top percentile of 8 is interesting, though. You could send an EXA to each country once and have it start searching when getting a message on M, but there's 12 countries so that would still be an activity of 12. I think it involves something like only sending EXAs to neighbouring nodes when needed, but then actually keeping them there. So nodes that are completely in the wrong direction will never get visited and no link will be traversed twice.
Either that or there are actually some countries deadlock never wants to go to.
The next task is finally for Moss again. And as usual, Ember has some things to say.
Well, this is something.
I can see an open network that's... I can't even tell how big.
Imagine all the computers in the world were hooked up to each other, and you would start to get an idea of the size.
No way to know just how big until we explore, though.
You have no idea how much I missed this part. Here's the first vote!
A little bit later in the same conversation, Ember has another question.
Why, do you think it could be dangerous?
The second vote.