Commit bbbfc5be authored by Taddeüs Kroes's avatar Taddeüs Kroes

Manage group sizes per group instead of per block

parent 5efb10b4
...@@ -26,16 +26,15 @@ BOMB_POINTS = 5 ...@@ -26,16 +26,15 @@ BOMB_POINTS = 5
class State: class State:
def __init__(self, blocks, exa, held, colskip, busy, moves, groups, groupsizes, maxgroup): def __init__(self, blocks, exa, held, colskip, busy, moves, blockgroups, groups):
self.blocks = blocks self.blocks = blocks
self.exa = exa self.exa = exa
self.held = held self.held = held
self.colskip = colskip self.colskip = colskip
self.busy = busy self.busy = busy
self.moves = moves self.moves = moves
self.blockgroups = blockgroups
self.groups = groups self.groups = groups
self.groupsizes = groupsizes
self.maxgroup = maxgroup
self.nrows = len(blocks) // COLUMNS self.nrows = len(blocks) // COLUMNS
@classmethod @classmethod
...@@ -45,9 +44,9 @@ class State: ...@@ -45,9 +44,9 @@ class State:
held = detect_held(board, exa) held = detect_held(board, exa)
colskip = get_colskip(blocks) colskip = get_colskip(blocks)
busy = get_busy(blocks, colskip) busy = get_busy(blocks, colskip)
groups, groupsizes, maxgroup = get_groups(blocks) blockgroups, groups = get_groups(blocks)
return cls(bytearray(blocks), exa, held, bytearray(colskip), busy, (), return cls(bytearray(blocks), exa, held, bytearray(colskip), busy, (),
bytearray(groups), bytearray(groupsizes), maxgroup) bytearray(blockgroups), groups)
def copy(self, deep): def copy(self, deep):
mcopy = copy if deep else lambda x: x mcopy = copy if deep else lambda x: x
...@@ -57,9 +56,8 @@ class State: ...@@ -57,9 +56,8 @@ class State:
mcopy(self.colskip), mcopy(self.colskip),
self.busy, self.busy,
self.moves, self.moves,
mcopy(self.groups), mcopy(self.blockgroups),
mcopy(self.groupsizes), mcopy(self.groups))
self.maxgroup)
def colbusy(self, col): def colbusy(self, col):
return (self.busy >> col) & 1 return (self.busy >> col) & 1
...@@ -93,13 +91,13 @@ class State: ...@@ -93,13 +91,13 @@ class State:
return score return score
def locked(self, i): def locked(self, i):
block = self.blocks[i] size, block = self.groups[self.blockgroups[i]]
if block == NOBLOCK: if block == NOBLOCK:
return False return False
if is_basic(block): if is_basic(block):
return self.groupsizes[i] >= MIN_BASIC_GROUP_SIZE return size >= MIN_BASIC_GROUP_SIZE
assert is_bomb(block) assert is_bomb(block)
return self.groupsizes[i] >= MIN_BOMB_GROUP_SIZE return size >= MIN_BOMB_GROUP_SIZE
def move(self, *moves): def move(self, *moves):
deep = any(move in (GRAB, DROP, SWAP) for move in moves) deep = any(move in (GRAB, DROP, SWAP) for move in moves)
...@@ -165,15 +163,14 @@ class State: ...@@ -165,15 +163,14 @@ class State:
def ungroup(self, i, visited): def ungroup(self, i, visited):
assert self.blocks[i] == NOBLOCK assert self.blocks[i] == NOBLOCK
oldid = self.groups[i] oldid = self.blockgroups[i]
self.blockgroups[i] = 0
self.groups[oldid] = 0, NOBLOCK
for nb in neighbors(i, self.blocks): for nb in neighbors(i, self.blocks):
if self.groups[nb] == oldid: if self.blockgroups[nb] == oldid:
self.create_group(nb, visited) self.create_group(nb, visited)
self.groups[i] = 0
self.groupsizes[i] = 0
def place(self, i, block): def place(self, i, block):
assert block != NOBLOCK assert block != NOBLOCK
assert self.blocks[i] == NOBLOCK assert self.blocks[i] == NOBLOCK
...@@ -192,10 +189,10 @@ class State: ...@@ -192,10 +189,10 @@ class State:
block = self.blocks[start] block = self.blocks[start]
group = tuple(scan(start)) group = tuple(scan(start))
if group: if group:
self.maxgroup = newid = self.maxgroup + 1 newid = len(self.groups)
self.groups.append((len(group), block))
for j in group: for j in group:
self.groups[j] = newid self.blockgroups[j] = newid
self.groupsizes[j] = len(group)
def fragmentation(self): def fragmentation(self):
""" """
...@@ -207,9 +204,9 @@ class State: ...@@ -207,9 +204,9 @@ class State:
yi, xi = divmod(i, COLUMNS) yi, xi = divmod(i, COLUMNS)
yj, xj = divmod(j, COLUMNS) yj, xj = divmod(j, COLUMNS)
# for blocks in the same group, only count vertical distance so # for blocks in the same group, only count vertical distance so that
# that groups are spread out horizontally # groups are spread out horizontally
if self.groups[i] == self.groups[j]: if self.blockgroups[i] == self.blockgroups[j]:
return abs(yj - yi) return abs(yj - yi)
return abs(xj - xi) + abs(yj - yi) * 2 - 1 + \ return abs(xj - xi) + abs(yj - yi) * 2 - 1 + \
...@@ -224,20 +221,10 @@ class State: ...@@ -224,20 +221,10 @@ class State:
for blocks in colors.values() for blocks in colors.values()
for i, j in combinations(blocks, 2)) for i, j in combinations(blocks, 2))
def group_leaders(self):
seen = set()
for i, groupid in enumerate(self.groups):
if groupid > 0 and groupid not in seen:
seen.add(groupid)
yield i
def points(self): def points(self):
points = 0 points = 0
for leader in self.group_leaders(): for size, block in self.groups:
block = self.blocks[leader]
size = self.groupsizes[leader]
if is_basic(block) and size >= MIN_BASIC_GROUP_SIZE: if is_basic(block) and size >= MIN_BASIC_GROUP_SIZE:
points += size points += size
elif is_bomb(block) and size >= MIN_BOMB_GROUP_SIZE: elif is_bomb(block) and size >= MIN_BOMB_GROUP_SIZE:
...@@ -367,12 +354,14 @@ class State: ...@@ -367,12 +354,14 @@ class State:
return cls.points, cls.fragmentation, cls.holes, cls.nmoves return cls.points, cls.fragmentation, cls.holes, cls.nmoves
def print_groupsizes(self): def print_groupsizes(self):
for start in range(len(self.groupsizes) - COLUMNS, -1, -COLUMNS): for start in range(len(self.blockgroups) - COLUMNS, -1, -COLUMNS):
print(' '.join('%-2d' % g for g in self.groupsizes[start:start + COLUMNS])) print(' '.join('%-2d' % self.groups[g][0]
for g in self.blockgroups[start:start + COLUMNS]))
def print_groups(self): def print_groups(self):
for start in range(len(self.groups) - COLUMNS, -1, -COLUMNS): for start in range(len(self.blockgroups) - COLUMNS, -1, -COLUMNS):
print(' '.join('%-2d' % g for g in self.groups[start:start + COLUMNS])) print(' '.join('%-2d' % g
for g in self.blockgroups[start:start + COLUMNS]))
def print(self): def print(self):
print_board(self.blocks, self.exa, self.held) print_board(self.blocks, self.exa, self.held)
...@@ -430,20 +419,19 @@ def scan_group(blocks, i, block, visited): ...@@ -430,20 +419,19 @@ def scan_group(blocks, i, block, visited):
def get_groups(blocks): def get_groups(blocks):
groupid = 0 blockgroups = [0] * len(blocks)
groups = [0] * len(blocks) groups = [(0, NOBLOCK)]
groupsizes = [0] * len(blocks)
visited = set() visited = set()
for i, block in enumerate(blocks): for i, block in enumerate(blocks):
if block != NOBLOCK and i not in visited: if block != NOBLOCK and i not in visited:
groupid += 1 groupid = len(groups)
group = tuple(scan_group(blocks, i, block, visited)) group = tuple(scan_group(blocks, i, block, visited))
groups.append((len(group), block))
for j in group: for j in group:
groups[j] = groupid blockgroups[j] = groupid
groupsizes[j] = len(group)
return groups, groupsizes, groupid return blockgroups, groups
def neighbors(i, blocks): def neighbors(i, blocks):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment