Search code examples
pythonformatting

Decoding a Message from a Text File - Issue with Formatting


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:

def decode(message_file):
    with open(message_file, "r") as f:
        lines = f.readlines()
  
    # Initialize an empty list to store the message words
    message_words = []

    # Loop through the lines in reverse order
    for line in reversed(lines):
        # Split the line by space and get the first element as the number
        number = int(line.split()[0])

        # Check if the number is equal to the length of the message words list
        # This means that the number is at the end of a pyramid line
        if number == len(message_words) + 1:
            # Get the second element as the word and insert it at the beginning of the message words list
            word = line.split()[1]
            message_words.insert(0, word)

    # Join the message words with spaces and return the result
    return " ".join(message_words)

file_path = "coding_qual_input.txt"
decoded_message = decode(file_path)
print(decoded_message)

And here's the content of "coding_qual_input.txt":

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

My current code is producing the output of love dogs I 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

  • Trying out your code, I indeed did get the same unwanted answer you note. In reviewing that the code is supposed to select words associated with the last value in a "pyramid" line, it was quickly evident that those values equate back to solving a summation for any given input value from "1" to the input value (e.g. from "1" to "100"). And that equates back to a standard formula for summations, "sum(x) = (x * x + x) / 2" (the sum of x squared plus x divided by two). Executing a quick program with that formula results in values that equate to the last value in each "pyramid" line.

    for x in range (50):
        print("value:", x, int((x * x + x)/2))
        
    craig@Vera:~/Python_Programs/Decode$ python3 Listing.py 
    value: 0 0
    value: 1 1
    value: 2 3
    value: 3 6
    value: 4 10
    value: 5 15
    value: 6 21
    value: 7 28
     . . .
    value: 45 1035
    value: 46 1081
    value: 47 1128
    value: 48 1176
    value: 49 1225
    

    Using that fundamental as the basis for matching up coded input data, following is a refactored version of your program.

    def decode(message_file):
        with open(message_file, "r") as f:
            lines = f.readlines()
      
        # Initialize an empty list to store the message words
        message_words = []
    
        # Store a null length placeholder in each list element
        for x in range(100):
            message_words.append('')
    
        # Loop through the lines
        for line in lines:
            # Split the line by space and get the first element as the number
            number = int(line.split()[0])
    
            # Determine if the number equates to the last element value of a "pyramid" line
            for x in range(100):
                if number == (int((x * x + x)/2)):
                    message_words[x] = line.split()[1]
                    break
    
        # Now, concatenate the non-null list values together to form a sentence.
        text = ""
    
        for x in message_words:
            if x != '':
                text = text + x + " "
    
        # Return the result
        return text
    
    file_path = "coding_qual_input.txt"
    decoded_message = decode(file_path)
    print(decoded_message)
    

    The key bits to point out are as follows:

    • The message list is set up and initialized beforehand with null values stored in each list element.
    • The lines are then read and the numeric portion (first part) of the line is evaluated to see if its numeric portion matches up to a summation value, and if so, that corresponding element in the list is updated with the text portion of the line.
    • Once all lines have been processed, a text sentence is built by concentrating all non-null list entries, and the text sentence is returned to the main function.

    Testing out the refactored code with the simpler six-line text file resulted in the requested output.

    3 love
    6 computers
    2 dogs
    4 cats
    1 I
    5 you
    
    craig@Vera:~/Python_Programs/Decode$ python3 Decode.py 
    I love computers 
    

    Testing out the refactored code with the larger text file resulted in the following output.

    craig@Vera:~/Python_Programs/Decode$ python3 Decode.py 
    especially group now morning noun indicate compare play system ocean possible general child reach to brown he machine fire about would each probable cause
    

    You will have to be the final arbiter on this if this is truly what the decoded output was to be (the words for line 1, 3, and 6 agree with the text line values). Also, there might be efficiencies added in the value testing to discontinue testing of a line value once the range test value is greater than the line value. But this hopefully should give food for thought.