Search code examples
javascriptnode.jstypescriptalgorithmtree

Decoding a Message from a Text File - Javascript


I am trying to develop a function named decode(message_file). This function should read an encoded message from a .txt file and return its decoded version as a string. The function must be able to process an input file with the following format:

3 love
6 computers
2 dogs
4 cats
1 I
5 you

In this file, each line contains a number followed by a word. The task is to decode a hidden message based on the arrangement of these numbers into a "pyramid" structure. The pyramid increases by one number per line, like so:

  1
 2 3
4 5 6

The key to decoding the message is to use the words corresponding to the numbers at the end of each pyramid line (in this example, 1, 3, and 6). You should ignore all the other words.

I'm having difficulty obtaining the desired result.

Here's the code I've tried:

function decode(input) {
    const lines = input.trim().split('\n');
    let decodedWords = [];
    let currentIndex = 0;
    for (const line of lines) {

        const words = line.trim().split(' ');
        const currentWord = words[currentIndex];
        decodedWords.push(currentWord);

        currentIndex++;
    }
    return decodedWords.join(' ');
}

const input = `3 love
6 computers
2 dogs
4 cats
1 I
5 you`;

const message = decode(input);
console.log(message);

My current code is producing the output of 3 computers when I need it to produce I love computers

After we get this working, I need it to decode the contents of this list:

195 land
235 sun
111 too
60 huge
5 dont
229 such
15 noun
176 student
136 brown
248 complete
36 play
65 cook
221 yard
84 clock
231 would
183 plain
187 excite
199 fire
298 wish
39 cool
91 child
148 past
118 colony
292 oil
287 dog
184 back
280 money
138 kind
249 open
102 finger
14 touch
252 are
99 dad
227 am
125 modern
140 meant
55 ocean
270 pitch
132 suit
154 town
22 east
126 over
3 group
179 good
19 kind
71 down
134 band
1 especially
117 organ
49 of
200 fire
17 out
212 area
69 touch
166 happen
238 sat
274 electric
104 wrote
262 buy
172 lot
152 stop
43 corn
137 where
239 check
41 live
9 best
77 hold
300 cause
246 grand
59 present
21 indicate
62 counter
288 we
265 like
109 visit
57 state
10 morning
198 true
224 are
218 ball
207 history
188 seat
165 rain
119 less
233 glass
214 tone
220 song
38 fair
4 element
243 speed
223 produce
80 quotient
112 sand
50 begin
32 moment
258 offer
276 probable
163 all
97 necessary
295 post
106 cent
240 happen
267 speech
259 object
196 silver
192 third
156 crease
26 wait
285 triangle
257 idea
100 clothe
289 young
237 discuss
282 field
95 company
64 capital
13 compare
268 chart
129 possible
293 written
46 remember
236 mile
234 cold
34 lady
93 felt
170 against
56 skin
250 prepare
153 he
186 card
201 organ
205 object
115 our
70 major
27 discuss
45 system
245 hole
272 above
76 they
58 produce
244 straight
160 level
266 though
54 modern
294 dry
37 bought
180 milk
279 make
185 show
178 middle
52 center
35 blood
261 speak
122 prove
281 select
173 power
225 come
121 brown
63 experiment
18 strong
89 hurry
159 touch
105 reach
269 case
47 beat
73 over
251 dry
94 hill
48 company
273 opposite
290 work
226 field
263 felt
213 prepare
6 now
260 his
168 stay
189 toward
133 observe
197 time
81 stop
66 possible
169 card
31 prepare
11 current
28 compare
151 neighbor
222 thus
33 include
40 copy
85 bit
283 stead
164 does
78 general
175 solve
182 glad
158 duck
74 offer
44 happen
216 ball
123 bread
161 like
171 machine
145 come
299 any
24 band
147 it
255 section
96 close
30 heavy
194 produce
232 got
254 possible
2 insect
215 way
150 before
217 men
209 bird
8 ease
98 trade
83 winter
131 am
42 repeat
113 first
120 to
253 each
162 guide
67 column
103 single
20 remember
228 wild
146 major
75 coast
114 class
135 done
157 jump
242 sister
149 feel
88 check
7 fire
167 nine
29 indicate
92 parent
277 whole
128 her
124 the
203 temperature
202 design
16 big
53 skill
296 friend
286 hit
116 wait
141 instant
291 blow
210 about
143 chick
275 answer
110 man
191 material
208 current
177 think
144 print
181 nor
51 better
247 example
155 people
79 drink
284 gun
174 together
90 cost
142 require
68 or
206 people
72 planet
25 ease
264 ready
82 enough
87 sugar
127 deal
130 with
101 us
204 share
139 office
230 protect
12 low
241 thus
193 farm
278 oxygen
190 fire
86 force
211 select
297 paragraph
107 always
108 poem
271 chick
256 planet
23 fact
61 moment
219 term

