def heuristic(node: Grid): score = 0 num_empty_cells = len(node.getAvailableCells()) for i in range(node.size): for j in range(node.size): val = node.getCellValue((i, j)) score += val * 10 if val else ( 1000 / num_empty_cells ) # reward empty spaces more if they are scarce val_up = node.getCellValue((i - 1, j)) val_dn = node.getCellValue((i + 1, j)) val_lt = node.getCellValue((i, j - 1)) val_rt = node.getCellValue((i, j + 1)) if val_up is not None and \ val_dn is not None and \ val != 0: if not (val_up <= val <= val_dn or val_up >= val >= val_dn): score -= 75 * (abs(val_up - val) + abs(val_dn - val)) if val_lt is not None and \ val_rt is not None and \ val != 0: if not (val_lt <= val <= val_rt or val_lt >= val >= val_rt): score -= 75 * (abs(val_lt - val) + abs(val_rt - val)) if j == 0: row = node.map[i] monotonic_row = all(x <= y for x, y in zip(row, row[1:])) monotonic_row = monotonic_row or all( x >= y for x, y in zip(row, row[1:])) if monotonic_row: score += 200 * sum(row) # big bonus if i == 0: col = [node.map[pos][j] for pos in range(node.size)] monotonic_col = all(x <= y for x, y in zip(col, col[1:])) monotonic_col = monotonic_col or all( x >= y for x, y in zip(col, col[1:])) if monotonic_col: score += 200 * sum(col) # big bonus val_order = PlayerAI.get_value_order(val) if val_order > 0: val_up_order = PlayerAI.get_value_order(val_up) val_dn_order = PlayerAI.get_value_order(val_dn) val_lt_order = PlayerAI.get_value_order(val_lt) val_rt_order = PlayerAI.get_value_order(val_rt) if val_up_order > 0: score -= abs(val_up_order - val_order) * 25 if val_dn_order > 0: score -= abs(val_dn_order - val_order) * 25 if val_lt_order > 0: score -= abs(val_lt_order - val_order) * 25 if val_rt_order > 0: score -= abs(val_rt_order - val_order) * 25 return score
def not_zero(g: Grid, x, y): return g.getCellValue((x, y)) != 0.0
def test_can_create_grid_to_design(self): sut = Grid() self.assertIsNotNone(sut) self.assertEqual(4, sut.size) sut.setCellValue((0, 0), 2) self.assertEqual(sut.getCellValue((0, 0)), 2)