Skip to content

Commit 422f5a4

Browse files
committed
0.3.0 redesign code, fix bugs, tests added
1 parent d2f7027 commit 422f5a4

9 files changed

+454
-230
lines changed

README.md

+21-16
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
# Crossmath algorithm prototype in Python
22

33
```
4-
0 1 2 3 4 5 6 7 8 9 10
5-
0 2 * 2 = 4
6-
1 *
7-
2 6 / 2 = 3
8-
3 =
9-
4 12 / 2 = 6
10-
5 - /
11-
6 1 + 4 = 5
12-
7 = = +
13-
8 1 1 2 + 3 = 5
14-
9 =
15-
10 7 - 5 = 2
16-
11 *
17-
12 1
18-
13 =
19-
14 2
4+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
5+
0
6+
1 8 - 4 = 4
7+
2 /
8+
3 9 7 * 2 = 14 4 + 4 = 8
9+
4 * = / +
10+
5 7 - 5 = 2 7 - 6 = 1
11+
6 = = =
12+
7 8 + 63 = 71 2 + 3 = 5
13+
8 + - +
14+
9 10 - 4 = 6 1 * 9 = 9
15+
10 = + = * =
16+
11 18 9 + 65 = 74 7 * 12 = 84
17+
12 = - = +
18+
13 13 + 5 = 18 7 + 4 = 11
19+
14 * = + =
20+
15 7 56 5 95
21+
16 = =
22+
17 35 9
23+
18
24+
19
2025
```
2126

2227
## Author

crossmath.py

+88-34
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,116 @@
22
import time
33
from typing import Tuple
44

5-
from expression import (
6-
ExpressionItems,
7-
Expression,
8-
ExpressionItem,
9-
Direction,
10-
)
5+
from expression import Expression
6+
from expression_map import ExpressionMap, ExpressionItem, Direction
117
from expression_resolver import ExpressionResolver
128

139

1410
class CrossMath:
15-
def __init__(self):
16-
self._items = ExpressionItems()
11+
def __init__(self, exp_map: ExpressionMap):
12+
self._map = exp_map
1713
self._expression_resolver = ExpressionResolver()
1814

19-
def _find_potential_positions(self, items_map: list[list]) -> list[Tuple[int, int]]:
20-
for y in range(len(items_map)):
21-
for x in range(len(items_map[y])):
22-
value = items_map[y][x]
15+
def _find_potential_positions(self) -> list[Tuple[int, int]]:
16+
for y in range(self._map.height()):
17+
for x in range(self._map.width()):
18+
value = self._map.get(x, y)
2319
if isinstance(value, int):
2420
yield x, y
2521

22+
def _check_expression_frame(
23+
self, x: int, y: int, direction: Direction, length: int
24+
) -> bool:
25+
if direction.is_horizontal():
26+
if x > 0 and self._map.get(x - 1, y) is not None:
27+
return False
28+
if (
29+
x + length + 1 < self._map.width()
30+
and self._map.get(x + length + 1, y) is not None
31+
):
32+
return False
33+
elif direction.is_vertical():
34+
if y > 0 and self._map.get(x, y - 1) is not None:
35+
return False
36+
if (
37+
y + length + 1 < self._map.height()
38+
and self._map.get(x, y + length + 1) is not None
39+
):
40+
return False
41+
else:
42+
raise ValueError(f"Not supported direction: {direction}")
43+
return True
44+
45+
def _check_x_y_overflow(self, x: int, y: int, length: int) -> bool:
46+
if x < 0:
47+
return False
48+
elif x + length >= self._map.width():
49+
return False
50+
elif y < 0:
51+
return False
52+
elif y + length >= self._map.height():
53+
return False
54+
return True
55+
2656
def _find_potential_values(
2757
self, potential_positions: list[Tuple[int, int]]
2858
) -> list[Tuple[Direction, int, int, list]]:
59+
max_expression_length = max(Expression.SUPPORTED_LENGTHS)
2960
for next_position in potential_positions:
3061
x, y = next_position
31-
slice_offset = -1
32-
slice_length = ExpressionItem.LENGTH - slice_offset
33-
values_offset = -slice_offset
34-
for direction in [Direction.HORIZONTAL, Direction.VERTICAL]:
35-
x_offset = 0 if direction == Direction.VERTICAL else slice_offset
36-
y_offset = 0 if direction == Direction.HORIZONTAL else slice_offset
37-
values = self._items.get_values(
38-
x + x_offset, y + y_offset, direction, slice_length
39-
)
40-
if values[0] is None and values[2] is None:
41-
yield (
42-
direction,
43-
x,
44-
y,
45-
values[values_offset:],
62+
for direction in Direction.all():
63+
for expression_offset in range(0, -max_expression_length - 1, -2):
64+
values_x_offset = (
65+
0 if direction.is_vertical() else expression_offset
66+
)
67+
values_y_offset = (
68+
0 if direction.is_horizontal() else expression_offset
4669
)
70+
for expression_length in Expression.SUPPORTED_LENGTHS:
71+
values_x = x + values_x_offset
72+
values_y = y + values_y_offset
73+
if not self._check_x_y_overflow(
74+
values_x, values_y, expression_length
75+
):
76+
continue
77+
78+
if not self._check_expression_frame(
79+
values_x, values_y, direction, expression_length
80+
):
81+
continue
82+
83+
values = self._map.get_values(
84+
values_x, values_y, direction, expression_length
85+
)
86+
if all([value is not None for value in values]):
87+
# already filled
88+
continue
89+
90+
yield (
91+
direction,
92+
values_x,
93+
values_y,
94+
values,
95+
)
4796

4897
def _init_generate(self):
4998
expression = self._expression_resolver.resolve(Expression())
5099
if expression is None:
51100
raise Exception("No expression found")
52101
direction = random.choice([Direction.HORIZONTAL, Direction.VERTICAL])
53-
self._items.append(ExpressionItem(0, 0, direction, expression))
102+
item = ExpressionItem(
103+
3,
104+
3,
105+
direction,
106+
expression,
107+
)
108+
self._map.put(item)
54109

55110
def generate(self):
56111
start_time = time.time()
57112
self._init_generate()
58-
for i in range(20):
59-
items_map = self._items.get_map()
60-
potential_positions = self._find_potential_positions(items_map)
113+
for i in range(40):
114+
potential_positions = self._find_potential_positions()
61115
potential_values = list(self._find_potential_values(potential_positions))
62116
random.shuffle(potential_values)
63117
is_expression_appended = False
@@ -66,7 +120,7 @@ def generate(self):
66120
# print("desc:", desc, "x:", _x, "y:", _y)
67121
try:
68122
expression = self._expression_resolver.resolve(
69-
Expression.instance_from_values(values)
123+
Expression.from_values(values)
70124
)
71125
except ValueError:
72126
# TODO store dead positions
@@ -75,7 +129,7 @@ def generate(self):
75129
# TODO store dead positions
76130
continue
77131
expression_item = ExpressionItem(_x, _y, direction, expression)
78-
self._items.append(expression_item)
132+
self._map.put(expression_item)
79133
is_expression_appended = True
80134
break
81135
if not is_expression_appended:
@@ -84,4 +138,4 @@ def generate(self):
84138
print("time: ", time.time() - start_time)
85139

86140
def print(self):
87-
self._items.print()
141+
self._map.print()

dev-requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-r requirements.txt
2+
pytest~=8.1
3+
parametrize-from-file~=0.19

0 commit comments

Comments
 (0)