Solution

  • The general idea is to first parse the file then sort the obtained entries by the number and then calculate the positions of the last element in a line in a pyramid until we reach the end of the array.

    To do that you have to image that you flatten the pyramid to an array i. e.

      1 
     2 3
    4 5 6
    

    becomes

          +---+---+---+---+---+---+
    Value | 1 | 2 | 3 | 4 | 5 | 6 |
          +---+---+---+---+---+---+
    Index   0   1   2   3   4   5 
          
    

    With that in mind the most challenging thing is coming up with a working formula that can give you the position of the last element in a row within the pyramid i. e. an index within the array based on the row you are at. We can derive this if we have a look at the first couple of rows:

    index := index of the element at the end of the row in a pyramid within the array

    height pyramid index diff to height + 1 Previous index Calculation
    0 1 0 2 - 0
    1 2 3 2 3 0 0 + 1 + 1 = 2
    2 4 5 6 5 4 2 2 + 2 + 2 = 5
    3 7 8 9 10 9 5 5 5 + 3 + 1 = 9
    4 11 12 13 14 15 14 6 9 9 + 4 + 1 = 14

    Looking at that we can conclude that we can use the following formula:

    new index = previous index + height + 1

    Obviously the first index is always 0, so we can use that as a start value.

    Using that formula we now have to just iterate through the array and pick out the words. Last but not least we need to concatenate them.

    /**
     * A token
     * @typedef {Object} Token
     * @property {number} index - Number in a line
     * @property {string} word - Word next to the number in a line
     */
    
    /**
     * Parses string of words and indices
     * @param {string} input string of words and indices
     * @returns {Array<Token>} list of tokens
     */
    const parse = (input) =>
      input
        .trim()
        .split("\n")
        .map((x) => {
          const [index, word] = x.split(" ");
          return { index: parseInt(index), word };
        });
    
    // Formula: new index = previous index + height + 1
    
    // height | pyramid          | index | diff to height + 1   | Previous index | Calculation    |
    //--------|------------------|-------|----------------------|----------------|----------------|
    //      0 |        1         |     0 |                    2 |              - |              0 |
    //      1 |       2 3        |     2 |                    3 |              0 | 0 + 1 + 1 =  2 |
    //      2 |      4 5 6       |     5 |                    4 |              2 | 2 + 2 + 2 =  5 |
    //      3 |     7 8 9 10     |     9 |                    5 |              5 | 5 + 3 + 1 =  9 |
    //      4 |  11 12 13 14 15  |    14 |                    6 |              9 | 9 + 4 + 1 = 14 |
    // ...
    
    /**
     * Decode tokens to sentence.
     * @param {Array<Token>} tokens
     * @returns {string} decoded sentence
     */
    const decode = (tokens) => {
      // sort tokens
      // This takes O(n log n) but with counting sort you can bring this down to O(n + k) with k being the range of your input number 1-300 here
      const sortedTokens = tokens.toSorted((a, b) => a.index - b.index);
      // actual decode
      let height = 0;
      const wordsOfSentence = [];
      for (let index = 0; index < sortedTokens.length; index = index + height + 1) {
        const word = sortedTokens[index].word;
        wordsOfSentence.push(word);
        height++;
      }
      return wordsOfSentence.join(" ");
    };
    
    const longSentence = `195 land
    235 sun
    111 too
    60 huge
    5 dont
    229 such
    15 noun
    176 student
    136 brown
    248 complete
    36 play
    65 cook
    221 yard
    84 clock
    231 would
    183 plain
    187 excite
    199 fire
    298 wish
    39 cool
    91 child
    148 past
    118 colony
    292 oil
    287 dog
    184 back
    280 money
    138 kind
    249 open
    102 finger
    14 touch
    252 are
    99 dad
    227 am
    125 modern
    140 meant
    55 ocean
    270 pitch
    132 suit
    154 town
    22 east
    126 over
    3 group
    179 good
    19 kind
    71 down
    134 band
    1 especially
    117 organ
    49 of
    200 fire
    17 out
    212 area
    69 touch
    166 happen
    238 sat
    274 electric
    104 wrote
    262 buy
    172 lot
    152 stop
    43 corn
    137 where
    239 check
    41 live
    9 best
    77 hold
    300 cause
    246 grand
    59 present
    21 indicate
    62 counter
    288 we
    265 like
    109 visit
    57 state
    10 morning
    198 true
    224 are
    218 ball
    207 history
    188 seat
    165 rain
    119 less
    233 glass
    214 tone
    220 song
    38 fair
    4 element
    243 speed
    223 produce
    80 quotient
    112 sand
    50 begin
    32 moment
    258 offer
    276 probable
    163 all
    97 necessary
    295 post
    106 cent
    240 happen
    267 speech
    259 object
    196 silver
    192 third
    156 crease
    26 wait
    285 triangle
    257 idea
    100 clothe
    289 young
    237 discuss
    282 field
    95 company
    64 capital
    13 compare
    268 chart
    129 possible
    293 written
    46 remember
    236 mile
    234 cold
    34 lady
    93 felt
    170 against
    56 skin
    250 prepare
    153 he
    186 card
    201 organ
    205 object
    115 our
    70 major
    27 discuss
    45 system
    245 hole
    272 above
    76 they
    58 produce
    244 straight
    160 level
    266 though
    54 modern
    294 dry
    37 bought
    180 milk
    279 make
    185 show
    178 middle
    52 center
    35 blood
    261 speak
    122 prove
    281 select
    173 power
    225 come
    121 brown
    63 experiment
    18 strong
    89 hurry
    159 touch
    105 reach
    269 case
    47 beat
    73 over
    251 dry
    94 hill
    48 company
    273 opposite
    290 work
    226 field
    263 felt
    213 prepare
    6 now
    260 his
    168 stay
    189 toward
    133 observe
    197 time
    81 stop
    66 possible
    169 card
    31 prepare
    11 current
    28 compare
    151 neighbor
    222 thus
    33 include
    40 copy
    85 bit
    283 stead
    164 does
    78 general
    175 solve
    182 glad
    158 duck
    74 offer
    44 happen
    216 ball
    123 bread
    161 like
    171 machine
    145 come
    299 any
    24 band
    147 it
    255 section
    96 close
    30 heavy
    194 produce
    232 got
    254 possible
    2 insect
    215 way
    150 before
    217 men
    209 bird
    8 ease
    98 trade
    83 winter
    131 am
    42 repeat
    113 first
    120 to
    253 each
    162 guide
    67 column
    103 single
    20 remember
    228 wild
    146 major
    75 coast
    114 class
    135 done
    157 jump
    242 sister
    149 feel
    88 check
    7 fire
    167 nine
    29 indicate
    92 parent
    277 whole
    128 her
    124 the
    203 temperature
    202 design
    16 big
    53 skill
    296 friend
    286 hit
    116 wait
    141 instant
    291 blow
    210 about
    143 chick
    275 answer
    110 man
    191 material
    208 current
    177 think
    144 print
    181 nor
    51 better
    247 example
    155 people
    79 drink
    284 gun
    174 together
    90 cost
    142 require
    68 or
    206 people
    72 planet
    25 ease
    264 ready
    82 enough
    87 sugar
    127 deal
    130 with
    101 us
    204 share
    139 office
    230 protect
    12 low
    241 thus
    193 farm
    278 oxygen
    190 fire
    86 force
    211 select
    297 paragraph
    107 always
    108 poem
    271 chick
    256 planet
    23 fact
    61 moment
    219 term`;
    
    const shortSentence = `3 love
    6 computers
    2 dogs
    4 cats
    1 I
    5 you`;
    
    /**
     * Process input and log result
     * @param {string} input input
     */
    const process = (input) => {
      const tokens = parse(input);
      return decode(tokens);
    };
    
    console.log(`Short sentence decoded: ${process(shortSentence)}`);
    console.log(`Long sentence decoded: ${process(longSentence)}`);
    /* Stackoverflow: show only console */
    .as-console-wrapper {
      max-height: 100% !important;
      top: 0;
    }

    Remarks on result

    I noticed that the long sentence decoded does not make much sense, but the algorithm should be correct (I've crossed check the first couple words manually and they are correct but don't make much sense as a sentence either). Might be that I made an error copying the words although I've checked at least the first couple words or your input and not seen any errors there or your input is not properly encoded or there is another element to the algorithm which I might have missed or you've missed in the specification.

    Remarks on runtime

    The runtime depends on how fast you can sort with this approach. As currently implemented this runs in O(n log n) because general sort algorithms based on comparisons cannot be faster than that. But you could use counting sort here which would give you linear runtime O(n+k), where k is the range of the non-negative key values for sorting.