Skip to content

Commit 6b2d625

Browse files
authored
Support conversion directly from NumPy arrays (#33)
Support conversion directly from NumPy arrays
1 parent a65b3d8 commit 6b2d625

File tree

5 files changed

+103
-9
lines changed

5 files changed

+103
-9
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
pip install flit pytest
2525
- name: Install module
2626
run: |
27-
flit install
27+
flit install --extras test
2828
- name: Run tests
2929
run: |
3030
pytest
@@ -44,7 +44,7 @@ jobs:
4444
pip install flit pytest coverage
4545
- name: Install module
4646
run: |
47-
flit install
47+
flit install --extras test
4848
- name: Run tests
4949
run: |
5050
coverage run -m pytest

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Advent of Code® OCR
22

3-
This Python module helps with converting Advent of Code ASCII art letters into plain characters. At the moment, it only supports 6-pixel-tall characters as seen in 2016 Day 8, 2019 Days 8 and 11, and 2021 Day 13.
3+
This Python module helps with converting [Advent of Code](https://adventofcode.com/) ASCII art letters into plain characters. At the moment, it only supports 6-pixel-tall characters as seen in 2016 Day 8, 2019 Days 8 and 11, and 2021 Day 13.
44

55
Support for 10-pixel-tall characters (2018 Day 10) is coming soon.
66

@@ -37,6 +37,23 @@ print(convert_6(" $$ \n$ $\n$ $\n$$$$\n$ $\n$ $", fill_pixel="$", empty_pixe
3737
# A
3838
```
3939

40+
You can also convert data that you have in a NumPy array or a nested list:
41+
42+
```py
43+
from advent_of_code_ocr import convert_array_6
44+
45+
array = [
46+
[0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
47+
[1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1],
48+
[1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
49+
[1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
50+
[1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1],
51+
[1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
52+
]
53+
print(convert_array_6(array, fill_pixel=1, empty_pixel=0))
54+
# AOC
55+
```
56+
4057
---
4158

4259
Advent of Code is a registered trademark of Eric K Wastl in the United States.

advent_of_code_ocr/__init__.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""Convert Advent of Code ASCII art"""
22

3+
from __future__ import annotations
4+
5+
from collections.abc import Sequence
6+
37
from .characters import ALPHABET_6
48

59
__version__ = "1.0.0"
@@ -8,9 +12,31 @@
812
def convert_6(
913
input_text: str, *, fill_pixel: str = "#", empty_pixel: str = "."
1014
) -> str:
11-
"""Convert height 6 characters"""
15+
"""Convert height 6 text to characters"""
1216
input_text = input_text.replace(fill_pixel, "#").replace(empty_pixel, ".")
13-
array = input_text.split("\n")
17+
prepared_array = [list(line) for line in input_text.split("\n")]
18+
return _convert_6(prepared_array)
19+
20+
21+
def convert_array_6(
22+
array: Sequence[Sequence[str | int]],
23+
*,
24+
fill_pixel: str | int = "#",
25+
empty_pixel: str | int = "."
26+
) -> str:
27+
"""Convert a height 6 NumPy array or nested list to characters"""
28+
prepared_array = [
29+
[
30+
"#" if pixel == fill_pixel else "." if pixel == empty_pixel else ""
31+
for pixel in line
32+
]
33+
for line in array
34+
]
35+
return _convert_6(prepared_array)
36+
37+
38+
def _convert_6(array: list[list[str]]) -> str:
39+
"""Convert a prepared height 6 array to characters"""
1440

1541
# Validate input
1642
rows, cols = len(array), len(array[0])
@@ -22,7 +48,8 @@ def convert_6(
2248
# Convert each letter
2349
indices = [slice(start, start + 4) for start in range(0, cols, 5)]
2450
result = [
25-
ALPHABET_6["\n".join(row[index] for row in array)] for index in indices
51+
ALPHABET_6["\n".join("".join(row[index]) for row in array)]
52+
for index in indices
2653
]
2754

2855
return "".join(result)

pyproject.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ classifiers = [
1818
"Programming Language :: Python :: 3.9",
1919
"Programming Language :: Python :: 3.10",
2020
]
21-
dependencies = []
2221
dynamic = ["version", "description"]
2322
license = {file = "LICENSE"}
2423
name = "advent-of-code-ocr"
@@ -32,6 +31,9 @@ name = "advent_of_code_ocr"
3231
Changelog = "https://github.com/bsoyka/advent-of-code-ocr/releases"
3332
Source = "https://github.com/bsoyka/advent-of-code-ocr"
3433

34+
[project.optional-dependencies]
35+
test = ["numpy", "pytest"]
36+
3537
### TOOLS ###
3638

3739
[tool.black]
@@ -65,6 +67,7 @@ envlist = py37,py38,py39,py310
6567
isolated_build = True
6668
6769
[testenv]
68-
deps = pytest
70+
deps = .
6971
commands = pytest
72+
extras = test
7073
"""

tests/test_6.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from re import escape
22

3+
import numpy as np
34
from pytest import mark, raises
45

5-
from advent_of_code_ocr import convert_6
6+
from advent_of_code_ocr import convert_6, convert_array_6
67
from advent_of_code_ocr.characters import ALPHABET_6
78

89

@@ -82,3 +83,49 @@ def test_strange_width_characters():
8283
]
8384
)
8485
assert convert_6(string) == "EFEYKFRFIJ"
86+
87+
88+
def test_array_nested_list():
89+
array = [
90+
["X", "O", "O", "X", "X", "X", "O", "O", "X"],
91+
["O", "X", "X", "O", "X", "O", "X", "X", "O"],
92+
["O", "X", "X", "O", "X", "O", "X", "X", "X"],
93+
["O", "O", "O", "O", "X", "O", "X", "X", "X"],
94+
["O", "X", "X", "O", "X", "O", "X", "X", "O"],
95+
["O", "X", "X", "O", "X", "X", "O", "O", "X"],
96+
]
97+
assert convert_array_6(array, fill_pixel="O", empty_pixel="X") == "AC"
98+
99+
100+
def test_array_list_of_strings():
101+
array = [
102+
".oo...oo..oooo..ooo.o..o..ooo..oo..o..o",
103+
"o..o.o..o.o....o....o..o...o..o..o.o..o",
104+
"o..o.o....ooo..o....oooo...o..o....oooo",
105+
"oooo.o....o.....oo..o..o...o..o.oo.o..o",
106+
"o..o.o..o.o.......o.o..o...o..o..o.o..o",
107+
"o..o..oo..oooo.ooo..o..o..ooo..ooo.o..o",
108+
]
109+
assert convert_array_6(array, fill_pixel="o") == "ACESHIGH"
110+
111+
112+
def test_array_numpy():
113+
array = np.array(
114+
[
115+
[0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
116+
[1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1],
117+
[1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
118+
[1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
119+
[1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1],
120+
[1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0],
121+
]
122+
)
123+
assert convert_array_6(array, fill_pixel=1, empty_pixel=0) == "AOC"
124+
125+
126+
@mark.parametrize("rows", [1, 5, 7, 10])
127+
def test_array_number_of_rows(rows):
128+
with raises(
129+
ValueError, match=escape("incorrect number of rows (expected 6)")
130+
):
131+
convert_array_6(["" for _ in range(rows)])

0 commit comments

Comments
 (0)