Skip to content
Snippets Groups Projects
Commit bbbfc5be authored by Taddeüs Kroes's avatar Taddeüs Kroes
Browse files

Manage group sizes per group instead of per block

parent 5efb10b4
No related branches found
No related tags found
No related merge requests found
...@@ -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):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment