Trouvez les chemins!

10

Vous devez écrire un programme ou une fonction.

L'entrée est une «carte» de nombres. Vous pouvez choisir de prendre la carte sous la forme d'une chaîne avec de nouveaux caractères de ligne ( \n) ou d'un tableau 2D de chaînes.

Toutes les cartes sont de 5 caractères par 5 caractères, et les caractères sont toujours des chiffres supérieurs à 0 ou des espaces.

Voici un exemple de carte:

12 45
11233
  233
    1
2 899

Votre tâche consiste à trouver les composants connectés sur la carte. Un composant valide est une série d'au moins trois chiffres identiques connectés horizontalement et / ou verticalement (et non en diagonale ) ( pas des espaces ). Vous devrez alors remplacer les caractères des composants connectés valides par xs et imprimer ou renvoyer ce résultat.

Ainsi, la sortie de l'exemple ci-dessus serait:

x2 45
xx2xx
  2xx
    1
2 899

Voici un autre cas de test (merci à Martin Ender):

Input:
2   3
    4
 1  5
111 6
11  7

Output:
2   3
    4
 x  5
xxx 6
xx  7

C'est le code golf, donc le code le plus court en octets gagne!

Daniel
la source
Les modules intégrés sont-ils autorisés?
Ioannes
@Joannes, oui.
Daniel

Réponses:

1

JavaScript (ES6), 171 161 139 139 137 136 133 132 octets

f=(a,i=0)=>(F=i=>" "<c&&a[i]===c&&(a[i]=n,1+F(i-1)+F(i+1)+F(i-6)+F(i+6)),n=1,c=a[i],n=F(i)>2?"x":c,c=1,F(i),i>28?a:f(a,++i+(i%6>4)))
<!-- this HTML included just for testing --><textarea rows=5 cols=6 oninput="document.querySelector`pre`.innerHTML=this.value.length==29?f([...this.value]).join``:'invalid input'">12 45&#10;11233&#10;  233&#10;    1&#10;2 899</textarea><br/><pre></pre>

Ceci est une traduction de ma réponse Python. E / S en tant que tableaux de caractères.

Dommage qu'il n'y ait pas de moyen efficace de faire sum...

PurkkaKoodari
la source
5

Python 3, 238 237 200 199 192 192 181 octets

def f(a,i=0):F=lambda i,n,c:29>i>=0!=" "!=a[i]==c!=n and(a.__setitem__(i,n)or-~sum(F(i+j,n,c)for j in[-1,1,-6,6]));j=i+i//5;F(j,[a[j],"x"][2<F(j,1,a[j])],1);i>23or f(a,i+1);return a

Définit une fonction f(a)qui prend l'entrée comme un tableau de caractères et renvoie le même tableau modifié. (Les tableaux de caractères sont acceptés comme chaînes par défaut. )

Non golfé avec explication

Le code modifié est récursif, mais fonctionne de la même manière.

# The main function; fills all continuous nonempty areas of size >= 3 in array
# with x's. Both modifies and returns array.
def findpaths(array):
    # Fills a continuous area of curr_char in array with new_char, starting
    # from index. Returns the number of cells affected.
    def floodfill(index, new_char, curr_char):
        if (0 <= index < 29                   # Check that the position is in bounds
                and (index + 1) % 6 != 0      # Don't fill newlines
                and array[index] != " "       # Don't fill empty cells
                and array[index] == curr_char # Don't fill over other characters
                and curr_char != new_char):   # Don't fill already filled-in cells
            array[index] = new_char # Fill current position
            return (1 # Add neighboring cells' results, plus 1 for this cell
                    + floodfill(index + 1, new_char, curr_char)  # Next char
                    + floodfill(index - 1, new_char, curr_char)  # Previous char
                    + floodfill(index + 6, new_char, curr_char)  # Next line
                    + floodfill(index - 6, new_char, curr_char)) # Previous line
        return 0 # Nothing was filled. The golfed solution returns False here,
                 # but that's coerced to 0 when adding.

    for i in range(25): # Loop through the 25 cells
        i += i // 5 # Accommodate for newlines in input
        curr_char = array[i] # Get the cell's contents
        # Fill the area from the cell with dummies
        area_size = floodfill(i, 1, curr_char)
        # Convert dummies to "x" if area was large enough, back to original otherwise
        fill_char = "x" if 2 < area_size else curr_char
        floodfill(i, fill_char, 1)
    return array
PurkkaKoodari
la source
2 octets de moins pour battre la solution mathématique ...
FlipTack
1
@FlipTack Ouais. Je ne pense pas que cela se passe aujourd'hui, mais je traduis cela en JS et cela semble prometteur.
PurkkaKoodari
3

Rubis, 304 octets

def b(s,i)
  @v=[]
  b2(s,i,s[i])
end
def b2(s,i,c)
  if(0...s.size)===i&&s[i]==c&&!@v[i]
    @v[i]=s[i]='x'
    [1,-1,6,-6].each{|j|b2(s,i+j,c)}
  end
  s
end
def f(s)
  z = s.dup
  ps = ->(i){b(z.dup,i).scan('x').size}
  (0...s.size).each{|i|b(s, i)if ![' ',"\n"].include?(s[i])&&ps.call(i)>2}
  s
end

exemple d'utilisation:

puts f(File.read("map.txt"))

le code réutilise la méthode «blot» pour calculer la longueur du chemin.

variables / méthodes:

  • f (s): fonction pour convertir la chaîne de la carte, retourne une nouvelle carte avec des «x»
  • ps (i): taille du chemin à partir de l'index de carte i (où x = i% 6, y = i / 6)
  • s: chaîne d'entrée, lignes de carte séparées par "\ n"
  • z: copie de la chaîne d'entrée
  • b (s, i): fonction 'blot': écrit 'x' à partir de l'index de carte i sur les chemins
  • @v: tableau 'visité'

Tentative d'explication plus détaillée:

faire une copie de la chaîne d'entrée, que nous utilisons pour trouver la longueur du chemin à partir de n'importe quel point donné de la carte.

z = s.dup

définir une fonction anonyme 'ps' (longueur de chemin) (lambda) qui prend l'index de la carte i comme argument. il renvoie la longueur du chemin à partir de ce point. il le fait en appelant la méthode 'b' (blot) pour insérer des x sur une copie de la carte d'origine, puis en comptant le nombre de x dans la chaîne renvoyée.

  ps = ->(i){b(z.dup,i).scan('x').size}

la partie suivante parcourt chaque caractère de la carte (index i, caractère s [i]). il appelle la fonction «b» (blot) sur la position de carte i si la longueur du chemin depuis la position i est supérieure à 2, et s'il ne s'agit pas d'un espace ou d'un caractère de nouvelle ligne.

  (0...s.size).each { |i|
     b(s, i) if ![' ',"\n"].include?(s[i]) && ps.call(i) > 2
  }

la fonction b (blot) prend comme argument la chaîne de carte et un index. il initialise @v (tableau visité) et appelle la fonction d'assistance b2.

def b(s,i)
  @v=[]
  b2(s,i,s[i])
end

