Können Sie den britischen Geheimdienst schlagen? (Nonogram Solver)

20

Es ist Zeit, sich auf eine gefährliche Suche zu begeben, um den britischen Geheimdienst zu besiegen. Ziel dieser Herausforderung ist es, den kürzesten Code zu schreiben, der ein Nonogramm löst.

Was ist ein Nonogramm?

Nonogram Puzzle

Die Regeln sind einfach. Sie haben ein Quadratraster, das entweder schwarz ausgefüllt oder leer gelassen werden muss. Neben jeder Zeile des Rasters sind die Längen der schwarzen Quadrate in dieser Zeile aufgeführt. Über jeder Spalte sind die Längen der schwarzen Quadrate in dieser Spalte aufgeführt. Ihr Ziel ist es, alle schwarzen Quadrate zu finden. In diesem Puzzletyp sind die Zahlen eine Form der diskreten Tomographie, die misst, wie viele ungebrochene Linien von ausgefüllten Quadraten sich in einer bestimmten Zeile oder Spalte befinden. Zum Beispiel würde ein Hinweis von "4 8 3" bedeuten, dass es Sätze von vier, acht und drei gefüllten Quadraten in dieser Reihenfolge gibt, wobei mindestens ein leeres Quadrat zwischen aufeinanderfolgenden Gruppen liegt. [ 1 ] [ 2 ]

Die Lösung für das obige Nonogramm wäre also:

Nichtogramm gelöst

Implementierungsdetails

Sie können das Nonogramm so darstellen, wie Sie möchten, und es als Eingabe verwenden, wie Sie es für Ihre Sprache für geeignet halten. Gleiches gilt für die Ausgabe. Das Ziel dieser Herausforderung ist es, den Job buchstäblich nur zu erledigen. Wenn Sie das Nonogramm mit der Ausgabe Ihres Programms lösen können, ist dies gültig. Eine Einschränkung ist, dass Sie keinen Online-Löser verwenden können :)

Dieses Problem ist algorithmisch sehr herausfordernd (np-complete), da es keine vollständig effiziente Lösung dafür gibt und Sie daher nicht dafür bestraft werden, dass Sie größere Probleme nicht lösen können, obwohl Ihre Antwort in diesem Fall sehr belohnt wird in der Lage, große Fälle zu behandeln (siehe Bonus). Als Benchmark funktioniert meine Lösung innerhalb von 5-10 Sekunden für bis zu 25x25. Um die Flexibilität zwischen verschiedenen Sprachen zu gewährleisten, sind Lösungen, die für ein 25x25-Nonogramm weniger als 5 Minuten dauern, ausreichend.

Sie können ein Puzzle in immer einem quadratischen NxN-Nonogramm annehmen.

Sie können diesen Online-Nonogram Puzzle Maker verwenden, um Ihre Lösungen zu testen.

Wertung

Selbstverständlich können Sie jede gewünschte Sprache verwenden. Da es sich um Codegolf handelt, werden die Einträge in der Reihenfolge sortiert: accuracy -> length of code -> speed.Lassen Sie sich jedoch nicht von Codegolf-Sprachen entmutigen. Antworten in allen Sprachen, die Golfversuche anzeigen auf interessante weise wird upvoted!

Bonus

Tatsächlich habe ich Nonogramme von einer kryptografischen Weihnachtskarte erfahren, die der britische Geheimdienst hier herausgebracht hat . Der erste Teil war im Grunde ein massives 25x25 Nonogramm. Wenn Ihre Lösung dies lösen kann, erhalten Sie ein großes Lob :)

Um Ihnen die Dateneingabe zu erleichtern, habe ich angegeben, wie ich die Daten für dieses spezielle Puzzle zur freien Verwendung dargestellt habe. Die ersten 25 Zeilen sind die Zeilenhinweise, gefolgt von einer '-' Trennlinie, gefolgt von 25 Zeilen der Spaltenhinweise, gefolgt von einer '#' Trennlinie und einer Darstellung des Gitters mit den ausgefüllten quadratischen Hinweisen.

