Solve first 70% problem 161.
This commit is contained in:
@@ -35,7 +35,7 @@ def euler_111():
|
|||||||
for p in get_permutations(base, 2):
|
for p in get_permutations(base, 2):
|
||||||
if is_prime(p):
|
if is_prime(p):
|
||||||
subresult += p
|
subresult += p
|
||||||
assert subresult > 0, "More than to permutations required to yield prime"
|
assert subresult > 0, "More than two permutations required to yield prime"
|
||||||
result += subresult
|
result += subresult
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
108
python/e161.py
Normal file
108
python/e161.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
from copy import copy
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
CACHE = {}
|
||||||
|
EMPTY = '⬛'
|
||||||
|
FIELDS = ['🔴', '🟠', '🟡', '🟢', '🔵', '🟣', '⚪', '🟤', '⭐']
|
||||||
|
|
||||||
|
|
||||||
|
# We use [row, col] indexing.
|
||||||
|
BLOCKS = [
|
||||||
|
((0, 0), (0, 1), (0, 2)), # dark blue
|
||||||
|
((0, 0), (1, 0), (2, 0)), # black
|
||||||
|
((0, 0), (0, 1), (1, 0)), # red
|
||||||
|
((0, 0), (0, 1), (1, 1)), # green
|
||||||
|
((0, 0), (1, 0), (1, 1)), # blue
|
||||||
|
((0, 0), (1, 0), (1, -1)), # orange
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Field:
|
||||||
|
|
||||||
|
def __init__(self, N_COLS, N_ROWS):
|
||||||
|
self.N_COLS = N_COLS
|
||||||
|
self.N_ROWS = N_ROWS
|
||||||
|
self.state = 0
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.state)
|
||||||
|
|
||||||
|
def get_first_empty(self) -> Optional[Tuple[int, int]]:
|
||||||
|
for row in range(self.N_ROWS):
|
||||||
|
for col in range(self.N_COLS):
|
||||||
|
if self.is_empty(row, col):
|
||||||
|
return (row, col)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def is_empty(self, row: int, col: int) -> bool:
|
||||||
|
index = row * self.N_COLS + col
|
||||||
|
result = not bool(self.state & (1 << index))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def set(self, row: int, col: int):
|
||||||
|
index = row * self.N_COLS + col
|
||||||
|
self.state |= (1 << index)
|
||||||
|
|
||||||
|
def __getitem__(self, row: int):
|
||||||
|
return [self.is_empty(row, col) for col in range(self.N_COLS)]
|
||||||
|
|
||||||
|
def print(self):
|
||||||
|
for row in range(self.N_ROWS):
|
||||||
|
row_str = ""
|
||||||
|
for col in range(self.N_COLS):
|
||||||
|
row_str += '⬛' if self.is_empty(row, col) else '⚪'
|
||||||
|
print(row_str)
|
||||||
|
|
||||||
|
|
||||||
|
def fits(field, block, coord):
|
||||||
|
N_ROWS = field.N_ROWS
|
||||||
|
N_COLS = field.N_COLS
|
||||||
|
|
||||||
|
for rel_coord in block:
|
||||||
|
abs_row = coord[0] + rel_coord[0]
|
||||||
|
abs_col = coord[1] + rel_coord[1]
|
||||||
|
|
||||||
|
if abs_row < 0 or abs_col < 0 or abs_row >= N_ROWS or abs_col >= N_COLS:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not field.is_empty(abs_row, abs_col):
|
||||||
|
return None
|
||||||
|
|
||||||
|
new_field = copy(field)
|
||||||
|
for rel_coord in block:
|
||||||
|
abs_row = coord[0] + rel_coord[0]
|
||||||
|
abs_col = coord[1] + rel_coord[1]
|
||||||
|
new_field.set(abs_row, abs_col)
|
||||||
|
|
||||||
|
return new_field
|
||||||
|
|
||||||
|
|
||||||
|
def count(field):
|
||||||
|
global CACHE
|
||||||
|
|
||||||
|
if hash(field) in CACHE:
|
||||||
|
return CACHE[hash(field)]
|
||||||
|
|
||||||
|
first_empty = field.get_first_empty()
|
||||||
|
if first_empty is None:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
result = 0
|
||||||
|
for block in BLOCKS:
|
||||||
|
if (new_field := fits(field, block, first_empty)) is not None:
|
||||||
|
result += count(new_field)
|
||||||
|
|
||||||
|
CACHE[hash(field)] = result
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def euler_161():
|
||||||
|
return count(Field(9, 12))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_161()
|
||||||
|
print("e161.py: " + str(solution))
|
||||||
|
assert(solution == 20574308184277971)
|
||||||
|
|
||||||
Reference in New Issue
Block a user