Nonogram solver: Difference between revisions
Content added Content deleted
m (Corrected a typo.) |
(Changed the way to initialize using an algorithm derived from that of Java/Kotlin/Go.) |
||
Line 2,130: | Line 2,130: | ||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
To generate the sequence, we use the Java algorithm modified to directly generate bit strings (as integers) rather than character strings. |
|||
<lang Nim>import bitops, |
<lang Nim>import bitops, math, sequtils, strutils |
||
type |
type |
||
Line 2,137: | Line 2,138: | ||
# Lengths of distinct runs of occupied cells. |
# Lengths of distinct runs of occupied cells. |
||
Lengths = seq[int] |
Lengths = seq[int] |
||
# Possibility, i.e. sequence of bits managed as an integer. |
|||
Possibility = int |
|||
# Possibilities described by tow masks and a list of integer values. |
# Possibilities described by tow masks and a list of integer values. |
||
Line 2,144: | Line 2,148: | ||
list: seq[int] # List of possibilities. |
list: seq[int] # List of possibilities. |
||
# Mapping of lists of lengths to lists of possible values. |
|||
Configs = Table[seq[int], seq[int]] |
|||
proc genSequence(ones: seq[int]; numZeroes: Natural): seq[Possibility] = |
|||
## Generate a sequence of possibilities. |
|||
if ones.len == 0: return @[0] |
|||
for x in 1..(numZeroes - ones.len + 1): |
|||
for tail in genSequence(ones[1..^1], numZeroes - x): |
|||
result.add (tail shl countSetBits(ones[0]) or ones[0]) shl x |
|||
func lengths(n: int): Lengths = |
|||
## Return the lengths corresponding to a possibility. |
|||
⚫ | |||
var count = 0 |
|||
while n != 0: |
|||
if (n and 1) != 0: |
|||
inc count |
|||
elif count != 0: |
|||
result.add count |
|||
count = 0 |
|||
n = n shr 1 |
|||
if count != 0: |
|||
result.add count |
|||
proc initPossibilities(lengthsList: openArray[Lengths]; length: Positive): seq[Possibilities] = |
|||
⚫ | |||
let initMask0 = 1 shl length - 1 |
|||
func initConfigs(n: int): Configs = |
|||
⚫ | |||
## Initialize a configs table. |
|||
let sumLengths = sum(lengths) |
|||
for val in 0..n: |
|||
let prep = lengths.mapIt(1 shl it - 1) |
|||
result.mgetOrPut(lengths(val), @[]).add val |
|||
let possList = genSequence(prep, length - sumLengths + 1).mapIt(it shr 1) |
|||
⚫ | |||
func updateUnset( |
func updateUnset(possList: var seq[Possibilities]; mask, rank: int) = |
||
## Update the lists of possibilities keeping only those |
## Update the lists of possibilities keeping only those |
||
## compatible with the mask (for bits not set only). |
## compatible with the mask (for bits not set only). |
||
var mask = mask |
var mask = mask |
||
for |
for poss in possList.mitems: |
||
if (mask and 1) == 0: |
if (mask and 1) == 0: |
||
for |
for i in countdown(poss.list.high, 0): |
||
if poss |
if poss.list[i].testBit(rank): |
||
# Bit is set, so the value is not compatible: remove it. |
# Bit is set, so the value is not compatible: remove it. |
||
poss |
poss.list.delete(i) |
||
mask = mask shr 1 |
mask = mask shr 1 |
||
func updateSet( |
func updateSet(possList: var seq[Possibilities]; mask, rank: int) = |
||
## Update the lists of possibilities keeping only those |
## Update the lists of possibilities keeping only those |
||
## compatible with the mask (for bits set only). |
## compatible with the mask (for bits set only). |
||
var mask = mask |
var mask = mask |
||
for |
for poss in possList.mitems: |
||
if (mask and 1) != 0: |
if (mask and 1) != 0: |
||
for |
for i in countdown(poss.list.high, 0): |
||
if not poss |
if not poss.list[i].testBit(rank): |
||
# Bit is not set, so the value is not compatible: remove it. |
# Bit is not set, so the value is not compatible: remove it. |
||
poss |
poss.list.delete(i) |
||
mask = mask shr 1 |
mask = mask shr 1 |
||
Line 2,228: | Line 2,227: | ||
## Solve nonogram defined by "rowLengths" and "colLengths". |
## Solve nonogram defined by "rowLengths" and "colLengths". |
||
⚫ | |||
# Build auxiliary tables. |
|||
rowPoss = initPossibilities(rowLengths, colLengths.len) |
|||
colPoss = initPossibilities(colLengths, rowLengths.len) |
|||
let rowConfs = initConfigs(rowmax) |
|||
let colConfs = initConfigs(colmax) |
|||
⚫ | |||
⚫ | |||
var rowPoss: seq[Possibilities] |
|||
⚫ | |||
⚫ | |||
var colPoss: seq[Possibilities] |
|||
for lengths in colLengths: |
|||
colPoss.add Possibilities(mask0: colmax, mask1: 0, list: colConfs[lengths]) |
|||
⚫ | |||
var hasChanged = true |
var hasChanged = true |
||
while hasChanged: |
while hasChanged: |
||
Line 2,258: | Line 2,247: | ||
var val = poss.list[0] |
var val = poss.list[0] |
||
for i in 0..colPoss.high: |
for i in 0..colPoss.high: |
||
line.add if ( |
line.add if val.testBit(i): "# " else: " " |
||
val = val shr 1 |
|||
echo line |
echo line |
||
Line 2,267: | Line 2,255: | ||
for elem in s.splitWhitespace(): |
for elem in s.splitWhitespace(): |
||
result.add elem.mapIt(ord(it) - ord('A') + 1) |
result.add elem.mapIt(ord(it) - ord('A') + 1) |
||
proc solve(rows, cols: string) = |
proc solve(rows, cols: string) = |