Compter les schémas Game of Life courants

21

La tâche ici est de lire à partir d'un .rlefichier Golly ou en texte brut (votre choix) dont le nom de fichier est fourni (sur STDIN ou comme argument de ligne de commande) et d'identifier et de compter les modèles courants dans la grille codée.

Alternativement, vous pouvez choisir d'avoir le contenu du fichier fourni directement sur STDIN à la place.

Votre programme devrait être en mesure d'identifier et de distinguer au moins les quinze natures mortes strictes les plus courantes et les cinq oscillateurs les plus courants , ainsi que les planeurs .

Toutes les phases de ces oscillateurs doivent être reconnues, tout comme les quatre phases du planeur.

Il devrait produire une liste contenant le nombre final de chaque modèle, avec le nom et la quantité de chaque modèle sur une ligne distincte. Votre programme peut inclure dans la liste de sortie tous ces modèles ou seulement ceux dont au moins un a été trouvé.

Les motifs qui font partie d'autres motifs en cours de comptage ne doivent pas être comptés. (par exemple, la phase à 8 cellules d'une balise ne doit pas également être comptée comme deux blocs, et une cravate ne doit pas également être comptée comme deux navires)

Vous pouvez supposer que l'entrée est déjà stabilisée et ne contient aucun motif qui ne se trouve pas dans l'ensemble susmentionné. Vous pouvez également supposer que la grille d'entrée s'insérera dans une zone 1024x1024.

Il s'agit de , donc le programme le plus court l'emporte.

Description du format de fichier RLE

Un fichier RLE contient une grille de durée de vie codée sur toute la durée. Toutes les lignes commençant par #sont des commentaires et doivent être ignorées.

La première ligne non vide et sans commentaire est du formulaire x=<width>,y=<height>,rule=<rule>. Aux fins de cette tâche, la règle sera toujours B3/S23. Il peut contenir des espaces qui doivent être supprimés avant de traiter cette ligne (bien sûr, il n'est pas nécessaire de traiter cette ligne du tout.)

Les lignes sans commentaire après la première doivent être traitées comme une chaîne unique. Cela devrait être composé uniquement de chiffres décimaux, les caractères $, bet o, et les sauts de ligne, et ne se terminera pas par un chiffre. Les sauts de ligne doivent être ignorés, mais vous pouvez supposer que les sauts de ligne n'interrompent pas les chaînes de chiffres.

Cela peut être résilié par un seul !.

breprésente une cellule morte, oreprésente une cellule vivante et $représente la fin d'une ligne. Tout nombre décimal indique que le symbole suivant doit être traité comme se répétant autant de fois.

Encodage de modèle en texte clair

L'autre option consiste à lire le modèle dans un autre format de texte en clair décrit ici. Dans cet encodage, les cellules off sont représentées par des tirets et les cellules on sont représentées par des O majuscules, avec des retours à la ligne séparant les lignes.

Vous pouvez supposer que toutes les lignes sans commentaire seront complétées de la même longueur que les tirets.

Les lignes commençant par !sont des commentaires et doivent être ignorées.

Quelques cas de test

RLE:

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

Texte clair:

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

Résultats:

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

Texte clair:

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

Résultats:

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!

Texte clair:

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

Résultats:

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!

Texte clair:

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

Résultats:

Pentadecathlon 1

Prime

Si vous prenez en charge les deux formats d'entrée (en utilisant l'extension de fichier [ .rlepour les fichiers rle et .cellspour le texte en clair - la façon dont les autres extensions doivent être lues n'est pas définie] ou un indicateur de ligne de commande pour les distinguer), vous pouvez soustraire 5% de votre score.

SuperJedi224
la source
Que diriez-vousOOO.OO\n....OO
Akangka
@ChristianIrwan Eh bien, ce n'est pas un modèle stable, donc vous ne le recevrez pas de toute façon.
SuperJedi224

Réponses:

13

Haskell, 2417 octets

Cela a pris un certain temps et il y a encore quelques bugs, mais j'ai eu plusieurs astuces qui fonctionnaient donc ça valait le coup.

Remarques:

  • Il accepte uniquement le format texte brut, transmis à STDIN
  • Cela prend quelque chose comme le temps O (n ^ 20)
  • J'ai supposé que le nombre de caractères dans les lignes de non-commentaire est constant (dans une entrée spécifique), comme c'est le cas dans les exemples
  • L'astuce la plus folle était de savoir comment les modèles sont décompressés, en extrayant les éléments aux positions (numéro de colonne) modulo (la longueur de la sortie) pour construire le tableau.

Il combine quelques idées clés:

  • les motifs et les symétries peuvent être précalculés
  • un seul motif peut être emballé dans un entier, avec des dimensions connues
  • trouver toutes les sous-matrices est facile
  • compter les égalités est facile

Voici le code:

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])

Voici le code Mathematica utilisé pour emballer un tableau de 0,1 dans le format décompressé plus tard par le programme 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]}

Voici un dégoût beaucoup plus complet du code:

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]]
Michael Klein
la source
Bienvenue chez PPCG! Je n'ai pas encore essayé cela mais ça a l'air impressionnant. +1!
un spaghetto du
C'est plus qu'impressionnant, +1!
chat