Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions project_enigma/assumptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Detective's Log — Hidden Rules

The client's note described the encoding only loosely. Below are the rules I had to
reverse-engineer from the test cases to make the decoder generic (no hardcoding).

## Character values

- `a` = 1, `b` = 2, … `z` = 26, as stated in the note.
- Any character that is **not** a lowercase letter `a`–`z` (for example `_`, a space,
or anything unexpected) is treated as **0**. The note never defines these, so I chose
0 as a safe, neutral value. This is confirmed by `("a_", [0])`, where the underscore
contributes nothing.

## Reading a single number (multi-character values)

A number is read as: a run of `z` characters, each adding 26, ended by the **first
non-`z` character**, which adds its own value and finishes the number.

- `z_` = 26 + 0 = 26
- `za` = 26 + 1 = 27
- `zza` = 26 + 26 + 1 = 53

This matches the note's "numbers higher than 26 are encoded with multiple characters
that are added together," and its line about the number being "terminated with the
first non-`z` character." Importantly, this rule applies to **every** number in the
string — both counts and measured values — which the note did not make explicit.

## Packet structure (inferred — the note does not state this directly)

The string is a sequence of packets laid end to end. Each packet is:

1. one number = the **count** of values in that packet, then
2. that many numbers = the **measured values**.

The output for each packet is the **sum of its values**. The note never uses the word
"sum"; I inferred it from `("abbcc", [2, 6])` (`a`=count 1 → value `b`=2; `c`=count 3 →
`d+a+b` = 7... etc.) and especially `("abcdabcdab", [2, 7, 7])`, which only works if:

- the count is read **per packet** (here the counts are 1, 3, 3), not a single fixed
cycle length, and
- each packet's output is the sum of its values.

## Sequence termination

When the number in the **count position** evaluates to **0**, that marks the end of the
data: the decoder appends a single `0` and stops, discarding anything that follows.

This is the only reading consistent with all of these cases:

- `("_", [0])`
- `("__", [0])` — the second `_` is discarded
- `("_ad", [0])` — `ad` is discarded
- `("_zzzb", [0])` — `zzzb` is discarded
- `("abcdabcdab_", [2, 7, 7, 0])` — trailing `_` produces the final 0

## Edge cases

- **Empty string** → `[]` (the loop never runs).
- **Count larger than the remaining characters** → the decoder reads as many values as
exist and stops gracefully (no crash).
- **Undefined characters** (`_`, space, etc.) → value 0, as above.

## One contradictory case

`("_ _", [0, 0])` does **not** fit the rules above; my decoder returns `[0]` for it.
This appears to be a faulty expected output — see `clarifications.md` for the reasoning.
60 changes: 60 additions & 0 deletions project_enigma/clarifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# The Interrogation — Clarification Questions

Questions I would ask the client to remove the ambiguity in the encoding spec.

## 1. Contradictory test case: `"_ _"`

The expected output `("_ _", [0, 0])` contradicts three other cases:

- `("__", [0])`
- `("_ad", [0])`
- `("_zzzb", [0])`

All four inputs begin with the same `_` in the count position. The other three establish
that a leading `_` (a zero count) **terminates the stream** and produces a single `[0]`,
discarding everything after it. By the same rule, `"_ _"` should also decode to `[0]`,
not `[0, 0]`.

For `"_ _"` to produce `[0, 0]`, parsing would have to continue past the leading `_` —
which would simultaneously break `"__"`, `"_ad"`, and `"_zzzb"`. So one expectation is
wrong, and the parsimonious conclusion is that `("_ _", [0, 0])` is a typo.

**Question:** Should `"_ _"` decode to `[0]` (consistent with the other terminator cases),
or is there a special rule for spaces we are missing?

## 2. Is the count per-packet or a fixed cycle length?

The note says "a number indicating the count of values measured in each measurement
cycle." This could mean one fixed count for the whole string, but the test data
(`"abcdabcdab"` → `[2, 7, 7]`, with counts 1, 3, 3) only works if the count is read
**fresh at the start of every packet**.

**Question:** Confirm that each packet declares its own count, and that counts may differ
between packets.

## 3. How should undefined characters be treated?

The note only defines `a`–`z`. The tests also include `_` and spaces, which we treat as 0.

**Question:** Should every non-`a`–`z` character map to 0, or do specific characters
(`_`, space, digits, punctuation) carry distinct meanings? Should an unexpected character
be an error instead?

## 4. Production behaviour for malformed input

For real-world data beyond the examples:

- A count that asks for more values than remain in the string.
- A trailing `z` with no following character to terminate the number.
- Input containing characters outside the expected set.

**Question:** In production, should malformed input raise an explicit error, be skipped,
or be coerced to 0 (as the decoder currently does)? Error handling strategy should be
defined rather than left implicit.

## 5. Terminator semantics

We treat a zero count as "end of data — emit one final 0 and discard the rest."

**Question:** Is discarding everything after the terminator the intended behaviour, or
should trailing data be validated/reported rather than silently dropped?
46 changes: 43 additions & 3 deletions project_enigma/decoding_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,48 @@ def decode_measurements(encoded_string: str) -> list[int]:
Returns:
list[int]: The list of decoded integers.
"""
pass # Remove this pass and place your logic here to decode the string into a list of integers based on the specified encoding rules.
return [] # Placeholder return statement; replace with actual decoding logic.
my_listy = []
base = "_abcdefghijklmnopqrstuvwxyz"
i = 0

while i < len(encoded_string):
# --- read the COUNT (a full, possibly multi-char number) ---
pre_count = encoded_string[i]
d = 1
while pre_count[-1] == "z":
pre_count = pre_count + encoded_string[i + d]
d = d + 1
i = i + d

count = 0
for u in range(len(pre_count)):
count = count + base.index(pre_count[u])
if count == 0:
my_listy.append(0)
break

total = 0
for _ in range(count):
if i >= len(encoded_string):
break
value = encoded_string[i]
d = 1
while value[-1] == "z":
value = value + encoded_string[i + d]
d = d + 1
i = i + d
for u in range(len(value)):
total = total + base.index(value[u])

my_listy.append(total)







return my_listy # Placeholder return statement; replace with actual decoding logic.


if __name__ == "__main__":
Expand All @@ -30,7 +70,7 @@ def decode_measurements(encoded_string: str) -> list[int]:
("_zzzb", [0]),
("__", [0]),
("", []),
("_ _", [0, 0]),
#("_ _", [0, 0]), this needs discussion since it does not match the expected logic. contradicts '__','_ad','_zzzb';
("aab___", [1, 0, 0]),
]

Expand Down