Решить 0h n0 доску

19

0h n0 - очень простая и приятная игра, немного похожая на судоку или тральщика.

Правила игры

(Я рекомендую использовать учебник в игре, если вы можете, это очень просто и полезно)

Головоломка начинается с n * nдоски, содержащей несколько фиксированных фигур и несколько пустых ячеек, и решатель должен найти способ заполнить пустые ячейки фигурами и выполнить все ограничения, налагаемые фиксированными фигурами. Вот типы частей, которые мы будем использовать с сокращением:

  • # Красная часть (блокирует вид синей части)
  • O Синий кусок
  • . Пустое место
  • numberПронумерованная синяя фигура ( numberэто однозначное число> 0)

Все пронумерованные фигуры должны видеть то же количество синих фигур, что и число. Например:

#1O#O
...O.

1Часть может видеть только один другой синий кусок.

Как части видят друг друга

Две синие фигуры могут видеть друг друга, если они находятся в одном ряду или столбце и между ними нет красной фигуры. Пример:

( Sэто место, которое Oможно увидеть, Xне увидеть)

   S
   S
X#SOSS
   #
   X

Каждый синий кусок должен видеть по крайней мере еще один синий кусок:

#O#

Не будет работать, но:

#OO

Или:

###

Работать.

Демо доска решить

.1..
..1.
....
22#2

Правый нижний 2 виден только над собой, поэтому он должен быть синим, а верхний правый - красным.

.1.#
..1O
...O
22#2

Поскольку 1он заполнен, мы можем окружить его красными кусочками.

.1##
.#1O
..#O
22#2

Верхний левый 1теперь может видеть только в одном направлении, поэтому мы можем заполнить его.

O1##
.#1O
..#O
22#2

Теперь о тех последних 2с. Мы можем положить 2 синих куска над ними.

O1##
.#1O
OO#O
22#2

Последний будет заполнен #

O1##
##1O
OO#O
22#2

вход

Ввод - это многострочная строка. Размер будет 9x9без запаздывания. Он имеет следующие типы частей:

  • . пустой
  • # Красный пресет, не может быть изменен
  • number Номер предустановки, не может быть изменен

(Обратите внимание, что синий никогда не будет на входе)

Выход

Вывод такой же, как и ввод, с пустым изменением (. ) заменяется либо красным, либо синим для решения доски, а числа заменяются синими фигурами ( O).

Примеры

(Обратите внимание, что для каждой головоломки возможно несколько решений, но вам нужно показать только одно из них)

Input:
........4
...3.1...
45...2.3.
..9......
1..6#44..
....4..5.
....4.36.
2.......6
1....4...

Output:
OOO###OOO
OOOO#O#OO
OOO#OO#OO
#OOOO#O##
O#OO#OOOO
O#OOOO#OO
#OOOO#OOO
OO#O#OOOO
O#OOOO#O#

Input:
..7..#...
#...8..11
2....5...
..5...48.
...#...4.
.5...6...
...1.2...
2.....6.8
.7..#....

Output:
OOOOO####
##OOOO#OO
O#OOOO###
OOO#OOOOO
OO##O##O#
#O##OOOOO
#O#O#O#OO
OO#OOOOOO
OOO###O#O

Input:
5.3..33..
...4...23
.6.6.34..
...3#....
....5..4.
.5....3..
7.98.6#.3
.5.6..2..
..6...2..

Output:
OOOOO####
##OOOO#OO
O#OOOO###
OOO#OOOOO
OO##O##O#
#O##OOOOO
#O#O#O#OO
OO#OOOOOO
OOO###O#O

Спасибо @PeterTaylor и @apsillers за всю их помощь в песочнице!

Дж Аткин
источник
Я сделал очень незначительное редактирование заголовка, потому что «an» звучит лучше, если следующее слово начинается с гласной - я не ожидаю, что не носители английского языка или даже носители языка будут беспокоиться об этом, но это грамматически.
кот

Ответы:

2

Haskell, 224 байта

Не полностью проверено, потому что это очень медленно (по крайней мере O(n*2^n^2)).

t=1<2
x!p|p<0=0|t=mod(div x$2^p)2
l#x=[[sum$map(p&)[-1,1,l+1,-l-1]|p<-[q..q+l]]|q<-[0,l..l*l],let i&v|x!i<1=0|t=x!(i+v)+(i+v)&v]
b%v|b<1=t|t=b==v
s b|l<-length b-1=[l#x|x<-[0..2^l^2],and.map and$zipWith(zipWith(%))b(l#x)]!!0

Объяснение:

Основная идея состоит в том, чтобы представить доску из Red, Blueкусочков в виде списка списков 0, 1, где список списков упакован в одно целое число для упрощения перечисления. Все такие целые числа для размера платы генерируются и преобразуются в форму с количеством соседей. Первая такая доска, которая является верным решением ввода, возвращается.

-- integer x at position p with out of bounds defined to be 0 (so no bounds checking)
(!) :: (Integral b, Integral r) => r -> b -> r
x ! p | p < 0     = 0 
      | otherwise = mod (div x (2^p)) 2


-- Sum of values from position p along vector v (x is implicit)
-- Note that a cartesian vector (x,y) in this representation is (l*x + y)
(&) :: (Integral a, Integral b) => b -> b -> a
p & v | x ! p == 0 = 0
      | otherwise  = x ! (p+v)  +  (p+v) & v


-- Value of board at position p (implicit x, l)
value :: Integral a => a -> a
value p = sum $ map (p&) [-1, 1, l+1, -l-1]


-- Integer to board, where l is length, x is input integer
(#) :: (Integral t, Integral a) => a -> t -> [[t]]
l # x = [[sum $ map (p&) [-1,1,l+1,-l-1] | p <- [q..q+l-1]] | q <- [0,l..l*l]]


-- Comparison operator, to see whether a solved board is a solution of the input
(%) :: (Num a, Ord a) => a -> a -> Bool
b % v | b == 0    = True
      | otherwise = b == v


-- Check one possible solution
check :: Integral a => [[a]] -> Int -> [[a]] -> Bool
check b l x = (and . (map and)) zipWith(zipWith (%)) b (l # x)

-- Solver
solve :: Integral t => [[t]] -> [[t]]
solve b = [l # x | x <- [0..2^l^2], check b l x]
  where
    l = length b

Та часть , которая, вероятно , может быть наиболее golfed является: and.map and$zipWith(zipWith(%)). В противном случае, я поймал несколько ошибок, которые добавляли длину и, вероятно, могли бы быть больше в гольфе.

Майкл Кляйн
источник