7 3 1 1 7
1 1 2 2 1 1
1 3 1 3 1 1 3 1
1 3 1 1 6 1 3 1
1 3 1 5 2 1 3 1
1 1 2 1 1
7 1 1 1 1 1 7
3 3
1 2 3 1 1 3 1 1 2
1 1 3 2 1 1
4 1 4 2 1 2
1 1 1 1 1 4 1 3
2 1 1 1 2 5
3 2 2 6 3 1
1 9 1 1 2 1
2 1 2 2 3 1
3 1 1 1 1 5 1
1 2 2 5
7 1 2 1 1 1 3
1 1 2 1 2 2 1
1 3 1 4 5 1
1 3 1 3 10 2
1 3 1 1 6 6
1 1 2 1 1 2
7 2 1 2 5
-
7 2 1 1 7
1 1 2 2 1 1
1 3 1 3 1 3 1 3 1
1 3 1 1 5 1 3 1
1 3 1 1 4 1 3 1
1 1 1 2 1 1
7 1 1 1 1 1 7
1 1 3
2 1 2 1 8 2 1
2 2 1 2 1 1 1 2
1 7 3 2 1
1 2 3 1 1 1 1 1
4 1 1 2 6
3 3 1 1 1 3 1
1 2 5 2 2
2 2 1 1 1 1 1 2 1
1 3 3 2 1 8 1
6 2 1
7 1 4 1 1 3
1 1 1 1 4
1 3 1 3 7 1
1 3 1 1 1 2 1 1 4
1 3 1 4 3 3
1 1 2 2 2 6 1
7 1 3 2 1 1
#
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Und hier ist eine etwas andere Version für Ihre Bequemlichkeit; Ein durch Kommas getrenntes Tupel (Zeile, Spalte), in dem jedes Element eine Liste von Listen ist.

([[7, 3, 1, 1, 7],
  [1, 1, 2, 2, 1, 1],
  [1, 3, 1, 3, 1, 1, 3, 1],
  [1, 3, 1, 1, 6, 1, 3, 1],
  [1, 3, 1, 5, 2, 1, 3, 1],
  [1, 1, 2, 1, 1],
  [7, 1, 1, 1, 1, 1, 7],
  [3, 3],
  [1, 2, 3, 1, 1, 3, 1, 1, 2],
  [1, 1, 3, 2, 1, 1],
  [4, 1, 4, 2, 1, 2],
  [1, 1, 1, 1, 1, 4, 1, 3],
  [2, 1, 1, 1, 2, 5],
  [3, 2, 2, 6, 3, 1],
  [1, 9, 1, 1, 2, 1],
  [2, 1, 2, 2, 3, 1],
  [3, 1, 1, 1, 1, 5, 1],
  [1, 2, 2, 5],
  [7, 1, 2, 1, 1, 1, 3],
  [1, 1, 2, 1, 2, 2, 1],
  [1, 3, 1, 4, 5, 1],
  [1, 3, 1, 3, 10, 2],
  [1, 3, 1, 1, 6, 6],
  [1, 1, 2, 1, 1, 2],
  [7, 2, 1, 2, 5]],
 [[7, 2, 1, 1, 7],
  [1, 1, 2, 2, 1, 1],
  [1, 3, 1, 3, 1, 3, 1, 3, 1],
  [1, 3, 1, 1, 5, 1, 3, 1],
  [1, 3, 1, 1, 4, 1, 3, 1],
  [1, 1, 1, 2, 1, 1],
  [7, 1, 1, 1, 1, 1, 7],
  [1, 1, 3],
  [2, 1, 2, 1, 8, 2, 1],
  [2, 2, 1, 2, 1, 1, 1, 2],
  [1, 7, 3, 2, 1],
  [1, 2, 3, 1, 1, 1, 1, 1],
  [4, 1, 1, 2, 6],
  [3, 3, 1, 1, 1, 3, 1],
  [1, 2, 5, 2, 2],
  [2, 2, 1, 1, 1, 1, 1, 2, 1],
  [1, 3, 3, 2, 1, 8, 1],
  [6, 2, 1],
  [7, 1, 4, 1, 1, 3],
  [1, 1, 1, 1, 4],
  [1, 3, 1, 3, 7, 1],
  [1, 3, 1, 1, 1, 2, 1, 1, 4],
  [1, 3, 1, 4, 3, 3],
  [1, 1, 2, 2, 2, 6, 1],
  [7, 1, 3, 2, 1, 1]])
