Conta i comuni schemi di Game of Life


21

Il compito qui è leggere da un .rlefile Golly o in testo semplice (a scelta) il cui nome file è fornito (su STDIN o come argomento della riga di comando) e identificare e contare i modelli comuni nella griglia in esso codificata.

In alternativa, è possibile scegliere di disporre invece dei contenuti del file direttamente su STDIN.

Il tuo programma dovrebbe essere in grado di identificare e distinguere almeno le quindici nature morte più comuni e i cinque oscillatori più comuni , oltre agli alianti .

Tutte le fasi di questi oscillatori dovrebbero essere riconosciute, così come tutte e quattro le fasi dell'aliante.

Dovrebbe essere visualizzato un elenco contenente il conteggio finale di ogni modello, con il nome e la quantità di ciascun modello su una riga separata. Il programma può includere nell'elenco di output tutti questi schemi o solo quelli di cui è stato trovato almeno uno.

I pattern che fanno parte di altri pattern contati non devono essere conteggiati. (ad esempio, la fase a 8 celle di un faro non deve essere conteggiata come due blocchi e un legame di nave non deve essere conteggiato come due navi)

Si può presumere che l'input si sia già stabilizzato e non contenga pattern non inclusi nel set di cui sopra. Si può anche supporre che la griglia di input si adatti a una casella 1024x1024.

Questo è , quindi vince il programma più breve.

Descrizione del formato di file RLE

Un file RLE contiene una griglia di vita codificata di lunghezza di esecuzione. Tutte le righe che iniziano con #sono commenti e devono essere ignorate.

La prima riga non vuota, non commentata è del modulo x=<width>,y=<height>,rule=<rule>. Ai fini di questa attività, la regola sarà sempre B3/S23. Può contenere spazi che devono essere rimossi prima di elaborare questa linea (ovviamente, non è necessario elaborare questa linea).

Le righe senza commento dopo la prima devono essere trattate come una singola stringa. Questo dovrebbe consistere solo di cifre decimali, i personaggi $, be o, e interruzioni di riga, e non finirà con una cifra. Le interruzioni di riga devono essere ignorate, ma si può presumere che le interruzioni di riga non interrompano le stringhe di cifre.

Questo può essere terminato da un singolo !.

brappresenta una cellula morta, orappresenta una cellula viva e $rappresenta la fine di una riga. Qualsiasi numero decimale indica che il seguente simbolo deve essere trattato come ripetuto più volte.

Codifica del modello in chiaro

L'altra opzione è leggere il modello in un altro formato di testo normale qui descritto . In questa codifica, le celle off sono rappresentate con trattini e le celle sono rappresentate con O maiuscole, con le nuove linee che separano le righe.

Si può presumere che tutte le righe senza commento verranno riempite alla stessa lunghezza dei trattini.

Le righe che iniziano con !sono commenti e devono essere ignorate.

Alcuni casi di test

RLE:

#This is a comment
x = 35, y = 16, rule = B3/S23
bo$2o$obo5$22bo$22bo$22bo2$18b3o3b3o2$22bo$22bo10b2o$22bo10b2o!

plaintext:

!This is a comment
-O---------------------------------
OO---------------------------------
O-O--------------------------------
-----------------------------------
-----------------------------------
-----------------------------------
-----------------------------------
----------------------O------------
----------------------O------------
----------------------O------------
-----------------------------------
------------------OOO---OOO--------
-----------------------------------
----------------------O------------
----------------------O----------OO
----------------------O----------OO

risultati:

Glider 1
Blinker 4
Block 1

RLE:

x = 27, y = 15, rule = B3/S23
5b2o$5b2o9$11bo$o9bobo$o9bobo$o10bo12b3o!
#Here's a comment at the end

plaintext:

-----OO--------------------
-----OO--------------------
---------------------------
---------------------------
---------------------------
---------------------------
---------------------------
---------------------------
---------------------------
---------------------------
-----------O---------------
O---------O-O--------------
O---------O-O--------------
O----------O------------OOO
!Here's a comment at the end

risultati:

Block 1
Blinker 2
Beehive 1

RLE:

#You may have multiple comments
#As shown here
x = 13, y = 11, rule = B3/S23
2o$2o2$12bo$12bo$12bo$2b2o$2b2o4b2o$7bo2bo$7bobo$8bo!

plaintext:

