How to resolve the algorithm Nonogram solver step by step in the Wren programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Nonogram solver step by step in the Wren programming language

Table of Contents

Problem Statement

A nonogram is a puzzle that provides numeric clues used to fill in a grid of cells, establishing for each cell whether it is filled or not. The puzzle solution is typically a picture of some kind. Each row and column of a rectangular grid is annotated with the lengths of its distinct runs of occupied cells. Using only these lengths you should find one valid configuration of empty and occupied cells, or show a failure message. The problem above could be represented by two lists of lists: A more compact representation of the same problem uses strings, where the letters represent the numbers, A=1, B=2, etc: For this task, try to solve the 4 problems below, read from a “nonogram_problems.txt” file that has this content (the blank lines are separators): Extra credit: generate nonograms with unique solutions, of desired height and width.

This task is the problem n.98 of the "99 Prolog Problems" (archived) by Werner Hett (also thanks to Paul Singleton for the idea and the examples).

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Nonogram solver step by step in the Wren programming language

Source code in the wren programming language

import "/pattern" for Pattern
import "/math" for Nums, Boolean
import "/fmt" for Conv

var p = Pattern.new("/s")

var genSequence // recursive
genSequence = Fn.new { |ones, numZeros|
    if (ones.isEmpty) return ["0" * numZeros]
    var result = []
    var x = 1
    while (x < numZeros - ones.count + 2) {
        var skipOne = ones.skip(1).toList
        for (tail in genSequence.call(skipOne, numZeros - x)) {
            result.add("0" * x + ones[0] + tail)
        }
        x = x + 1
    }
    return result
}

/* If all the candidates for a row have a value in common for a certain cell,
    then it's the only possible outcome, and all the candidates from the
    corresponding column need to have that value for that cell too. The ones
    that don't, are removed. The same for all columns. It goes back and forth,
    until no more candidates can be removed or a list is empty (failure).
*/
var reduce =  Fn.new { |a, b|
    var countRemoved = 0
    for (i in 0...a.count) {
        var commonOn  = List.filled(b.count, true)
        var commonOff = List.filled(b.count, false)

        // determine which values all candidates of a[i] have in common
        for (candidate in a[i]) {
            for (i in 0...b.count) {
                commonOn[i]  = Boolean.and(commonOn[i], candidate[i])
                commonOff[i] = Boolean.or(commonOff[i], candidate[i])
            }
        }

        // remove from b[j] all candidates that don't share the forced values
        for (j in 0...b.count) {
            var fi = i
            var fj = j
            var removals = false
            b[j].each { |cnd|
                if ((commonOn[fj] && !cnd[fi]) || (!commonOff[fj] && cnd[fi])) {
                    b[j].remove(cnd)
                    removals = true
                }
            }
            if (removals) countRemoved = countRemoved + 1
            if (b[j].isEmpty) return -1
        }
    }
    return countRemoved
}

var reduceMutual = Fn.new { |cols, rows|
    var countRemoved1 = reduce.call(cols, rows)
    if (countRemoved1 == -1) return -1
    var countRemoved2 = reduce.call(rows, cols)
    if (countRemoved2 == -1) return -1
    return countRemoved1 + countRemoved2
}

// collect all possible solutions for the given clues
var getCandidates = Fn.new { |data, len|
    var result = []
    for (s in data) {
        var lst = []
        var a = s.bytes
        var sumChars = Nums.sum(a.map { |b| b - 64 })
        var prep = a.map { |b| "1" * (b - 64) }.toList

        for (r in genSequence.call(prep, len - sumChars + 1)) {
            var bits = r[1..-1].bytes
            var len = bits.count
            if (len % 64 != 0) len = (len/64).ceil * 64
            var bitset = List.filled(len, false)
            for (i in 0...bits.count.min(bitset.count)) bitset[i] = bits[i] == 49
            lst.add(bitset)
        }
        result.add(lst)
    }
    return result
}

var newPuzzle = Fn.new { |data|
    var rowData = p.splitAll(data[0])
    var colData = p.splitAll(data[1])
    var rows = getCandidates.call(rowData, colData.count)
    var cols = getCandidates.call(colData, rowData.count)

    while (true) {
        var numChanged = reduceMutual.call(cols, rows)
        if (numChanged == -1) {
            System.print("No solution")
            return
        }
        if (numChanged <= 0) break
    }

    for (row in rows) {
        for (i in 0...cols.count) {
            System.write(row[0][i] ? "# " : ". ")
        }
        System.print()
    }
    System.print()
}

var p1 = ["C BA CB BB F AE F A B", "AB CA AE GA E C D C"]

var p2 = [
    "F CAC ACAC CN AAA AABB EBB EAA ECCC HCCC",
    "D D AE CD AE A DA BBB CC AAB BAA AAB DA AAB AAA BAB AAA CD BBA DA"
]

var p3 = [
    "CA BDA ACC BD CCAC CBBAC BBBBB BAABAA ABAD AABB BBH " +
    "BBBD ABBAAA CCEA AACAAB BCACC ACBH DCH ADBE ADBB DBE ECE DAA DB CC",
    "BC CAC CBAB BDD CDBDE BEBDF ADCDFA DCCFB DBCFC ABDBA BBF AAF BADB DBF " +
    "AAAAD BDG CEF CBDB BBB FC"
]

var p4 = [
    "E BCB BEA BH BEK AABAF ABAC BAA BFB OD JH BADCF Q Q R AN AAN EI H G",
    "E CB BAB AAA AAA AC BB ACC ACCA AGB AIA AJ AJ " +
    "ACE AH BAF CAG DAG FAH FJ GJ ADK ABK BL CM"
]

for (puzzleData in [p1, p2, p3, p4]) newPuzzle.call(puzzleData)

  

You may also check:How to resolve the algorithm Equal prime and composite sums step by step in the Go programming language
You may also check:How to resolve the algorithm Old Russian measure of length step by step in the Wren programming language
You may also check:How to resolve the algorithm Hamming numbers step by step in the Rust programming language
You may also check:How to resolve the algorithm Brazilian numbers step by step in the REXX programming language
You may also check:How to resolve the algorithm Variadic function step by step in the Batch File programming language