Gowrath
quelle
Leider ist meine Website nicht verfügbar, aber sie hatte früher einen recht schnellen Nonogram-Solver. 5-10 Minuten klingt übertrieben.
Neil
1
@dwana Sie müssen sich keine Sorgen über unlösbare Fälle machen. Was die zufällige Antwort betrifft, so haben Sie bei einem 25x25-Nonogramm 2 ^ 625 mögliche Konfigurationen. Im Kontext ist das mehr als die doppelte Anzahl von Atomen im bekannten Universum (dh, wenn Sie jedes Atom im Universum als Teil verwenden würden, hätten Sie immer noch nicht genug Platz, um die Möglichkeiten zu speichern). In Bezug auf die Zeit, wenn Sie eine Nanosekunde (großzügig)
benötigen
1
Ty zur Klärung unlösbarer Fälle. (+ Ich habe einen magischen PC, der eine Antwort in ~ 2.1546362E-186 Sekunden validiert)
Dwana
1
Ihre CSV enthält keine quadratischen Hinweise. Hier sind einige JS, um sie zu generieren:s=[].fill([].fill(0,0,25),0,25);s[3][3]=s[3][4]=s3[3][12]=s3[3][13]=s3[3][21]=s[8][6]=s[8][7]=s[8][10]=s[8][14]=s[8][15]=s[8][18]=s[16][6]=s[16][11]=s[16][16]=s[16][20]=s[21][3]=s[21][4]=s[21][9]=s[21][10]=s[21][15]=s[21][20]=s[21][21]=1;
Titus

Antworten:

5

Brachylog , 70 69 Bytes

[R:C]hlL~l:L:1f=.:3aR,.z:3aC,
tL,?he##ElL,E:2a
.<2,_1<
@b:4f:la
e.h1,

Dies nimmt eine Liste von zwei Listen (zuerst die Zeilenindikatoren, dann die Spaltenindikatoren). Jeder Indikator ist selbst eine Liste (für Situationen wie [3,1]in einer Zeile).

Diese Version benötigt ca. 3 Minuten, um das 5-mal-5-Beispiel der Herausforderung zu lösen.

Viel effizientere Version, 91 Bytes

[R:C]hlL~l:L:1f:Cz:3az:Rz:3a=.:4aR,.z:4aC,
tL,?he##ElL,E:2a
.<2,_1<
:+a#=,?h
@b:5f:la
e.h1,

Probieren Sie es online!

Dies ist keine vollständige rohe Gewalt: Der einzige Unterschied besteht darin, dass die Werte der Zellen durch diese Einschränkung so festgelegt werden, dass die Anzahl der Einsen in jeder Zeile und Spalte mit den als Indikatoren in der Eingabe angegebenen Zahlen übereinstimmt. Der einzige Brute-Force-Teil besteht dann darin, das eine Gitter mit den Einschränkungen zu finden, für die die "Blöcke" von 1s mit dem übereinstimmen, was als Indikation angegeben ist.

Dieser Vorgang dauert in dem 5 x 5-Beispiel der Herausforderung ungefähr 0,05 Sekunden. Dies ist für den Bonusfall immer noch viel zu langsam, da ich keine Ahnung habe, wie man die durch eine oder mehrere Nullen getrennten Einsenblöcke in Bezug auf Einschränkungen ausdrückt.

Erläuterung

