Home >Web Front-end >JS Tutorial >Disk Fragments
The phases as I see them spelled out:
None of it feels particularly difficult.
And some of it actually seems like yet another fun algorithmic challenge!
I want to turn this:
12345
Into this:
0..111....22222
I need to consider:
Here's my disk-generating algorithm:
let id = 0 let disk = [] for (let i = 0; i < input.length; i++) { if (i % 2 == 1) { // Odd for (let j = 0; j < +input[i]; j++) { disk.push('.') } } else { // Even for (let j = 0; j < +input[i]; j++) { disk.push(id) } id++ } }
Works like a charm!
What would make this easier is having a list of all empty places on the disk.
I need to update my algorithm in two places:
Testing it on the example shows the expected index numbers of each .!
This is the list I'll iterate through as I move values from the end of the list to the beginning and onward.
But wait.
This may be more difficult that I thought.
How will I know when to stop trying to move values?
This is the last state of the short example:
022111222......
And of the first example:
0099811188827773336446555566..............
Which means there comes a point where all id's are on the left and all empty spaces are on the right.
How would I check for that state?
Enter: the number 10.
The amount of contiguous empty spaces will never be higher than 9.
So, if I come across an empty space, look forward 9 spaces (or to the end of the disk list), and see all empty spaces, I know I'll have finished fragmenting.
I think I know how to write the rest of this algorithm!
Here's the working algorithm:
let diskI = disk.length - 1 let emptyI = 0 while (true) { while (disk[diskI] == '.') { diskI-- } disk[empty[emptyI]] = disk[diskI] disk[diskI] = '.' emptyI++ diskI-- if (disk.slice(empty[emptyI],empty[emptyI] + 10).every(el => el == '.')) { break; } }
How it works:
Two trackers: - one for my place in the disk - one for my place in the list of empty slots Do until manually escaped Do as long as the current place in the disk is an empty slot Adjust the tracker one to the left Swap the values at each tracker Decrement the disk tracker Increment the empty tracker If there are 9 empty slots contiguous with the current empty slot Escape the loop
Thankfully, I see the same output as in both examples!
This seems fairly easy and straightforward:
let part1 = disk.slice(0, disk.indexOf('.')).reduce((checksum, id, position) => { checksum += (+id * position) return checksum }, 0)
In pseudocode:
Extract all values up to the first empty cell Iterate through each value, amassing a total Increment the accumulator by the product of the value and its index
Success! It generates the correct answer for the example input!
Will it do the same for my puzzle input?
...
YES!!!
Woohoo!!!
What will the twist be for Part Two? A slight rule adjustment or some challenge of scale?
Was parts. Now whole.
This will definitely require some adjustment of my algorithm.
Probably more robust tracking of sizes of gaps and blocks.
I was tracking where each empty was.
I think I need to track where - and how big - each empty is.
What would that look like?
Scratch that. Maybe new strategy.
Using the first example:
12345
The file block sizes are the odd numbers:
0..111....22222
The empty cell sizes are the even numbers:
let id = 0 let disk = [] for (let i = 0; i < input.length; i++) { if (i % 2 == 1) { // Odd for (let j = 0; j < +input[i]; j++) { disk.push('.') } } else { // Even for (let j = 0; j < +input[i]; j++) { disk.push(id) } id++ } }
Starting from the end of the odd numbers and the beginning of the even numbers, I look for an even number greater than or equal to the odd number:
022111222......
I immediately find a match.
As a result:
0099811188827773336446555566..............
This strategy definitely won't work.
I don't like the performance implications of this one.
But I trust it will work...as long as it finishes running.
For each number in the disk input, I'll record as a list item:
As an example:
let diskI = disk.length - 1 let emptyI = 0 while (true) { while (disk[diskI] == '.') { diskI-- } disk[empty[emptyI]] = disk[diskI] disk[diskI] = '.' emptyI++ diskI-- if (disk.slice(empty[emptyI],empty[emptyI] + 10).every(el => el == '.')) { break; } }
Will become:
Two trackers: - one for my place in the disk - one for my place in the list of empty slots Do until manually escaped Do as long as the current place in the disk is an empty slot Adjust the tracker one to the left Swap the values at each tracker Decrement the disk tracker Increment the empty tracker If there are 9 empty slots contiguous with the current empty slot Escape the loop
Ew, let's clean that up:
let part1 = disk.slice(0, disk.indexOf('.')).reduce((checksum, id, position) => { checksum += (+id * position) return checksum }, 0)
I will distinguish gaps from file blocks by way of data type.
Moving file blocks will look like this in an altered example input:
Extract all values up to the first empty cell Iterate through each value, amassing a total Increment the accumulator by the product of the value and its index
This will involve in each 100k iterations:
Both are very costly tasks.
But it's the only way I can think of to solve this puzzle.
So, this shall be my approach.
Here's the JavaScript that gets me the above data architecture:
2333133121414131402
How will I start and end my main loop?
Attempt to move each file exactly once in order of decreasing file ID number starting with the file with the highest file ID number
Seems like moving back-to-front will do what I need.
This for loop skeleton should work:
[2,4,1,4,2,5,5,3,5,2]
[3,3,3,1,1,1,1,1,0]
That second clause in the if was my last debug. It was putting the lowest IDs too early.
I realized I had to see my disk being fragmented in near-real-time. At least a log of it, like in the example walkthrough.
Thankfully, coding it wasn't difficult. Just the part where I mixed up two indices and saw some real weird output:
12345
It works great! I could see where files were being moved, and troubleshoot my code much easier!
0..111....22222
It looks like my file-moving algorithm works!
Last step is to calculate the new checksum.
By way of a double-reduce:
let id = 0 let disk = [] for (let i = 0; i < input.length; i++) { if (i % 2 == 1) { // Odd for (let j = 0; j < +input[i]; j++) { disk.push('.') } } else { // Even for (let j = 0; j < +input[i]; j++) { disk.push(id) } id++ } }
On the example puzzle input? YES!
On my puzzle input?
...
YEEESSSSSS!
Wow. I'm surprised. The number I submitted for Part 2 is almost identical to Part 1. I thought it would be higher.
I'm not interested in investigating further.
I'd rather take my two hard-earned gold stars and walk along to Day 10.
Byeeeeee Day 9!
The above is the detailed content of Disk Fragments. For more information, please follow other related articles on the PHP Chinese website!