|
| 1 | +def find_different(text: str) -> int: |
| 2 | + """Returns the index of mirrored pairs that hold different values.""" |
| 3 | + indexed_pairs = enumerate(zip(text, text[::-1])) |
| 4 | + i = next((i for i, (a, b) in indexed_pairs if a != b), len(text) // 2) |
| 5 | + return i |
| 6 | + |
| 7 | + |
| 8 | +def encode(msg: str) -> str: |
| 9 | + i = find_different(msg) |
| 10 | + n = len(msg) // 2 |
| 11 | + |
| 12 | + if len(msg) % 2 == 0: |
| 13 | + return msg[:n] + msg[i] + msg[n:] |
| 14 | + |
| 15 | + middle = msg[n] if msg[i] == "0" else ["1", "0"][int(msg[n])] |
| 16 | + head = msg[: n + 1] |
| 17 | + tail = msg[n + 1 :] |
| 18 | + return head + middle + tail |
| 19 | + |
| 20 | + |
| 21 | +def decode(msg: str) -> str: |
| 22 | + i = find_different(msg) |
| 23 | + n = len(msg) // 2 |
| 24 | + |
| 25 | + if len(msg) % 2 == 1: |
| 26 | + received = msg[:n] + msg[n + 1 :] |
| 27 | + if msg[i] != msg[n]: |
| 28 | + return received[::-1] |
| 29 | + return received |
| 30 | + |
| 31 | + head = msg[: n - 1] |
| 32 | + mid1 = msg[n - 1] |
| 33 | + mid2 = msg[n] |
| 34 | + tail = msg[n + 1 :] |
| 35 | + expected = ["0", "1"][mid1 != mid2] |
| 36 | + if msg[i] != expected: |
| 37 | + return (head + mid2 + tail)[::-1] |
| 38 | + return head + mid1 + tail |
| 39 | + |
| 40 | + |
| 41 | +def test_protocol(): |
| 42 | + for n in range(1, 7): |
| 43 | + for i in range(2**n): |
| 44 | + bits = f"{i:0{n}b}" |
| 45 | + assert len(bits) == n |
| 46 | + test_string(bits) |
| 47 | + |
| 48 | + |
| 49 | +def test_string(original): |
| 50 | + encoded = encode(original) |
| 51 | + decoded = decode(encoded) |
| 52 | + |
| 53 | + if original != decoded: |
| 54 | + print(f"FAIL {original} -> {encoded} -> {decoded}") |
| 55 | + |
| 56 | + decoded = decode(encoded[::-1]) |
| 57 | + |
| 58 | + if original != decoded: |
| 59 | + print(f"FAIL {original} -> {encoded[::-1]} -> {decoded}") |
| 60 | + |
| 61 | + |
| 62 | +if __name__ == "__main__": |
| 63 | + test_protocol() |
0 commit comments