Ich werde im Folgenden die 93-Byte-Version erklären. Der einzige Unterschied zwischen den beiden ist der Aufruf von Prädikat 3, der in der 70-Byte-Version nicht existiert, und die Nummerierung der Prädikate (da es eins weniger gibt).

  • Hauptprädikat:

    [R:C]     Input = [R, C]
    hlL       The length of R is L
    ~l        Create a list of length L
    :L:1f     Each element of that list is a sublist of length L with cells 0 or 1 (Pred 1)
              %%% Part unique to the 93 bytes version
    :Cz       Zip the rows of the list of lists with C
    :3a       The sum of 1s in each row is equal to the sum of the indicators (Pred 3)
    z         Transpose
    :Rz       Zip the columns of the list of lists with R
    :3a       The sum of 1s in each column is equal to the sum of the indicators (Pred 3)
              %%%
    =.        Assign values to the cells of the list of lists which satisfy the constraints
    :4aR,     The blocks of 1s must match the indicators on rows
    .z        Transpose
    :4aC,     The blocks of 1s must match the indicators on columns
    
  • Prädikat 1: Erzwingt, dass die Zeilen eine bestimmte Länge haben und dass jede Zelle 0 oder 1 ist.

    tL,       L is the length given as second element of the input
    ?he       Take an element from the list
    ##ElL,    That element E is itself a list of length L
    E:2a      The elements of E are 0s and 1s (Pred 2)
    
  • Prädikat 2: Beschränken Sie eine Variable auf 0 oder 1

    .<2,      Input = Output < 2
    _1<       Output > -1
    
  • Prädikat 3: Die Summe der Einsen in einer Liste muss gleich der Summe der Indikatoren sein (z. B. wenn der Indikator [3: 1] ist, muss die Liste die Summe 4 haben)

    :+a       Sum the elements of the list and sum the indicator
    #=,       Both sums must be equal
    ?h        Output is the list
    
  • Prädikat 4: Überprüfen Sie, ob die Einsenblöcke mit dem Indikator übereinstimmen

    @b        Split the list in blocks of the same value
    :5f       Find all blocks of 1s (Pred 5)
    :la       The list of lengths of the blocks results in the indicator (given as output)
    
  • Prädikat 5: Wahr für Einsenblöcke, sonst falsch

    e.        Output is an element of the input
      h1,     Its first value is 1
    
Tödlich
quelle
Fühlt sich wie das perfekte Werkzeug für den Job an. Freue mich auf die Erklärung.
Emigna
@Fatalize Das ist fantastisch, ich habe darauf gewartet, dass jemand eine prologartige Sprache verwendet, um dies zu tun. Haben Sie es mit dem 25x25 Fall versucht? Ich trat in die Daten für Sie bereits
gowrath
@gowrath Ich werde dies heute Nachmittag auf meinem Computer ausführen, wir werden sehen, was passiert.
Fatalize
@Fatalize Scheint eine Auszeit zu haben, aber ich kann es falsch machen. Ich würde mich auch nicht vollständig auf meine Dateneingabefähigkeiten verlassen: D
Gowrath
@gowrath Bei TIO tritt eine Zeitüberschreitung auf, ich werde sie jedoch im Offline-Interpreter direkt auf meinem Computer ausführen.
Fatalize
9

Haskell, 242 230 201 199 177 163 160 149 131 Bytes

import Data.Lists
m=map
a#b=[x|x<-m(chunk$length b).mapM id$[0,1]<$(a>>b),g x==a,g(transpose x)==b]
g=m$list[0]id.m sum.wordsBy(<1)

Schließlich unter 200 Bytes, schreiben Sie @Bergi gut. Vielen Dank an @nimi für die fast halbierte Größe.

Wow. Fast halb so groß, teilweise wegen mir, aber hauptsächlich wegen @nimi.

Die magische Funktion ist (#). Es werden alle Lösungen eines gegebenen Nonogramms gefunden.

Dies ist in der Lage, alle Fälle zu lösen, kann aber sehr langsam sein, da es um die Komplexität geht O(2^(len a * len b)). Ein schneller Benchmark ergab, dass 86 GB für ein 5 x 5-Nonogramm reserviert waren.

Unterhaltsame Tatsache: Es funktioniert für alle Nonogramme, nicht nur für quadratische.


Wie es funktioniert:

  • a#b: Erzeuge alle Gitter aus Listen mit ganzen Zahlen, die die Anzahl der Quadrate repräsentieren (map(chunk$length b).mapM id$a>>b>>[[0,1]] ) und filtern Sie die Ergebnisse, um nur die gültigen zu behalten.
  • g: Bei einem gegebenen potentiellen Nonogramm summiert es die Läufe von Einsen horizontal.
ThreeFx
quelle
Du meinst O (2 ^ (len a * len b)), nicht O ((len a * len b) ^ 2).
Anders Kaseorg
@AndersKaseorg Richtig. Behalte die Million, die ich versehentlich angedeutet habe. : D
ThreeFx
1
Noch ein paar Bytes: m(chunk$l b)undreplicate(l$a>>b)
Bergi
@ThreeFx 86GB: O ... Übrigens, kannst du kurz erklären, wie das kompiliert wird? Ich habe gerade erst angefangen, haskell zu lernen und das gibt Fehler mit ghc. Willst du es ausprobieren :)
Gowrath
1
import Data.Listsist genug, weil es sowohl Data.Listals auch wieder exportiert Data.List.Split.
Nimi
4