!You may have multiple comments
!As shown here
OO-----------
OO-----------
-------------
------------O
------------O
------------O
--OO---------
--OO----OO---
-------O--O--
-------O-O---
--------O----

risultati:

Block 2
Blinker 1
Loaf 1

RLE:

# Pentadecathlon
# Discovered by John Conway
# www.conwaylife.com/wiki/index.php?title=Pentadecathlon
x = 10, y = 3, rule = B3/S23
2bo4bo2b$2ob4ob2o$2bo4bo!

plaintext:

! Pentadecathlon
! Discovered by John Conway
! www.conwaylife.com/wiki/index.php?title=Pentadecathlon
--O----O--
OO-OOOO-OO
--O----O--

risultati:

Pentadecathlon 1

indennità

Se si supportano entrambi i formati di input (utilizzando l'estensione del file [ .rleper i file rle e .cellsper il testo in chiaro - come viene definita la definizione di altre estensioni) o un flag della riga di comando per distinguerli) è possibile sottrarre il 5% dal punteggio.


Che ne diciOOO.OO\n....OO
Akangka il

@ChristianIrwan Bene, questo non è un modello stabile, quindi non ti verrà dato come input comunque.
SuperJedi224,

Risposte:


13

Haskell, 2417 byte

Ci è voluto un po 'di tempo e ci sono ancora alcuni bug, ma ho avuto diversi trucchi funzionanti quindi ne è valsa la pena.

Gli appunti:

  • Accetta solo il formato in chiaro, passato a STDIN
  • Ci vuole qualcosa come O (n ^ 20) tempo
  • Ho assunto che il numero di caratteri nelle righe non di commento sia costante (all'interno di un input specifico), poiché è così negli esempi
  • Il trucco più folle è stato come decomprimere i modelli, estraendo gli elementi in posizioni (numero colonna) modulo (la lunghezza dell'output) per costruire l'array.

Unisce alcune idee chiave:

  • modelli e simmetrie possono essere pre-calcolati
  • un singolo modello può essere impacchettato in un numero intero, con dimensioni note
  • trovare tutte le matrici è facile
  • contare le uguaglianze è facile

Ecco il codice:

r=[1..20]
a!0=a!!0
a!x=tail a!(x-1)
u[_,x,y,l]=[[odd$div l$2^i|i<-[0..y],mod i x==j]|j<-[0..x-1]]
main=interact(\s->let q=[map(=='O')l|l<-lines s,l!0/='!']in let g=[i|i<-[[[0,3,11,3339,0,4,11,924,0,4,11,3219,0,3,11,1638,1,4,15,19026,1,4,15,9636,2,3,11,1386,2,4,11,1686,3,7,48,143505703994502,3,7,48,26700311308320,3,7,48,213590917399170,3,7,48,8970354435120,4,2,3,15,5,3,8,171,5,3,8,174,5,3,8,426,5,3,8,234,6,4,15,36371,6,4,15,12972,6,4,15,51313,6,4,15,13644,6,4,15,50259,6,4,15,12776,6,4,15,51747,6,4,15,6028,7,4,15,26962,7,4,15,9622,7,4,15,19094,7,4,15,27044,8,5,24,9054370,8,5,24,2271880,9,4,15,51794,9,4,15,13732,9,4,15,19027,9,4,15,9644,10,4,19,305490,10,5,19,206412,10,5,19,411942,10,4,19,154020,11,3,8,427,11,3,8,238,12,6,35,52217012547,12,6,35,3306785328,13,3,8,170,14,3,8,428,14,3,8,458,14,3,8,107,14,3,8,167,14,3,8,482,14,3,8,302,14,3,8,143,14,3,8,233,14,3,8,241,14,3,8,157,14,3,8,286,14,3,8,370,14,3,8,181,14,3,8,115,14,3,8,346,14,3,8,412,15,4,15,51219,15,4,15,12684,15,4,15,52275,15,4,15,13260,16,1,2,7,16,3,2,7,17,3,29,313075026,17,10,29,139324548,17,3,23,16252911,17,8,23,16760319,17,5,49,152335562622276,17,10,49,277354493774076,17,7,69,75835515713922895368,17,10,69,138634868908666122360,17,9,89,135722011765098439128942648,17,10,89,58184575467336340020006960,17,5,59,160968502306438596,17,12,59,145347113669124612,17,5,59,524156984170595886,17,12,59,434193401052698118,17,5,69,164495599269019571652,17,14,69,222245969722444385292,17,5,69,517140479305239282702,17,14,69,222262922122170485772,17,3,47,83020951028178,17,16,47,39740928107556,17,3,35,62664969879,17,12,35,40432499049,17,3,41,1581499314234,17,14,41,1293532058322,17,3,41,4349006881983,17,14,41,3376910168355,17,3,47,92426891685930,17,16,47,83780021865522,17,3,47,79346167206930,17,16,47,11342241794640,18,13,168,166245817041425752669390138490014048702557312780060,18,15,224,1711376967527965679922107419525530922835414769336784993839766570000,18,13,168,141409121010242927634239017227763246261766273041932,19,2,7,126,19,4,7,231,19,4,7,126,19,2,7,189,19,4,15,24966,19,4,15,18834,19,4,15,10644,19,4,15,26646]!p|p<-[h..h+3]]|h<-[0,4..424]],j<-[[[q!y!x|x<-[a..a+c]]|y<-[b..b+d]]|c<-r,d<-r,a<-[0..(length$q!0)-c-1],b<-[0..length q-d-1]],u i==j]in show[(words"aircraftcarrier barge beehive biloaf1 block boat eater1 loaf longbarge longboat mango ship shiptie tub glider beacon blinker pentadecathlon pulsar toad"!(e!0),sum[1|f<-g,e!0==f!0])|e<-g])

Ecco il codice Mathematica utilizzato per impacchettare un array di 0,1 nel formato successivamente decompresso dal programma haskell:

rotate[m_]:=Transpose[Map[Reverse,m]]
findInversePermutation[m_]:=Block[{y=Length[First[m]], x=Length[m]}, InversePermutation[FindPermutation[Flatten[m], Flatten[Table[Table[Flatten[m][[i+1]], {i, Select[Range[0, x * y - 1], Mod[#, x]==j&]}], {j, 0, x - 1}]]]]]
enumShape[m_]:=Partition[Range[1, Length[Flatten[m]]], Length[m[[1]]]]
pack[m_]:={Length[rotate[rotate[m]]], Length[Flatten[rotate[rotate[m]]]], FromDigits[Permute[Flatten[rotate[rotate[m]]], findInversePermutation[enumShape[rotate[rotate[m]]]]], 2]}

Ecco un ungolfing molto più completo del codice:

range = [1..16]          -- all of the patterns fall within this range

list ! 0        = list !! 0           -- this is a simple generic (!!)
list ! position = (tail list) ! (position - 1)

unpack [_, unpackedLength, unpackedSize, packed] = [ [odd $ div packed (2^i) | i <- [0..unpackedSize], (mod i unpackedLength) == j] | j <- [0..unpackedLength - 1]]

main=interact doer

doer input = show $ tallyByFirst (words nameString) foundPatterns -- this counts equalities between the list of patterns and the submatrices of the input
  where
    parsed = parse input -- this selects the non-comment lines and converts to an array of Bool's
    foundPatterns = countOccurrences partitioned subArrays
    subArrays     = allSubArrays parsed
    partitioned   = modPartition compressed 428 4 -- this partitions the compressed patterns into the form [name number, x length, x length * y length, packed integer]

countOccurrences patterns subArrays = [pattern | pattern <- patterns, subArray <- allSubArrays q, unpack pattern == subArray]

subArray m offsetX subSizeX offsetY subSizeY = [[m ! y ! x | x <- [offsetX..offsetX + subSizeX]] | y <- [offsetY..offsetY + subSizeY]]

allSubArrays m = [subArray m offsetX subSizeX offsetY subSizeY | subSizeX <- range, subSizeY <- range, offsetX <- [0.. (length $ head m) - subSizeX - 1], offsetY <- [0..(length m) - subSizeY - 1]]

tallyByFirst names list = [ (names ! (a ! 0), sum [1 | a <- list, (head a) == (head b)]) | b <- list]

parse string = [map (=='O') line | line <- lines string, head line /= '!']

modPartition list chunksize = [ [list ! position | position <- [offset..offset + chunksize - 1]] | offset <- [0, chunksize..(length list) - chunksize]]

Benvenuti in PPCG! Non l'ho ancora provato ma sembra davvero impressionante. +1!
uno spaghetto il

Questo è più che impressionante, +1!
gatto
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.