Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
First solution in Clear category for Wall Keeper by brownie57
from itertools import product
from copy import copy
def adjacent(n):
nums = [n, n + 5]
if n % 5 != 1:
nums.append(n - 1)
if n % 5 != 0:
nums.append(n + 1)
return nums
def reduce_to_the_bottom(on_panels, click):
for i in range(4):
for j in [x for x in on_panels if 5 * i + 1 <= x <= 5 * i + 5]:
on_panels.extend(adjacent(j + 5))
click.append(j + 5)
on_panels = list({x for x in on_panels if on_panels.count(x) % 2 == 1})
click = list({x for x in click if click.count(x) % 2 == 1})
return [x for x in on_panels if 21 <= x <= 25], click
def wall_keeper(on_panels):
bottom_line, click = reduce_to_the_bottom(on_panels, [])
for p in product(range(2), repeat=5):
if p == (0, 0, 0, 0, 0):
continue
top = [n for n, a in enumerate(p, 1) if a]
ans = copy(click)
panels = copy(bottom_line)
for t in top:
panels.extend(adjacent(t))
ans.append(t)
panels = list({x for x in panels if panels.count(x) % 2 == 1})
ans = list({x for x in ans if ans.count(x) % 2 == 1})
bottom, ans = reduce_to_the_bottom(panels, ans)
if not bottom:
return sorted(ans)
if __name__ == '__main__':
#These "asserts" using only for self-checking and not necessary for auto-testing
from itertools import chain
def checker(solution, on_panels):
answer = solution(on_panels)
wk_p = list((0, 1)[n in on_panels] for n in range(1, 26))
p = list(wk_p[n: n+5] for n in range(0, 25, 5))
for a in answer:
r, c = (a-1) // 5, (a-1) % 5
p[r][c] = 1 - p[r][c]
if r+1 < 5:
p[r+1][c] = 1 - p[r+1][c]
if r-1 > -1:
p[r-1][c] = 1 - p[r-1][c]
if c+1 < len(p[0]):
p[r][c+1] = 1 - p[r][c+1]
if c-1 > -1:
p[r][c-1] = 1 - p[r][c-1]
return sum(chain(*p)) == 0
assert checker(wall_keeper, [5, 7, 13, 14, 18]), 'basic'
assert checker(wall_keeper, list(range(1, 26))), 'all_lights'
Feb. 20, 2019