Pyth, 91 72 71 Bytes

D:GHdRq@@QdG.nCf.)TrH8V^,01^hQ2=TcNhQ=Y1VhQ=*Y*:H@TH1:H@CTH2)IYjbmjkdTb

Ein Programm, das eine Liste der Formulare eingibt, in der [size, [horizontal clues], [vertical clues]]jeder Hinweis eine Liste ganzer Zahlen ist (leere Hinweise sind die leere Liste []), und jede Lösung in Form eines binären Rasters mit den 1schattierten und0 ist nicht schattieren .

Das ist eine rohe Kraft, ungefähr so O(2^n^2). Bei größeren Puzzles dauert es sehr lange, löst aber bei ausreichender Zeit jede beliebige Größe.

Probieren Sie es online aus

Wie es funktioniert

Das Programm generiert jedes mögliche Layout, indem es das wiederholte kartesische Produkt [0, 1]mit einer Länge von gleich verwendet size^2. Dies wird dann in Blöcke aufgeteilt, wobei für jede horizontale Linie eine Liste erstellt wird. Jede Zeile ist lauflängencodiert, nach Vorhandensein gefiltert 1und abgeflacht, so dass der Hinweis für diese Zeile erhalten bleibt . Dies wird dann gegen die Eingabe geprüft. Der obige Vorgang wird für die Transponierung der Chunks wiederholt, wobei die vertikalen Linien überprüft werden. Bei einem Treffer wird jeder Block verkettet, und die verketteten Blöcke werden in Zeilenumbrüchen zusammengefügt und implizit mit einem nachgestellten Zeilenumbruch gedruckt.

D:GHdRq@@QdG.nCf.)TrH8V^,01^hQ2=TcNhQ=Y1VhQ=*Y*:H@TH1:H@CTH2)IYjbmjkdTb  Program. Input: Q
                            hQ                                           Q[0], size
                           ^  2                                          Square
                        ,01                                              [0, 1]
                       ^                                                 Cartesian product
                      V                                     )            For N in the Cartesian product:
                                 cNhQ                                    Split N into Q[0] chunks
                               =T                                        Assign that to T
                                     =Y1                                 Y=1
                                        VhQ                              For H in range [0, Q[0]-1]:
D:GHd                                                                     def :(G, H, d)
                   rH8                                                     Run-length-encode(H)
               f.)T                                                        Filter by presence of 1 in character part
            .nC                                                            Transpose and flatten, giving the clue
       @@QdG                                                               Q[d][G], the relevant input clue
     Rq                                                                    Return clue==input clue
                                               :H@TH1                     :(H, T, 1)
                                                     :H@CTH2              :(H, transpose(T), 2)
                                           =*Y*                           Y=Y*product of above two
                                                             IY           If Y:
                                                                 mjkdT     Conacatenate each element of T
                                                               jb          Join on newlines
                                                                      b    Add a newline and implicitly print

Danke an @ Pietu1998 für ein paar Tipps

TheBikingViking
quelle
Dies ist möglicherweise das längste Pyth-Programm, das ich je gesehen habe
Business Cat
=ZhZist gleich =hZund FNist gleich V.
PurkkaKoodari
@TheBikingViking Was genau meinst du mit genügend Zeit? Ich bin mir ziemlich sicher, dass dies ein 25x25 nicht lösen würde, wenn Sie es aus der Vorstellung des Universums heraus begonnen hätten.
Gowrath
1
@gowrath da bin ich mir auch ziemlich sicher! Ich bin neu in Pyth, und nach der Zeit, die ich dafür gebraucht habe, möchte ich nicht einmal darüber
nachdenken,
2

