humanized grid as entry
This commit is contained in:
parent
47ccffaf81
commit
fbc133b8a9
122
main.py
122
main.py
@ -2,11 +2,16 @@ import itertools
|
||||
from copy import deepcopy
|
||||
from itertools import combinations, combinations_with_replacement
|
||||
|
||||
OP_PLUS = "PLUS"
|
||||
OP_MINUS = "MINUS"
|
||||
OP_MULTIPLY = "MULTIPLY"
|
||||
OP_DIVIDE = "DIVIDE"
|
||||
OP_NONE = "NONE"
|
||||
# up right down left
|
||||
DIRECTIONS = [(0, -1), (1, 0), (0, 1), (-1, 0)]
|
||||
OP_PLUS = "+"
|
||||
OP_MINUS = "-"
|
||||
OP_MULTIPLY = "x"
|
||||
OP_DIVIDE = "/"
|
||||
OP_NONE = "#"
|
||||
|
||||
BOX_H_LABELS = 'ABCDEFGHI'
|
||||
BOX_V_LABELS = '123456789'
|
||||
|
||||
|
||||
def lambda_mul(x):
|
||||
@ -24,12 +29,13 @@ OP_LAMBDAS = {
|
||||
OP_NONE: lambda x: x[0],
|
||||
}
|
||||
|
||||
BOX_H_LABELS = 'ABCDEFGHI'
|
||||
BOX_V_LABELS = '123456789'
|
||||
|
||||
|
||||
def translate_box_to_rc(box, grid_size):
|
||||
return BOX_V_LABELS.index(box[1]), BOX_H_LABELS[grid_size-1::-1].index(box[0])
|
||||
return BOX_V_LABELS.index(box[1]), BOX_H_LABELS[grid_size - 1::-1].index(box[0])
|
||||
|
||||
|
||||
def translate_rc_to_box(row_id, col_id, grid_size):
|
||||
return BOX_H_LABELS[col_id] + BOX_V_LABELS[grid_size - row_id - 1]
|
||||
|
||||
|
||||
def has_line_integrity(line):
|
||||
@ -183,28 +189,88 @@ class Game(object):
|
||||
return sol
|
||||
|
||||
|
||||
def main():
|
||||
game = Game(grid_size=6,
|
||||
blocks=[
|
||||
Block(boxes=['A6', 'B6', 'C6', 'D6'], operation=OP_MULTIPLY, result=120),
|
||||
Block(boxes=['E6', 'E5', 'E4', 'F4'], operation=OP_PLUS, result=17),
|
||||
Block(boxes=['F6', 'F5'], operation=OP_PLUS, result=5),
|
||||
Block(boxes=['A5', 'B5'], operation=OP_MINUS, result=1),
|
||||
Block(boxes=['C5', 'C4'], operation=OP_DIVIDE, result=2),
|
||||
Block(boxes=['D5', 'D4'], operation=OP_PLUS, result=3),
|
||||
Block(boxes=['A4', 'A3'], operation=OP_PLUS, result=5),
|
||||
Block(boxes=['B4', 'B3', 'C3'], operation=OP_MULTIPLY, result=30),
|
||||
Block(boxes=['D3', 'D2', 'E2'], operation=OP_MULTIPLY, result=15),
|
||||
Block(boxes=['B2', 'C2', 'C1'], operation=OP_MULTIPLY, result=10),
|
||||
Block(boxes=['A2'], operation=OP_NONE, result=6),
|
||||
Block(boxes=['A1', 'B1'], operation=OP_DIVIDE, result=3),
|
||||
Block(boxes=['D1', 'E1'], operation=OP_MINUS, result=1),
|
||||
Block(boxes=['F1', 'F2', 'F3', 'E3'], operation=OP_PLUS, result=16),
|
||||
])
|
||||
grid = game.solve(grid=init_grid(game.grid_size))
|
||||
def walk_grid_to_boxes(grid, row_id, col_id, initial_cell, boxes):
|
||||
"""Recursively walk through the boxes in a grid going up,left,down,right to construct
|
||||
a contiguous block of same operations."""
|
||||
grid_size = len(grid)
|
||||
for v_offset, h_offset in DIRECTIONS:
|
||||
new_row_id, new_col_id = row_id + h_offset, col_id + v_offset
|
||||
# avoid wrap-around
|
||||
if not (0 <= new_row_id < grid_size and 0 <= new_col_id < grid_size):
|
||||
continue
|
||||
box = translate_rc_to_box(new_row_id, new_col_id, grid_size)
|
||||
if box in boxes:
|
||||
continue
|
||||
cell = grid[new_row_id][new_col_id].strip()
|
||||
if cell == initial_cell:
|
||||
boxes.append(box)
|
||||
walk_grid_to_boxes(grid, new_row_id, new_col_id, initial_cell, boxes)
|
||||
return boxes
|
||||
|
||||
|
||||
def construct_blocks(grid):
|
||||
"""Reads a grid of operations and converts them to contiguous blocks."""
|
||||
grid_size = len(grid)
|
||||
blocks, used_boxes = [], []
|
||||
for row_id, row in enumerate(grid):
|
||||
assert len(row) == grid_size
|
||||
for col_id, cell in enumerate(row):
|
||||
box = translate_rc_to_box(row_id, col_id, grid_size)
|
||||
if box in used_boxes:
|
||||
continue
|
||||
cell = cell.strip()
|
||||
operation = cell[-1]
|
||||
assert operation in OP_LAMBDAS.keys()
|
||||
value = int(cell[:-1])
|
||||
boxes = walk_grid_to_boxes(grid, row_id, col_id, cell, [box])
|
||||
used_boxes += boxes
|
||||
blocks.append(Block(boxes=boxes, operation=operation, result=value))
|
||||
return grid_size, blocks
|
||||
|
||||
|
||||
def print_grid(grid):
|
||||
for line in grid:
|
||||
print(line)
|
||||
|
||||
|
||||
def solve_game(grid: list):
|
||||
grid_size, blocks = construct_blocks(grid)
|
||||
game = Game(grid_size=grid_size, blocks=blocks)
|
||||
grid = game.solve(grid=init_grid(game.grid_size))
|
||||
print_grid(grid)
|
||||
|
||||
|
||||
def main():
|
||||
"""Construct a game using the +-x/ symbols for operations and the number before that.
|
||||
Whitespace around is meaningless and can be used to arrange the matrix visually."""
|
||||
solve_game([
|
||||
['120x', '120x', '120x', '120x', '17+', '5+ '],
|
||||
['1- ', '1- ', '2/ ', '3+ ', '17+', '5+ '],
|
||||
['5+ ', '30x ', '2/ ', '3+ ', '17+', '17+'],
|
||||
['5+ ', '30x ', '30x ', '15x ', '16+', '16+'],
|
||||
['6# ', '10x ', '10x ', '15x ', '15x', '16+'],
|
||||
['3/ ', '3/ ', '10x ', '1- ', '1- ', '16+'],
|
||||
])
|
||||
|
||||
# Alternatively construct a Game object more explicitly:
|
||||
# game = Game(grid_size=6,
|
||||
# blocks=[
|
||||
# Block(boxes=['A6', 'B6', 'C6', 'D6'], operation=OP_MULTIPLY, result=120),
|
||||
# Block(boxes=['E6', 'E5', 'E4', 'F4'], operation=OP_PLUS, result=17),
|
||||
# Block(boxes=['F6', 'F5'], operation=OP_PLUS, result=5),
|
||||
# Block(boxes=['A5', 'B5'], operation=OP_MINUS, result=1),
|
||||
# Block(boxes=['C5', 'C4'], operation=OP_DIVIDE, result=2),
|
||||
# Block(boxes=['D5', 'D4'], operation=OP_PLUS, result=3),
|
||||
# Block(boxes=['A4', 'A3'], operation=OP_PLUS, result=5),
|
||||
# Block(boxes=['B4', 'B3', 'C3'], operation=OP_MULTIPLY, result=30),
|
||||
# Block(boxes=['D3', 'D2', 'E2'], operation=OP_MULTIPLY, result=15),
|
||||
# Block(boxes=['B2', 'C2', 'C1'], operation=OP_MULTIPLY, result=10),
|
||||
# Block(boxes=['A2'], operation=OP_NONE, result=6),
|
||||
# Block(boxes=['A1', 'B1'], operation=OP_DIVIDE, result=3),
|
||||
# Block(boxes=['D1', 'E1'], operation=OP_MINUS, result=1),
|
||||
# Block(boxes=['F1', 'F2', 'F3', 'E3'], operation=OP_PLUS, result=16),
|
||||
# ])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user