|
| 1 | +#!/bin/env python |
| 2 | +# coding=utf-8 |
| 3 | +# http://kohsamui:thailand@www.pythonchallenge.com/pc/rock/arecibo.html |
| 4 | + |
| 5 | +import requests |
| 6 | +from PIL import Image, ImageDraw |
| 7 | + |
| 8 | +PREFIX = "http://kohsamui:thailand@www.pythonchallenge.com/pc/rock/" |
| 9 | +url = PREFIX + 'warmup.txt' |
| 10 | + |
| 11 | + |
| 12 | +def parse_data(data): |
| 13 | + lines = iter(data.splitlines()) |
| 14 | + width, height = 0, 0 |
| 15 | + rows, cols = [], [] |
| 16 | + for line in lines: |
| 17 | + if line.startswith("#"): |
| 18 | + continue |
| 19 | + if line.strip() == "": |
| 20 | + break |
| 21 | + if width == 0: |
| 22 | + width, height = map(int, line.split()) |
| 23 | + else: |
| 24 | + rows.append(list(map(int, line.split()))) |
| 25 | + for line in lines: |
| 26 | + if line.strip() == "": |
| 27 | + continue |
| 28 | + cols.append(list(map(int, line.split()))) |
| 29 | + return width, height, rows, cols |
| 30 | + |
| 31 | + |
| 32 | +def solve_nonogram(width, height, rows, cols): |
| 33 | + grid = [[0] * width for _ in range(height)] |
| 34 | + |
| 35 | + def is_valid_row(row, hints): |
| 36 | + current = [] |
| 37 | + count = 0 |
| 38 | + for cell in row: |
| 39 | + if cell == 1: |
| 40 | + count += 1 |
| 41 | + elif count > 0: |
| 42 | + current.append(count) |
| 43 | + count = 0 |
| 44 | + if count > 0: |
| 45 | + current.append(count) |
| 46 | + return current == hints |
| 47 | + |
| 48 | + def backtrack(y): |
| 49 | + if y == height: |
| 50 | + for x in range(width): |
| 51 | + column = [grid[y][x] for y in range(height)] |
| 52 | + if not is_valid_row(column, cols[x]): |
| 53 | + return False |
| 54 | + return True |
| 55 | + row_hint = rows[y] |
| 56 | + for candidate in generate_candidates(width, row_hint): |
| 57 | + grid[y] = candidate |
| 58 | + if backtrack(y + 1): |
| 59 | + return True |
| 60 | + return False |
| 61 | + |
| 62 | + backtrack(0) |
| 63 | + return grid |
| 64 | + |
| 65 | + |
| 66 | +def generate_candidates(width, hint): |
| 67 | + from itertools import combinations |
| 68 | + blocks = len(hint) |
| 69 | + total = sum(hint) + blocks - 1 |
| 70 | + if total > width: |
| 71 | + return [] |
| 72 | + positions = width - total |
| 73 | + gaps = [0] + [1] * (blocks - 1) + [0] |
| 74 | + for combo in combinations(range(positions + len(gaps)), len(gaps)): |
| 75 | + gaps_sizes = [combo[i] - combo[i - 1] for i in range(1, len(combo))] |
| 76 | + if any(s < 0 for s in gaps_sizes): |
| 77 | + continue |
| 78 | + row = [] |
| 79 | + for i in range(blocks): |
| 80 | + row += [0] * gaps_sizes[i] |
| 81 | + row += [1] * hint[i] |
| 82 | + if i < blocks - 1: |
| 83 | + row += [0] * 1 |
| 84 | + row += [0] * (width - len(row)) |
| 85 | + yield row |
| 86 | + |
| 87 | + |
| 88 | +def solve(width, height, rows, cols): |
| 89 | + solution = solve_nonogram(width, height, rows, cols) |
| 90 | + img = Image.new("RGB", (width * 10, height * 10), "white") |
| 91 | + draw = ImageDraw.Draw(img) |
| 92 | + for y in range(height): |
| 93 | + for x in range(width): |
| 94 | + if solution[y][x] == 1: |
| 95 | + draw.rectangle([x * 10, y * 10, (x + 1) * 10, (y + 1) * 10], fill="black") |
| 96 | + img.show() |
| 97 | + return "" |
| 98 | + |
| 99 | + |
| 100 | +if __name__ == "__main__": |
| 101 | + r = requests.get(url) |
| 102 | + something = r.text |
| 103 | + width, height, rows, cols = parse_data(something) |
| 104 | + answer = solve(width, height, rows, cols) |
| 105 | + # http://kohsamui:thailand@www.pythonchallenge.com/pc/rock/arrow.html |
0 commit comments