Javascript (ES6), 401 386 333 Bytes

Dies ist ein früher Versuch. Es ist nicht sehr effizient, aber ich war neugierig, eine Lösung mit regulären Ausdrücken für die binäre Darstellung der Zeilen und Spalten zu testen.

Beispielsweise wird der Hinweis [3,1]in den folgenden regulären Ausdruck übersetzt:

/^0*1{3}0+1{1}0*$/

Im Moment berücksichtigt diese Version keine viereckigen Hinweise. Ich werde dies wahrscheinlich später hinzufügen.

Code

(c,r)=>{W=c.length;w=[];S=0;M=(n,p)=>eval(`/^0*${p.map(v=>`1{${v}}`).join`0+`}0*$/`).exec(n);R=(y,i=0)=>S||(w[y]=r[y][i],y+1<W?R(y+1):c.every((c,y)=>(n=0,w.map((_,x)=>n+=w[W-1-x][y]),M(n,c)))&&(S=w.join`
`),r[y][i+1]&&R(y,i+1));r=r.map(r=>[...Array(1<<W)].map((_,n)=>((1<<30)|n).toString(2).slice(-W)).filter(n=>M(n,r)));return R(0)}

Ausgabe

Die Lösung wird im Binärformat angezeigt. Sowie:

00110
01110
11100
11101
00001

Prüfung

Dies ist ein einfacher Test für das Beispielgitter.

let f =
(c,r)=>{W=c.length;w=[];S=0;M=(n,p)=>eval(`/^0*${p.map(v=>`1{${v}}`).join`0+`}0*$/`).exec(n);R=(y,i=0)=>S||(w[y]=r[y][i],y+1<W?R(y+1):c.every((c,y)=>(n=0,w.map((_,x)=>n+=w[W-1-x][y]),M(n,c)))&&(S=w.join`
`),r[y][i+1]&&R(y,i+1));r=r.map(r=>[...Array(1<<W)].map((_,n)=>((1<<30)|n).toString(2).slice(-W)).filter(n=>M(n,r)));return R(0)}

console.log(f(
  [[2],[3],[4],[2],[2]],
  [[2],[3],[3],[3,1],[1]]
));

Arnauld
quelle
gute Idee. tötet jedoch meine Browser beim Weihnachtsrätsel.
Titus
2

Haskell, 109 Bytes

Haftungsausschluss: Dies ergibt sich aus der Antwort von @ ThreeFx . Ich habe ihm geholfen, seine Antwort aufzuschlüsseln, aber er scheint das Interesse verloren zu haben, meine letzten wesentlichen Verbesserungen einzubeziehen, also poste ich sie als neue Antwort.

import Data.List
n=mapM id
a#b=[x|x<-n$(n$" #"<$a)<$b,g x==a,g(transpose x)==b]
g=map$max[0].map length.words

Anwendungsbeispiel: [[2],[3],[3],[3,1],[1]] # [[2],[3],[4],[2],[2]] -> [[" ## "," ### ","### ","### #"," #"]].

Rohe Gewalt. Probieren Sie alle Kombinationen von und aus #, teilen Sie int-Stücke von #, zählen Sie die Längen und vergleichen Sie sie mit der Eingabe.

nimi
quelle
1

PHP, 751 833 (720) 753 724 726 710 691 680 682 Bytes

Ich wollte unbedingt ein spezielles Sequenzinkrement erstellen und meinen kartesischen Generator erneut testen.
aber ließ die kartesische zugunsten von Backtracking, um das große Rätsel schneller zu lösen.