la fonction b2 prend la chaîne de carte, une position de carte (i) et un caractère dans le chemin courant (c). il s'appelle récursivement pour remplacer les sections de chiffres connectées par le caractère «x». il retourne la chaîne d'entrée (c'est ainsi que la fonction ps peut appeler scan () sur la valeur de retour).

cette instruction if vérifie que la position de la carte (i) donnée est dans les limites de la chaîne (0 ... s.size) et que le caractère à s [i] est le même que le caractère de départ. @v [i] est également vérifié pour éviter une récursion infinie.

if(0...s.size) === i && s[i] == c && !@v[i]

c'est le bit qui remplace le caractère de l'index (i) par le caractère 'x'. il marque également cet index comme visité.

@v[i] = s[i] = 'x'

c'est là que b2 s'appelle récursivement en recherchant le chemin. i + 1 est un caractère à droite, i-1 est un caractère à gauche, i + 6 est une ligne vers le bas (5 chiffres + 1 nouvelle ligne = 6 caractères), i-6 est une ligne vers le haut.

[1,-1,6,-6].each { |j| b2(s, i+j, c) }
Andrew
la source
1

C (Ansi), 243 233 179 188 octets

Golfé:

#define O o[1][l]
x,n,l,L;r(o,l)char**o;{if(!(l>L|l<0|O<47|O!=x))n++,O++,r(o,l-1),r(o,l+6),r(o,l-6),r(o,l+1),n>2?O='x':O--;}main(g,o)char**o;{for(;(L=30)>l;l++)n=0,x=O,r(o,l);puts(o[1]);}

Avec annotations:

#define O o[1][l]
x,n,l,L;      /*-------------------------- Globals*/
r(o,l)char**o;{ /*------------------------ Recursive Function*/
    if(!(l>L|l<0|O<47|O!=x)) /*----------- if this cell is valid(in
                                              range, is a number, is the 
                                              same as the parent number*/
    n++,     /*--------------------------- Increment count*/
    O++,     /*--------------------------- Increment character to mark*/
    r(o,l-1),  /*------------------------- Recurse left*/
    r(o,l+6),  /*------------------------- Recurse down*/
    r(o,l-6),  /*------------------------- Recurse down*/
    r(o,l+1),  /*------------------------- Recurse right*/
    n>2?O='x':O--;  /*---------------------If greater than 3, replace with x, else decrement character*/ 
}          /*----------------------------- Return*/

main(g,o)char**o;{ /*--------------------- Main*/
    for(;l<(L=30);l++){ /*---------------- For entire string and set L*/
        n=0;
        x=O;        /*-------------------- set counter to 0*/
        r(o,l); /*------------------------ Recurse*/
    } /*---------------------------------- End While*/
    puts(o[1]); /*------------------------ Print*/

}

Contribution:

Attend une nouvelle ligne au début et à la fin de la chaîne.

Exemple d'entrée:

./findPaths "
12 45
11233
  233
    1
2 899
"

Exemple de sortie:

x2 45
xx2xx
  2xx
    1
2 899

Mise à jour

Fixer la grille m'a permis de raser près de 60 octets.

dj0wns
la source
Je suppose que je peux enregistrer comme 22 caractères si je change cela en une taille de carte fixe - je changerai cela si je trouve autre chose que je veux changer
dj0wns
1

Mathematica, 180 octets

(f=Flatten@#;p=Partition)[If[Tr[1^VertexComponent[r~Graph~Cases[##&@@p[#,2,1]&/@Join[g=p[r,5],g],{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":>a<->b],#]]<3,f[[#]],"x"]&/@(r=Range@25),5]&

Explication:

(f=Flatten@#;p=Partition)[
  If[
    Tr[1^VertexComponent[
        r~Graph~Cases[
          ##&@@p[#,2,1]&/@Join[g=p[r,5],g],
          {a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":>a<->b
        ],
        #
      ]]<3,
    f[[#]],
    "x"
  ]&/@(r=Range@25),
  5
]&

Fonction pure qui accepte un 5x5tableau. est le caractère à usage privé de 3 octets U+F3C7représentant l'opérateur de transposition postfix \[Transpose].

(f=Flatten@#;p=Partition): Aplanit la liste d'entrée et la stocke f. Définit p = Partitionet retourne.

g=p[r,5]: Le tableau {{1,2,3,4,5}, ..., {21,22,23,24,25}}(c'est parce qu'il rest réglé sur Range@25).

Join[g=p[r,5],g]: la liste des lignes et colonnes de g.

p[#,2,1]&: Fonction pure qui partitionne la liste #en sous-listes de longueur 2avec chevauchement 1; c'est-à-dire la liste des paires adjacentes dans #.

##&@@p[#,2,1]&: Identique à ci-dessus sauf qu'il renvoie a Sequence.

##&@@p[#,2,1]&/@Join[g=p[r,5],g]: Mappe la fonction précédente des lignes et des colonnes de gpour obtenir une liste de toutes les entrées adjacentes dans g. Mon instinct dit qu'il existe un moyen plus court de le faire.

r~Graph~Cases[...]: Graphique dont les sommets sont les entiers 1, ..., 25et dont les arêtes sont les arêtes entre les entrées adjacentes dans glesquelles ont les mêmes entrées correspondantes dans le tableau d'entrée (autre que " ")

{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ": Modèle qui correspond {a,b}tel que f[[a]] == f[[b]](même valeur dans le tableau d'entrée) et qui n'est pas égal à " ". Réglez A = f[[a]]pour enregistrer l' 1octet.

...:>a<->b: Remplacez chaque correspondance par un bord non orienté de a à b.

VertexComponent: Renvoie la composante connectée du deuxième argument (un sommet) dans le premier argument (un graphique).

Tr[1^VertexComponent[...]]: La taille du composant connecté. Enregistre l' 1octet de Length@VertexComponent[...].

If[Tr[...]<3,f[[#]],"x"]&: Pure fonction qui prend une entrée #dans g. Si la taille de son composant connecté est inférieure à 3, remplacez-la par l'entrée correspondante dans l'entrée. Sinon, remplacez-le par "x".

(f=Flatten@#;p=Partition)[...,5]: Et enfin remodeler le résultat en un 5x5tableau.

ngenisis
la source
0

Clojure, 188 octets

C'est assez écrasant: D

#(apply str(map-indexed(fn[i v](if((set(flatten(for[m(range 30)](let[n(for[p[-1 -6 1 6]:when(=(get %(+ m p)0)((set"123456789")(% m)))](+ m p))](if(< 1(count n))(conj n m)[])))))i)\x v))%))

Appelé comme ceci (il faut un vecteur de caractères 1D):

(def f #(apply str(...))

(print (str "\n" (f (vec (str "12 45\n"
                              "11233\n"
                              "  233\n"
                              "    1\n"
                              "2 899\n")))))

(print (str "\n" (f (vec (str "2   3\n"
                              "    4\n"
                              " 1  5\n"
                              "111 6\n"
                              "11  7\n")))))

Trop paresseux pour le dé-golfer, mais for[m(range 30)]visite essentiellement chaque index et pour chaque index, l'intérieur let[n(for[p[-1 -6 1 6]...(+ m p))]fait une liste de 0 à 4 éléments qui répertorie les emplacements qui ont la même valeur (1 - 9) que l'emplacement du milieu. Si plus d'un voisin correspond à la pièce centrale, cela signifie que tous ceux-ci forment un cluster, donc ces emplacements sont ajoutés à l'ensemble utilisé à (if((set(flatten(...)))i). Si l'index iest trouvé dans l'ensemble, il \xest émis et la valeur d'origine dans le cas contraire. C'est :when( ... )assez intéressant ...

NikoNyrh
la source