Recherche de carrés de marche

9

Marching Squares est un algorithme de l'infographie, qui est utilisé pour récupérer des isocontours 2D à partir d'une grille d'échantillons (voir également son grand frère Marching Cubes pour les paramètres 3D). L'idée est de traiter chaque cellule de la grille indépendamment et de déterminer les contours passant par cette cellule en fonction des valeurs à ses coins.

La première étape de ce processus consiste à déterminer quelles arêtes sont reliées par des contours, selon que les coins sont supérieurs ou inférieurs à la valeur du contour. Par souci de simplicité, nous ne considérerons que les contours le long de la valeur 0, de sorte que nous souhaitons savoir si les coins sont positifs ou négatifs. Il y a des cas à distinguer:24 = 16

entrez la description de l'image ici
Source de l'image: Wikipedia

L'identification du blanc et du noir n'a pas vraiment d'importance ici, mais pour être précis, disons que le blanc est positif et le noir est négatif. Nous ignorerons les cas où l'un des coins est exactement 0.

Les points de selle (cas 5 et 10) offrent un peu de difficulté supplémentaire: il n'est pas clair quelles diagonales doivent être utilisées en ne regardant que les coins. Cela peut être résolu en trouvant la moyenne des quatre coins (c'est-à-dire une approximation de la valeur centrale) et en choisissant les diagonales de telle sorte que les contours séparent le centre des coins avec le signe opposé. Si la moyenne est exactement 0, l'un ou l'autre cas peut être choisi.

Normalement, ces 16 cas sont simplement stockés dans une table de recherche. C'est génial pour l'efficacité, mais bien sûr, nous préférerions que le code soit court ici. Votre tâche consiste donc à effectuer cette étape de recherche et à imprimer une représentation ASCII du cas dans le moins de code possible.

Le défi

On vous donne les valeurs des quatre coins (entiers non nuls) dans un ordre fixe de votre choix. Vous devez ensuite générer la disposition correcte des contours, en résolvant correctement les cas de point de selle.

Vous pouvez écrire un programme ou une fonction, en prenant une entrée via STDIN (ou l'alternative la plus proche), un argument de ligne de commande ou un argument de fonction et en sortant le résultat via STDOUT (ou l'alternative la plus proche), une valeur de retour de fonction ou un paramètre de fonction (out).

L'entrée peut être prise dans n'importe quel format de chaîne ou de liste.

Les 16 cas seront représentés dans l'art ASCII en utilisant l'un des blocs 5x5 suivants:

o---o  o---o  o---o
|   |  |   |  | | |
|   |  |---|  | | |
|   |  |   |  | | |
o---o  o---o  o---o

o---o  o---o  o---o  o---o
|/  |  |  \|  |   |  |   |
|   |  |   |  |   |  |   |
|   |  |   |  |\  |  |  /|
o---o  o---o  o---o  o---o

o---o  o---o
|/  |  |  \|
|   |  |   |
|  /|  |\  |
o---o  o---o

Vous ne devez imprimer aucun espace de début ou de fin, mais vous pouvez imprimer une seule nouvelle ligne facultative.

Il s'agit du code golf, donc la réponse la plus courte (en octets) l'emporte.

Cas de test

Les cas de test supposent que l'entrée est donnée dans l'ordre supérieur gauche , supérieur droit , inférieur gauche , inférieur droit . Les cas de test sont présentés en 9 groupes, un correspondant à chacune des 9 représentations données ci-dessus (dans le même ordre, à partir de la cellule vide, en terminant par les deux points de selle).

[1, 2, 1, 3]
[-9, -2, -2, -7]

[4, 5, -1, -2]
[-1, -2, 3, 4]

[7, -7, 7, -7]
[-5, 5, -5, 5]

[1, -6, -4, -1]
[-2, 3, 3, 4]

[-1, 6, -4, -1]
[2, -3, 3, 4]   

[-1, -6, 4, -1]
[2, 3, -3, 4]

[-1, -6, -4, 1]
[2, 3, 3, -4]

[3, -8, -9, 2]
[-3, 8, 9, -2]

[8, -3, -2, 9]
[-8, 3, 2, -9]

De plus, les cas de test suivants peuvent renvoyer l'un des points de selle (votre choix):

[1, -4, -2, 5]
[-1, 4, 2, -5]
Martin Ender
la source