$p=[];foreach($r as$y=>$h){for($d=[2-($n=count($h)+1)+$u=-array_sum($h)+$w=count($r)]+array_fill($i=0,$n,1),$d[$n-1]=0;$i<1;$d[0]+=$u-array_sum($d)){$o=$x=0;foreach($d as$i=>$v)for($x+=$v,$k=$h[$i];$k--;)$o+=1<<$x++;if(($s[$y]|$o)==$o){$p[$y][]=$o;$q[$y]++;}for($i=0;$i<$n-1&$d[$i]==($i?1:0);$i++);if(++$i<$n)for($d[$i]++;$i--;)$d[$i]=1;}}
function s($i,$m){global$c,$w,$p;for(;!$k&&$i[$m]--;$k=$k&$m<$w-1?s($i,$m+1):$k){for($k=1,$x=$w;$k&&$x--;){$h=$c[$x];for($v=$n=$z=$y=0;$k&&$y<=$m;$y++)$n=$n*($f=($p[$y][$i[$y]]>>$x&1)==$v)+$k=$f?:($v=!$v)||$n==$h[$z++];if($k&$v)$k=$n<=$h[$z];}}return$k?is_array($k)?$k:$i:0;}
foreach(s($q,0)as$y=>$o)echo strrev(sprintf("\n%0{$w}b",$p[$y][$o]));
  • erwartet Hinweise in Arrays $rfür Zeilenhinweise, $cfür Spaltenhinweise und$s für quadratische Hinweise.
  • wirft, invalid argument supplied for foreachwenn es keine Lösung findet.
  • Verwenden Sie ein physisches Byte, \nund entfernen Sie die anderen zwei Zeilenumbrüche , um die richtige Byte-Anzahl zu erhalten .

Beschreibung

1)
Generieren Sie aus Zeilenhinweisen mögliche Zeilen, die den quadratischen Hinweisen entsprechen,
und merken Sie sich deren Anzahl für jeden Zeilenindex.

2) Zurückverfolgen der Zeilenkombinationen:
Wenn die Kombination den Spaltenhinweisen entspricht, suchen Sie eine tiefere oder geben Sie eine erfolgreiche Kombination zurück.
andernfalls versuchen Sie die nächste Möglichkeit für diese Zeile

3) Drucklösung


Das letzte Golfen hatte schwerwiegende Auswirkungen auf die Leistung;
Ich habe jedoch die Profilzuweisungen für die endgültigen Benchmarks entfernt.

Ersetzen Sie $n=$n*($f=($p[$y][$i[$y]]>>$x&1)==$v)+$k=$f?:($v=!$v)||$n==$h[$z++];
mit if(($p[$y][$i[$y]]>>$x&1)-$v){$k=($v=!$v)||$n==$h[$z++];$n=1;}else$n++;
, um den letzten Golfschritt rückgängig zu machen.

Beispiele

Verwenden Sie für das kleine Beispiel ( 17 bis 21 um 12 8 7 6.7 5.3 ms)

$r=[[2],[3],[3],[3,1],[1]];$c=[[2],[3],[4],[2],[2]];$s=[0,0,0,0,0];

für das Weihnachtspuzzle:

  • habe meinen kleinen Heimserver mit der alten Lösung getötet
  • tötete den Browser mit Testausgaben
  • jetzt gelöst in 50 37,8 45,5 um 36 Sekunden

Füge die Daten aus der Frage in eine Datei ein christmas.nonogramund benutze diesen Code zum Importieren:

$t=r;foreach(file('christmas.nonogram')as$h)if('-'==$h=trim($h))$t=c;elseif('#'==$h){$t=s;$f=count($h).b;}else
{$v=explode(' ',$h);if(s==$t)for($h=$v,$v=0,$b=1;count($h);$b*=2)$v+=$b*array_shift($h);${$t}[]=$v;}

Nervenzusammenbruch

