Skip to content

Commit

Permalink
First version of Donimo Drivers for #171.
Browse files Browse the repository at this point in the history
  • Loading branch information
donkirkby committed Nov 13, 2021
1 parent dec1126 commit c7a3fa4
Show file tree
Hide file tree
Showing 6 changed files with 810 additions and 32 deletions.
56 changes: 31 additions & 25 deletions bees.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,36 @@ def has_touching_blanks(self):
return False


def count_gaps(positions: typing.Set[typing.Tuple[int, int]],
width: int,
height: int):
unvisited = set(positions)
max_gap = width + height
old_total = max_gap * len(unvisited)
grouped = set()
grouped.add(unvisited.pop())
while True:
total_gaps = 0
while unvisited:
x1, y1 = unvisited.pop()
min_gap = width + height
for x2, y2 in grouped:
gap = abs(x1 - x2) + abs(y1 - y2) - 1
if gap == 0:
break
elif gap < min_gap:
min_gap = gap
else:
total_gaps += min_gap
continue
grouped.add((x1, y1))
if total_gaps == 0 or total_gaps == old_total:
break
old_total = total_gaps
unvisited = positions - grouped
return total_gaps


class BeesGraph(BoardGraph):
def __init__(self,
board_class=BeesBoard,
Expand Down Expand Up @@ -290,31 +320,7 @@ def extend_positions(self, positions: typing.List[typing.Tuple[int, int]], board

def check_progress(self, board: BeesBoard) -> int:
""" See how close a board is to a solution. """
unvisited = set(board.dice_set.dice)
max_gap = board.width + board.height
old_total = max_gap * len(unvisited)
grouped = set()
grouped.add(unvisited.pop())
while True:
total_gaps = 0
while unvisited:
x1, y1 = unvisited.pop()
min_gap = board.width + board.height
for x2, y2 in grouped:
gap = abs(x1-x2) + abs(y1-y2) - 1
if gap == 0:
break
elif gap < min_gap:
min_gap = gap
else:
total_gaps += min_gap
continue
grouped.add((x1, y1))
if total_gaps == 0 or total_gaps == old_total:
break
old_total = total_gaps
unvisited = set(board.dice_set.dice) - grouped
return total_gaps
return count_gaps(set(board.dice_set.dice), board.width, board.height)


def parse_args():
Expand Down
22 changes: 16 additions & 6 deletions domino_puzzle.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,31 +99,35 @@ def check_markers(self, pips_or_marker: str, x: int, y: int) -> str:


class DiceSet:
def __init__(self, dice_text: str = ''):
def __init__(self, dice_text: str = '', border: int = 0):
self.dice = {} # {(x, y): pips}
for match in re.finditer(r'\((\d+),(\d+)\)(\d+)', dice_text):
row = int(match.group(1))
column = int(match.group(2))
die_pips = int(match.group(3))
self.dice[row, column] = die_pips
self.dice[row+border, column+border] = die_pips

def __repr__(self):
return f'DiceSet({self.text!r})'

@property
def text(self):
return self.crop_text(0, 0)

def crop_text(self, left_border: int, top_border: int):
sorted_dice = sorted(self.dice.items(), key=itemgetter(1))
return ','.join(f'({x},{y}){die_pips}'
return ','.join(f'({x-left_border},{y-top_border}){die_pips}'
for (x, y), die_pips in sorted_dice)

def items(self):
return self.dice.items()

def move(self, *positions) -> str:
def move(self, *positions, show_length=True) -> str:
""" Move a die through a list of positions.
:param positions: ((x, y), ...) the starting position of the die,
followed by one or more positions for it to turn on or stop at.
:param show_length: True if move lengths are included in text
:return: a description of the move described by the positions
"""
move_parts = []
Expand All @@ -143,6 +147,8 @@ def move(self, *positions) -> str:
move_part = f'U{dy}'
else:
move_part = f'D{-dy}'
if not show_length:
move_part = move_part[0]
if i == 1:
move_part = f'{pips}{move_part}'
if i == move_count - 1:
Expand All @@ -156,6 +162,9 @@ def __getitem__(self, coordinates):
x, y = coordinates
return self.dice.get((x, y))

def __contains__(self, coordinates):
return coordinates in self.dice


class ArrowSet:
directions = dict(r=(1, 0),
Expand Down Expand Up @@ -194,7 +203,7 @@ def create(cls, state, border=0, max_pips=None):
for line in sections[1].splitlines():
if line.startswith('dice:'):
dice_text = line[5:].rstrip()
dice_set = DiceSet(dice_text)
dice_set = DiceSet(dice_text, border)
elif line.startswith('arrows:'):
arrows_text = line[7:].rstrip()
arrows = ArrowSet(arrows_text)
Expand Down Expand Up @@ -473,7 +482,8 @@ def display(self, cropped=False, cropping_bounds=None):
marker_display += f'{name}{pips}'
main_display = f'{main_display}---\n{marker_display}\n'
if self.dice_set:
main_display = f'{main_display}---\ndice:{self.dice_set.text}\n'
dice_text = self.dice_set.crop_text(xmin, ymin)
main_display = f'{main_display}---\ndice:{dice_text}\n'

return main_display

Expand Down
Loading

0 comments on commit c7a3fa4

Please sign in to comment.