Hur vi gör våra nonogram
Varje pussel här börjar som en vanlig bild och slutar som ett rutnät du kan lösa med enbart logik. Däremellan går det genom en automatiserad pipeline som rasteriserar bilden, testar om resultatet faktiskt är lösbart och kastar bort dem som inte är det. Den här sidan går ärligt igenom den processen — inklusive delarna som misslyckas, eftersom det mesta av arbetet ligger i att förkasta dåliga pussel snarare än att skapa bra.
1. Det börjar med en bild
Ett nonogram är alltid bara en svartvit siluett — ingen skuggning, ingen färg, inga inre detaljer. Så det första steget är att välja en källbild vars form läses tydligt vid en pytteliten upplösning: ett djur, en frukt, ett stjärntecken, ett vardagsföremål. Vi utgår från vektorgrafik (SVG), transparenta PNG-filer och vanliga foton, organiserade i temabaserade resurspaket, plus bilder som hämtas in via en bildsökning i appen.
Det som räknas i det här skedet är inte hur vacker bilden är — det är hur väl dess kontur överlever att pressas ner till ett 15×15- eller 20×20-rutnät. En kraftfull, väl avgränsad form fungerar. En rörig scen med många små överlappande delar gör det nästan aldrig, och vi ska se varför nedan.
2. Att göra en bild till ett rutnät
Bilden rasteriseras med ett riktigt bildbibliotek (samma som webbläsare lutar sig mot för SVG) och reduceras sedan till ett enda svart-eller-vitt-värde per cell. Det finns inget enda ”rätt” sätt att göra det på, så pipelinen provar flera: utifrån bildens egen genomskinlighet där den har någon, utifrån ren ljushet (mörkt = fyllt) eller — för ett ljust, färgstarkt motiv mot en enfärgad bakgrund, där ljushet ensam knappt skiljer ut det — utifrån färgavstånd från bakgrunden. En ljusorange räv på vitt är nästan vit i ljushet men långt därifrån i färg; färgavståndsmasken isolerar den rent.
Gränsen mellan ”fylld” och ”tom” väljs automatiskt med Otsus metod (Otsu's method), en standardteknik som hittar det ljushetströskelvärde som delar bilden renast i två grupper. Eftersom det inte går att veta i förväg vilken storlek, beskärning och tröskel som läses bäst, genererar pipelinen många kandidatrutnät per bild — olika storlekar, olika trösklar — beskär vart och ett till sitt fyllda innehåll och anpassar formen till rutnätets proportioner, så att en bred krona får ett brett rutnät i stället för att pressas ihop till en kvadrat.
3. Att kontrollera att det faktiskt går att lösa
En bild som ser bra ut för en människa är inte automatiskt ett giltigt pussel. Ett riktigt nonogram måste vara lösbart utifrån enbart sina rad- och kolumnledtrådar och — avgörande nog — måste ha exakt en lösning. Om två olika fyllda mönster båda uppfyller varje ledtråd är pusslet tvetydigt och orättvist, eftersom en lösare som följer ren logik korrekt skulle kunna hamna på den ”felaktiga” bilden.
Så varje kandidat matas till en lösare: den tillämpar samma rad-för-rad-slutledningar som en person skulle göra, och där logiken ensam kör fast faller den tillbaka på en uttömmande sökning för att räkna hur många fullständiga lösningar som finns. Varje rutnät med noll lösningar (motsägelsefullt) eller mer än en lösning (tvetydigt) förkastas på fläcken. Denna entydighetskontroll är den enskilt viktigaste grinden i hela pipelinen.
4. Att se till att det är logik, inte gissning
Att ha en lösning är inte riktigt nog. Ett pussel kan vara tekniskt entydigt men bara nåbart genom prövning och misstag — fylla en cell, följa den djupt in i rutnätet och backa när den motsäger sig. Det är inte att lösa; det är att gissa, och det ger ett frustrerande pussel.
För att fånga detta klassificerar vi hur svårt varje pussel är att resonera sig igenom. Pussel som följer av rättfram rad-för-rad-logik är ”enkla”. En andra, välstuderad nivå av deduktion (baserad på publicerad forskning om nonogramsvårighet av Batenburg and Kosters) klarar det mesta av resten utan någon gissning. Allt som fortfarande inte kan avgöras utan prövning och misstag flaggas som gissning-krävande — och för den vardagliga katalogen läggs de åt sidan i stället för att publiceras.
5. Varför många bilder aldrig kommer med
Före allt lösningsarbete förutsäger pipelinen också om en bild ens är värd att försöka med, med hjälp av två trubbiga men ärliga signaler. Den ena är separerbarhet: hur rent bilden alls delar sig i två toner — en grumlig källa med låg kontrast är en dålig satsning i vilken storlek som helst. Den andra är en detalj-mot-upplösning-passform: en bild med långt fler fina drag än rutnätet har celler kollapsar bara till en klick.
Ett konkret exempel från vår egen testning: ett riktigt foto av Eiffeltornet gav en 40×40-kandidat som klarade varje lösbarhetskontroll — en entydig lösning, ett rimligt fyllnadsförhållande — men återgavs som en massiv rektangel. Tornets gitterdetalj och röran under det plattades ut till ett enda odifferentierat block. Tekniskt ett giltigt nonogram; visuellt oanvändbart. Fall som det är precis vad dessa förhandskontroller, plus en mänsklig blick, finns till för att stoppa. För att vara tydliga om gränserna: det finns ingen synmodell här — pipelinen känner aldrig igen *vad* som finns i en bild, den mäter bara hur väl dess form konverteras. Därför är det slutliga avgörandet fortfarande en persons.
6. Ett betyg, och en sista mänsklig blick
Pussel som klarar varje grind får ett svårighetsbetyg utifrån sin lösningsnivå och sin formstatistik (hur fyllt rutnätet är, om bilden löper ut över kanterna och så vidare), vilket är det som sorterar in dem i lätta, medelsvåra och svåra samlingar. Sedan öppnar en person dem som är på väg till katalogen i vår rutnätsredigerare, kontrollerar att bilden verkligen läses som det den ska vara, och justerar eller kasserar allt som de automatiska kontrollerna släppte igenom men inte borde ha.
Det är en medvetet oglamorös process, och det är själva poängen: automatiseringen finns för att garantera rättvisa — en lösning, lösbar med logik — medan en människa vakar över det en dator inte kan bedöma, nämligen om den färdiga bilden är något att ha.
Det är hela pipelinen, minus koden. Om du hellre löser ett än läser om hur det byggs är dagens pussel ett bra ställe att börja.
