-
Notifications
You must be signed in to change notification settings - Fork 17
/
decompress-alg-2.js
158 lines (110 loc) · 3.99 KB
/
decompress-alg-2.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/**
* Had to cheat for this one, looked up the algorithm on the
* reddit solution thread. Seeing the algorithm, it makes total
* sense but honestly not sure how long it would have taken me
* to come up with that one.
*
* I've copied the post in its entirety below.
*
* @see https://www.reddit.com/r/adventofcode/comments/5hbygy/2016_day_9_solutions/dazentu/
*/
/*
In short the idea is to give each character in the input a weight, or
multiplier if you will. Then for each character, as the input is read,
increase its weight according to the decompression markers. This is roughly
the steps taken:
- Initialise all characters weights to 1
- Scan input one character at a time and
- if it's a normal character, count its weight towards the total length
- if it's the beginning of a marker, read the marker and multiply character
weights forward in the input, according to the values of the marker.
- Print out the value of length
-----------------------------------------------------------------------------
Using the second example from the puzzle description
as an input; "X(8x2)(3x3)ABCY", the algorithm would run as follows:
1.
Weights: [111111111111111], length: 0
"X(8x2)(3x3)ABCY"
^
X is a normal character, so we add its weight to length.
2.
Weights: [111111111111111], length: 1
"X(8x2)(3x3)ABCY"
^
( is the beginning of a marker, so we read it and update the following
weights according to its values.
3.
Weights: [111111222222221], length: 1
"X(8x2)(3x3)ABCY"
^
( is the beginning of a marker, so we read it and update the following
weights according to its values.
4.
Weights: [111111222226661], length: 1
"X(8x2)(3x3)ABCY"
^
A is a normal character, so we add its weight to length.
5.
Weights: [111111222226661], length: 7
"X(8x2)(3x3)ABCY"
^
B is a normal character, so we add its weight to length.
6.
Weights: [111111222226661], length: 13
"X(8x2)(3x3)ABCY"
^
C is a normal character, so we add its weight to length.
7.
Weights: [111111222226661], length: 19
"X(8x2)(3x3)ABCY"
^
Y is a normal character, so we add its weight to length.
8.
Weights: [111111222226661], length: 20
"X(8x2)(3x3)ABCY"
^
We're at the end of input, so we read out the final result to be 20.
*/
const decompress = str => {
let weights = Array(str.length).fill(1);
let total_length = 0;
let in_marker = false;
// Use objects so I can set my `filling` variable by reference.
let chars = { val: '' },
repeat = { val: '' };
let filling;
for (let i = 0; i < str.length; i++) {
let char = str[i];
if (char === '(') {
in_marker = true;
// Reset temp parsing variables
chars.val = '';
repeat.val = '';
// Reference `chars` that I am currently parsing
filling = chars;
} else if (in_marker) {
if (char === 'x') {
// Finished parsing `chars`, start parsing `repeat` next
filling = repeat;
} else if (char === ')') {
// No longer in the marker
in_marker = false;
// Parse our numbers
let chars_int = parseInt(chars.val);
let repeat_int = parseInt(repeat.val);
// Update the weights accordingly
for (let c = 1; c <= chars_int; c++) {
weights[i + c] *= repeat_int;
}
} else {
// Extract the relevant characer into either `chars.val` or `repeat.val`
filling.val += char;
}
} else {
// Regular letter, add its weight to our total
total_length += weights[i];
}
}
return total_length;
};
module.exports = decompress;