$p=[];  // must init $p to array or `$p[$y][]=$o;` will fail
foreach($r as$y=>$h)
{
    // walk $d through all combinations of $n=`hint count+1` numbers that sum up to $u=`width-hint sum`
    // (possible `0` hints for $h) - first and last number can be 0, all others are >0
    for(
        $d=[2-
            ($n=count($h)+1)+               // count(0 hint)=count(1 hint)+1
            $u=-array_sum($h)+$w=count($r)  // sum(0 hint) = width-sum(1 hint)
        ]                           // index 0 to max value $u-$n+2
        +array_fill($i=0,$n,1)      // other indexes to 1
        ,$d[$n-1]=0;                // last index to 0
                                    // --> first combination (little endian)
        $i<1;   // $i:0 before loop; -1 after increment; >=$n after the last combination
        $d[0]+=$u-array_sum($d) // (see below)
    )
    {
        // A: create row (binary value) from 1-hints $h and 0-hints $d
        $o=$x=0;
        foreach($d as$i=>$v)
            for($x+=$v,$k=$h[$i];$k--;)
                $o+=1<<$x++;
        // B: if $o satisfies the square hints
        if(($s[$y]|$o)==$o)
        {
            $p[$y][]=$o;    // add to possible combinations
            $q[$y]++;       // increase possibility counter
        }
        // C: increase $d
            // find lowest index with a value>min
                // this loop doesn´t need to go to the last index:
                // if all previous values are min, there is nothing left to increase
        for($i=0;$i<$n-1&$d[$i]==($i?1:0);$i++);
        if(++$i<$n)             // index one up; increase $d if possible
            for($d[$i]++        // increase this value
            ;$i--;)$d[$i]=1;    // reset everything below to 1
            // adjust $d[0] to have the correct sum (loop post condition)
    }
}

// search solution: with backtracking on the row combinations ...
function s($i,$m)
{
    global $c,$w,$p;
    for(;
        !$k // solution not yet found
        &&$i[$m]    // if $i[$m]==0, the previous iteration was the last one on this row: no solution
            --;     // decrease possibility index for row $m
        $k=$k&$m<$w-1? s($i,$m+1) : $k      // if ok, seek deeper while last row not reached ($m<$w-1)
    )
    {
        // test if the field so far satisfies the column hints: loop $x through columns
        for($k=1,$x=$w;$k&&$x--;)   // ok while $k is true
        {
            $h=$c[$x];
            // test column hints on the current combination: loop $y through rows up to $m
            for($v=$n=$z=   // $v=temporary value, $n=temporary hint, $z=hint index
                $y=0;$k&&$y<=$m;$y++)
                // if value has not changed, increase $n. if not, reset $n to 1
                // (or 0 for $k=false; in that case $n is irrelevant)
                $n=$n*  
                    // $f=false (int 0) when value has changed, true (1) if not
                    ($f=($p[$y][$i[$y]]>>$x&1)==$v)
                    +$k=$f?:    // ok if value has NOT changed, else
                        ($v=!$v)        // invert value. ok if value was 0
                        || $n==$h[$z    // value was 1: ok if temp hint equals current sub-hint
                        ++]             // next sub-hint
                ;
            // if there is a possibly incomplete hint ($v==1)
            // the incomplete hint ($n) must be <= the next sub-hint ($c[x][$z])
            // if $n was <$h[$z] in the last row, the previous column hints would not have matched
            if($k&$v)$k=$n<=$h[$z];
        }
        // ok: seek deeper (loop post condition)
        // not ok: try next possibility (loop pre condition)
    }
    return$k?is_array($k)?$k:$i:0;  // return solution if solved, 0 if not
}

// print solution
foreach(s($q,0)as$y=>$o)echo strrev(sprintf("\n%0{$w}b",$p[$y][$o]));
Titus
quelle
1
Das große Beispiel beendet meinen kleinen Heimserver (500 - Interner Serverfehler). Die Kombinationen sind nach 15 Sekunden fertig, aber das kartesische Produkt hat 1.823E + 61 Mitglieder. (Die 7. und 22. Reihe haben übrigens nur eine Lösung.) Der Algorithmus muss verbessert werden.
Titus
Ich denke, dies könnte beschleunigt werden, wenn Sie rekursives Backtracking verwenden. Trotzdem tolle Arbeit!
Gowrath
@gowrath: backtracking gibt ein bischen und spart sogar bytes ... integer mit bit arithmetik geben ca. 50% geschwindigkeit aber erhöhen die größe (muss noch herausfinden wie viel es genau kostet) ... ich bin noch dran.
Titus
@gowrath: Ich habe meinen Käfer verfolgt; es war in dem Zuwachs (wo sonst?): $dmuss in der richtigen Reihenfolge sein fürforeach
Titus