···2020assert sameChars("123", "123") == True
2121assert sameChars("", "a") == False
2222assert sameChars("", "") == True
2323-assert sameChars(14, "14") == False
2323+# assert sameChars(14, "14") == False # this check passes but if I don't comment it I get an editor warning since I've typed the function
2424print("Passed!")
+17
python/oct2/level2/addUpcBarcodeCheckDigit.py
···11+def addUpcBarcodeCheckDigit(barcode: str) -> str:
22+ """Adds the check digit to a UPC barcode."""
33+ evenChecks = [int(digit) for i, digit in enumerate(barcode) if i % 2 == 0]
44+ oddChecks = [int(digit) for i, digit in enumerate(barcode) if i % 2 != 0]
55+ evenTotal = sum(int(digit) for digit in evenChecks) * 3
66+ oddTotal = sum(int(digit) for digit in oddChecks)
77+ checkDigit = 10 - (evenTotal + oddTotal) % 10
88+ return barcode + (str(checkDigit) if checkDigit != 10 else "0")
99+1010+1111+print("Testing addUpcBarcodeCheckDigit()...", end="")
1212+assert addUpcBarcodeCheckDigit("03600029145") == "036000291452"
1313+assert addUpcBarcodeCheckDigit("11111111111") == "111111111117"
1414+assert addUpcBarcodeCheckDigit("23232323232") == "232323232329"
1515+assert addUpcBarcodeCheckDigit("12345678900") == "123456789005"
1616+assert addUpcBarcodeCheckDigit("00000000000") == "000000000000"
1717+print("Passed!")
+50
python/oct2/level2/simpleCipher.py
···11+def encodeSimpleCipher(s: str) -> str:
22+ """
33+ Encode a string using this formula.
44+ - s[i] = 2*i
55+ - if 2*i > len(s), s[i] = (2*i) % len(s)
66+ """
77+ encoded = list(s)
88+ for i in range(len(s)):
99+ j = (2 * i) % len(s)
1010+ cj = encoded[j]
1111+ encoded[j] = encoded[i]
1212+ encoded[i] = cj
1313+ return "".join(encoded)
1414+1515+1616+def decodeSimpleCipher(s: str) -> str:
1717+ """Decode a string encoded from encodeSimpleCipher"""
1818+ decoded = list(s)
1919+ for i in range(len(s) - 1, -1, -1):
2020+ j = (2 * i) % len(s)
2121+ cj = decoded[j]
2222+ decoded[j] = decoded[i]
2323+ decoded[i] = cj
2424+ return "".join(decoded)
2525+2626+2727+print("Testing encodeSimpleCipher()...", end="")
2828+assert encodeSimpleCipher("AB") == "BA"
2929+assert encodeSimpleCipher("ABC") == "ABC"
3030+assert encodeSimpleCipher("ABCD") == "BCDA"
3131+assert encodeSimpleCipher("ABCDEFGH") == "BCFGDEHA"
3232+assert encodeSimpleCipher("SECRET MESSAGE") == "MCE SSTSAEREEG"
3333+assert (
3434+ encodeSimpleCipher("THIS IS A LONGER SECRET MESSAGE JUST FOR YOU!")
3535+ == "T SAENG SR MGARJ H U!SSTE TFECORIIEYSELUOOS"
3636+)
3737+print("Passed!")
3838+3939+4040+print("Testing decodeSimpleCipher()...", end="")
4141+assert decodeSimpleCipher("BA") == "AB"
4242+assert decodeSimpleCipher("ABC") == "ABC"
4343+assert decodeSimpleCipher("BCDA") == "ABCD"
4444+assert decodeSimpleCipher("BCFGDEHA") == "ABCDEFGH"
4545+assert decodeSimpleCipher("MCE SSTSAEREEG") == "SECRET MESSAGE"
4646+assert (
4747+ decodeSimpleCipher("T SAENG SR MGARJ H U!SSTE TFECORIIEYSELUOOS")
4848+ == "THIS IS A LONGER SECRET MESSAGE JUST FOR YOU!"
4949+)
5050+print("Passed!")
+45
python/oct2/level2/spellCheck.py
···11+def spellCheck(lookupWord: str, words: str) -> str | None:
22+ """Spell check a word against a list of words."""
33+ map = {}
44+ for word in words.split():
55+ map[word] = levenshtein(lookupWord, word)
66+ min_distance = min(map.values())
77+ if min_distance >= 3:
88+ return None
99+ return ",".join([word for word in map.keys() if map[word] == min_distance])
1010+1111+1212+# from: https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Python
1313+def levenshtein(s1: str, s2: str) -> int:
1414+ if len(s1) < len(s2):
1515+ return levenshtein(s2, s1)
1616+1717+ # len(s1) >= len(s2)
1818+ if len(s2) == 0:
1919+ return len(s1)
2020+2121+ previous_row = range(len(s2) + 1)
2222+ for i, c1 in enumerate(s1):
2323+ current_row = [i + 1]
2424+ for j, c2 in enumerate(s2):
2525+ insertions = (
2626+ previous_row[j + 1] + 1
2727+ ) # j+1 instead of j since previous_row and current_row are one character longer
2828+ deletions = current_row[j] + 1 # than s2
2929+ substitutions = previous_row[j] + (c1 != c2)
3030+ current_row.append(min(insertions, deletions, substitutions))
3131+ previous_row = current_row
3232+3333+ return previous_row[-1]
3434+3535+3636+print("Testing spellCheck()...", end="")
3737+words = "cat cow dog frog"
3838+assert spellCheck("frog", words) == "frog" # frog is correct
3939+assert spellCheck("cats", words) == "cat" # cat is distance 1
4040+assert spellCheck("caw", words) == "cat,cow" # cat and cow are distance 1
4141+assert spellCheck("drog", words) == "dog,frog" # dog and frog are distance 1
4242+assert spellCheck("kit", words) == "cat" # cat is distance 2
4343+assert spellCheck("ack", words) == None # cat, cow, and dog are
4444+# distance 3 (too far)
4545+print("Passed!")
+52
python/oct2/level2/wrapText.py
···11+def wrapText(text: str, lineSize: int) -> str:
22+ """Wrap text to a specified line size."""
33+ lines = []
44+ words = text.split()
55+ currentLine = ""
66+ for word in words:
77+ if len(currentLine) + len(word) > lineSize:
88+ currentLine = currentLine.rstrip()
99+ currentLine = currentLine.ljust(lineSize)
1010+ currentLine = f"|{currentLine}|"
1111+ lines.append(currentLine)
1212+ currentLine = f"{word} "
1313+ else:
1414+ currentLine += f"{word} "
1515+ else:
1616+ currentLine = currentLine.rstrip()
1717+ currentLine = currentLine.ljust(lineSize)
1818+ currentLine = f"|{currentLine}|"
1919+ lines.append(currentLine)
2020+ return "\n".join(lines)
2121+2222+2323+print("Testing wrapText()...", end="")
2424+text = """\
2525+This is some sample text. It is just sample text.
2626+Nothing more than sample text. Really, that's it."""
2727+2828+textWrappedAt20 = """\
2929+|This is some sample |
3030+|text. It is just |
3131+|sample text. Nothing|
3232+|more than sample |
3333+|text. Really, that's|
3434+|it. |"""
3535+3636+assert wrapText(text, 20) == textWrappedAt20
3737+3838+textWrappedAt30 = """\
3939+|This is some sample text. It |
4040+|is just sample text. Nothing |
4141+|more than sample text. Really,|
4242+|that's it. |"""
4343+4444+assert wrapText(text, 30) == textWrappedAt30
4545+4646+textWrappedAt40 = """\
4747+|This is some sample text. It is just |
4848+|sample text. Nothing more than sample |
4949+|text. Really, that's it. |"""
5050+5151+assert wrapText(text, 40) == textWrappedAt40
5252+print("Passed!")