Réponses:

4

Rubis, 201 180 176

Il s'agit d'une fonction lambda anonyme, à appeler de la manière indiquée dans l'exemple non golfé.

Cela ne contient aucune variable s. Dans la version non golfée, une expression complexe est affectée à des sfins de clarté avant d'être utilisée. 4 octets sont enregistrés dans la version golfée en la mettant en ligne. La seule autre différence entre les versions est l'espace et les commentaires.

S'il est acceptable de renvoyer la sortie sous la forme d'un tableau de cinq chaînes de cinq caractères, au lieu d'imprimer sur stdout, un octet supplémentaire peut être enregistré.

->a{p=t=0
4.times{|i|t+=a[i]*=a[3];p+=a[i]>>9&1<<i}
q=p==6&&t>0?19:'@AC@P*10'[p].ord
puts c='o---o',(0..2).map{|i|b=p*i==3?'|---|':'|   |';b[q%4]='|/|\|/'[q%4+(i&2)];q/=4;b},c}

Je suis satisfait de l'analyse du tableau, mais je pense qu'il peut y avoir des moyens plus courts pour former la sortie.

Les quatre éléments du tableau d'entrée sont multipliés par le dernier élément. Cela garantit que le dernier élément est positif et réduit le nombre de cas de 16 à 8. Les éléments sont décalés de 9 places, de sorte que tous les nombres positifs deviennent 0 et tous les nombres négatifs deviennent -1 (au moins dans la plage d'entrée) donné dans les cas de test.) Ils sont ensuite ET 1<<array indexpour donner un nombre binaire de 3 bits indiquant le modèle (en fait 4 bits, mais comme le dernier élément est toujours positif, le 4e bit est toujours zéro.)

Ce nombre compris entre 0 et 7 est ensuite introduit dans une table de recherche (soupir) pour déterminer quels caractères de chaque ligne ne sont pas des espaces. C'est à ce stade que les deux affichages différents pour le boîtier de selle sont traités, avec une alternative au nombre dans la table de recherche utilisée si le total est positif (la question dit de considérer la "moyenne", mais comme nous ne le sommes que intéressé par le signe, peu importe si nous considérons le total à la place.)

Nous espérons que le fonctionnement de l'affichage des résultats ressort clairement des commentaires dans le code.

non golfé dans le programme de test

f=->a{p=t=0
  4.times{|i|                      #for each number in the input
    t+=a[i]*=a[3];                   #multiply each number by a[3]; totalize the sum in t
    p+=a[i]>>9&1<<i                  #shift right to find if negative; AND with 1<<i to build index number for pattern 
  }                                #q is a 3-digit base 4 number indicating which character of each line is non-whitespace (if any). 
  q=p==6&&t>0?19:'@AC@P*10'[p].ord #It's encoded in the magic string, except for the case of saddles with a positive total, which is encoded by the number 19.
  s=(0..2).map{|i|                 #build an array of 3 strings, indexes 0..2
    b=p*i==3?'|---|':'|   |';        #IF p is 3 and we are on row 1, the string is |---| for the horizontal line case. ELSE it is |   |.
    b[q%4]='|/|\|/'[q%4+(i&2)];      #The numbers in q indicate which character is to be modified. The characters in the string indicate the character to replace with.
    q/=4;                            #If q%4=0, the initial | is replaced by | (no change.) i&2 shifts the string index appropriately for the last row.
    b                                #divide q by 4, and terminate the loop with the expression b so that this is the object loaded into array s.  
  }
puts c='o---o',s,c}                #print the array s, capped with "o---o" above and below.


[[1, 2, 1, 3],
[-9, -2, -2, -7],

[4, 5, -1, -2],
[-1, -2, 3, 4],

[7, -7, 7, -7],
[-5, 5, -5, 5],

[1, -6, -4, -1],
[-2, 3, 3, 4],

[-1, 6, -4, -1],
[2, -3, 3, 4],

[-1, -6, 4, -1],
[2, 3, -3, 4],

[-1, -6, -4, 1],
[2, 3, 3, -4],

[3, -8, -9, 2],
[-3, 8, 9, -2],

[8, -3, -2, 9],
[-8, 3, 2, -9],

[1, -4, -2, 5],
[-1, 4, 2, -5]].each{|k|f.call(k)}
Level River St
la source