Quante torri riesci a vedere?


29

Questa domanda si basa sulle torri puzzle di posizionamento dei numeri (note anche come grattacieli), che puoi giocare online . Il tuo obiettivo è quello di prendere una soluzione al puzzle e determinare gli indizi: il numero di torri visibili lungo ogni riga e colonna. Questo è il golf del codice, quindi vince meno byte.

Come funzionano le torri

La soluzione di un puzzle di Torri è un quadrato latino - una n*ngriglia in cui ogni riga e colonna contiene una permutazione dei numeri 1attraverso n. Un esempio per n=5è:

4 3 5 2 1 
5 4 1 3 2 
1 5 2 4 3 
2 1 3 5 4 
3 2 4 1 5 

Ogni riga e colonna è etichettata con un indizio a ciascuna estremità come:

       2 3 1 4 5    
       v v v v v

 2 >   4 3 5 2 1   < 3
 1 >   5 4 1 3 2   < 4
 2 >   1 5 2 4 3   < 3
 3 >   2 1 3 5 4   < 2
 3 >   3 2 4 1 5   < 1 

       ^ ^ ^ ^ ^
       2 2 2 2 1

Ogni indizio è un numero da 1a nche indica quante torri "vedi" guardando lungo la riga / colonna da quella direzione, se i numeri sono trattati come torri con quell'altezza. Ogni torre blocca torri più brevi dietro di essa. In altre parole, le torri che puoi vedere sono quelle che sono più alte di qualsiasi torre prima di loro.

Immagine da Conceptis Puzzles

Ad esempio, diamo un'occhiata alla prima riga.

 2 >   4 3 5 2 1   < 3

Ha un indizio 2da sinistra perché puoi vedere il 4e il 5. I 4blocchi della 3dalla vista e la 5blocca tutto il resto. Da destra, è possibile vedere 3le torri: 1, 2, e 5.

Requisiti del programma

Scrivi un programma o una funzione che accetta la griglia di numeri e genera o stampa gli indizi, procedendo in senso orario dall'angolo in alto a sinistra.

Ingresso

Una n*npiazza latina con 2<=n<=9.

Il formato è flessibile È possibile utilizzare qualsiasi struttura di dati che rappresenti una griglia o un elenco contenente numeri o caratteri numerici. Potrebbe essere necessario un separatore tra le righe o nessun separatore. Alcune possibilità sono un elenco, un elenco di elenchi, una matrice, una stringa separata da token come

43521 54132 15243 21354 32415,

o una stringa senza spazi.

Non ti viene dato ncome parte dell'input.

Produzione

Ritorna o stampa gli indizi partendo dall'angolo in alto a sinistra e procedendo in senso orario. Quindi, prima gli indizi superiori leggono verso destra, poi gli indizi destra leggono verso il basso, quindi gli indizi inferiori leggono verso sinistra, gli indizi sinistri leggono verso l'alto.

Questo sarebbe 23145 34321 12222 33212per l'esempio precedente

       2 3 1 4 5    
       v v v v v

 2 >   4 3 5 2 1   < 3
 1 >   5 4 1 3 2   < 4
 2 >   1 5 2 4 3   < 3
 3 >   2 1 3 5 4   < 2
 3 >   3 2 4 1 5   < 1 

       ^ ^ ^ ^ ^
       2 2 2 2 1

Proprio come per l'input, è possibile utilizzare un elenco, una stringa o qualsiasi struttura ordinata. I quattro "gruppi" possono essere separati o meno, in una struttura nidificata o piatta. Tuttavia, il formato deve essere lo stesso per ciascun gruppo.

Esempi di test:

(Il formato di input / output non deve essere lo stesso di questi.)

>> [[1 2] [2 1]]

[2 1]
[1 2]
[2 1]
[1 2]

>> [[3 1 2] [2 3 1] [1 2 3]]

[1 2 2]
[2 2 1]
[1 2 3]
[3 2 1]

>> [[4 3 5 2 1] [5 4 1 3 2] [1 5 2 4 3] [2 1 3 5 4] [3 2 4 1 5]]

[2 3 1 4 5]
[3 4 3 2 1]
[1 2 2 2 2]
[3 3 2 1 2]

>> [[2 6 4 1 3 7 5 8 9] [7 2 9 6 8 3 1 4 5] [5 9 7 4 6 1 8 2 3] [6 1 8 5 7 2 9 3 4] [1 5 3 9 2 6 4 7 8] [3 7 5 2 4 8 6 9 1] [8 3 1 7 9 4 2 5 6] [9 4 2 8 1 5 3 6 7] [4 8 6 3 5 9 7 1 2]]

[4 2 2 3 3 3 3 2 1]
[1 3 3 2 2 2 2 3 3]
[4 3 2 1 2 3 3 2 2]
[3 1 2 4 3 3 2 2 5]

Per comodità, ecco gli stessi casi di test in formato stringa piatta.

>> 1221

21
12
21
12

>> 312231123

122
221
123
321

>> 4352154132152432135432415

23145
34321
12222
33212

>> 264137589729683145597461823618572934153926478375248691831794256942815367486359712

422333321
133222233
432123322
312433225

Risposte:


22

19 APL

≢¨∪/⌈\(⍉⍪⌽⍪⊖∘⌽∘⍉⍪⊖)

(golf un po 'di più dopo il suggerimento di ngn, grazie)

Spiegazione:

(⍉⍪⌽⍪⊖∘⌽∘⍉⍪⊖)  rotates matrix 4 times appending results
⌈\ gets maximums for each row up to current column (example: 4 2 3 5 1 gives 4 4 4 5 5)
≢¨∪/ counts unique elements for each row

Provalo su tryapl.org


1
Puoi evitare di aggiungere 1:≢¨∪¨↓⌈\(⍉⍪⌽⍪⍉∘⌽∘⊖⍪⊖)
ngn il

@ngn hai ragione, grazie! Ho anche applicato ∪ / quindi 1 carattere in meno :)
Moris Zucca il

Wow - questo è il tipo di sfida che APL eccelle.
isaacg,

12

Python 2, 115 byte

def T(m):o=[];exec'm=zip(*m)[::-1]\nfor r in m[::-1]:\n n=k=0\n for x in r:k+=x>n;n=max(x,n)\n o+=[k]\n'*4;return o

C'è un sacco di sfogliare l'elenco che sta succedendo lì dentro.

Accetta l'input come elenco nidificato (ad es. Chiama con T([[4,3,5,2,1],[5,4,1,3,2],[1,5,2,4,3],[2,1,3,5,4],[3,2,4,1,5]])). L'output è un unico elenco piatto.

Ungolfed:

def T(m):
 o=[]
 for _ in [0]*4:
  m=zip(*m)[::-1]
  for r in m[::-1]:
   n=k=0
   for x in r:k+=x>n;n=max(x,n)
   o+=[k]
 return o

Alternativa 115:

def T(m):o=[];exec'm=zip(*m)[::-1];o+=[len(set([max(r[:i+1])for i in range(len(r))]))for r in m[::-1]];'*4;return o

Non ho idea del motivo per cui questo funziona con una comprensione dell'elenco, ma getta un NameErrorcon una comprensione impostata ...

Un po 'troppo a lungo, ma se qualcuno è interessato - sì, è possibile arrivare a una lambda!

T=lambda m:[len({max(r[:i+1])for i in range(len(r))})for k in[1,2,3,4]for r in eval("zip(*"*k+"m"+")[::-1]"*k)[::-1]]

Pyth , 25 byte

V4=Q_CQ~Yml{meS<dhkUd_Q)Y

Porta Pyth obbligatoria.

Immettere l'elenco tramite STDIN, ad es [[4, 3, 5, 2, 1], [5, 4, 1, 3, 2], [1, 5, 2, 4, 3], [2, 1, 3, 5, 4], [3, 2, 4, 1, 5]].

Provalo online ... è quello che direi ma sfortunatamente, per motivi di sicurezza, l'interprete online non consente l'uso di eval tra parentesi nidificate. Prova JcQ5V4=J_CJ~Yml{meS<dhkUd_J)Yinvece il codice di soluzione alternativa e inserisci come un elenco appiattito come [4, 3, 5, 2, 1, 5, 4, 1, 3, 2, 1, 5, 2, 4, 3, 2, 1, 3, 5, 4, 3, 2, 4, 1, 5].

(Grazie a @isaacg che ha aiutato a giocare a golf a pochi byte)


Un paio di golf Pyth: <e >sono gli operatori di slice un lato, quindi :d0hkpossono essere trasformati in <dhk. Usugli input della raccolta è lo stesso di Ul, quindi Uldpuò essere trasformato in Ud.
isaacg,

@isaacg Grazie - sembra che il mio Pyth debba essere aggiornato. Il documento che ho è obsoleto.
Sp3000,

11

CJam, 29 27 byte

q~{z_{[{1$e>}*]_&,}%pW%}4*;

Inserisci come

[[4 3 5 2 1] [5 4 1 3 2] [1 5 2 4 3] [2 1 3 5 4] [3 2 4 1 5]]

Uscita come

[2 3 1 4 5]
[3 4 3 2 1]
[1 2 2 2 2]
[3 3 2 1 2]

Come funziona

L'idea di base è far funzionare il codice lungo le file e ruotare la griglia in senso antiorario 4 volte. Per contare le torri, sto sollevando ogni torre per quanto non faccia una "differenza visiva" (cioè, non cambiarla se è visibile, o tirarla fino alla stessa altezza della torre di fronte a esso), e quindi sto contando altezze distinte.

q~                          "Read and evaluate the input.";
  {                    }4*  "Four times...";
   z                        "Transpose the grid.";
    _                       "Duplicate.";
     {            }%        "Map this block onto each row.";
      [       ]             "Collect into an array.";
       {    }*              "Fold this block onto the row.";
        1$                  "Copy the second-to-topmost element.":
          e>                "Take the maximum of the top two stack elements.";
                            "This fold replaces each element in the row by the
                             maximum of the numbers up to that element. So e.g.
                             [2 1 3 5 4] becomes [2 2 3 5 5].";
               _&,          "Count unique elements. This is how many towers you see.";
                    p       "Print array of results.";
                     W%     "Reverse the rows for the next run. Together with the transpose at
                             the start this rotates the grid counter-clockwise.";
                          ; "Get rid of the grid so that it isn't printed at the end.";


5

J, 35 caratteri

(+/@((>./={:)\)"2@(|.@|:^:(<4)@|:))

Esempio:

   t=.4 3 5 2 1,. 5 4 1 3 2,. 1 5 2 4 3,. 2 1 3 5 4,. 3 2 4 1 5
   (+/@((>./={:)\)"2@(|.@|:^:(<4)@|:)) t
2 3 1 4 5
3 4 3 2 1
1 2 2 2 2
3 3 2 1 2

Provalo qui.


5

Haskell, 113

import Data.List
f(x:s)=1+f[r|r<-s,r>x]
f _=0
r=reverse
t=transpose
(?)=map
l s=[f?t s,(f.r)?s,r$(f.r)?t s,r$f?s]

4

Mathematica, 230.120.116.113 110 byte

f=(t=Table;a=#;s=Length@a;t[v=t[c=m=0;t[h=a[[y,x]];If[h>m,c++;m=h],{y,s}];c,{x,s}];a=Thread@Reverse@a;v,{4}])&

Uso:

f[{
  {4, 3, 5, 2, 1},
  {5, 4, 1, 3, 2},
  {1, 5, 2, 4, 3},
  {2, 1, 3, 5, 4},
  {3, 2, 4, 1, 5}
}]

{{2, 3, 1, 4, 5}, {3, 4, 3, 2, 1}, {1, 2, 2, 2, 2}, {3, 3, 2, 1, 2}}

a[[y]][[x]]lo è a[[y,x]]. E l'utilizzo Arraypotrebbe essere più breve di Table.
Martin Ender,

4

JavaScript, 335 264 256 213

T=I=>((n,O)=>(S=i=>i--&&O.push([])+S(i)+(R=(j,a,x)=>j--&&R(j,0,0)+(C=k=>k--&&((!(a>>(b=I[(F=[f=>n-k-1,f=>j,f=>k,f=>n-j-1])[i]()][F[i+1&3]()])))&&++x+(a=1<<b))+C(k))(n)+O[i].push(x))(n,0,0))(4)&&O)(I.length,[],[])

Valuta nella console JavaScript del browser (ho usato Firefox 34.0, non sembra funzionare in Chrome 39 ??) Prova con:

JSON.stringify(T([[4, 3, 5, 2, 1], [5, 4, 1, 3, 2], [1, 5, 2, 4, 3], [2, 1, 3, 5, 4], [3, 2, 4, 1, 5]]));

Ecco l'attuale incarnazione del codice non golfato: diventa sempre più difficile seguirlo:

function countVisibleTowers(input) {
  return ((n, out) =>
      (sideRecurse = i =>
          i-- &&
          out.push([]) +
          sideRecurse(i) +
          (rowRecurse = (j, a, x) =>
              j-- &&
              rowRecurse(j, 0, 0) +
              (columnRecurse = k =>
                  k-- &&
                  ((!(a >> (b = input[
                                        (offsetFtn = [
                                            f => n - k - 1,   // col negative
                                            f => j,           // row positive
                                            f => k,           // col positive
                                            f => n - j - 1    // row negative
                                        ])[i]()
                                     ]
                                     [
                                        offsetFtn[i + 1 & 3]()
                                     ]))) &&
                  ++x +
                  (a = 1 << b)) +
                  columnRecurse(k)
              )(n) +
              out[i].push(x)
          )(n, 0, 0)
      )(4) && out
  )(input.length, [], [])
}

Non ho intenzionalmente guardato nessuna delle altre risposte, volevo vedere se potevo risolvere qualcosa da solo. Il mio approccio è stato quello di appiattire gli array di input in un array monodimensionale e pre-calcolare gli offset delle righe da tutte e quattro le direzioni. Quindi ho usato lo spostamento a destra per verificare se la torre successiva era falsa e se lo fosse, quindi incrementare il contatore per ogni riga.

Spero che ci siano molti modi per migliorare questo, forse non precalcolare gli offset, ma piuttosto utilizzare una sorta di overflow / modulo sull'array di input 1D? E forse unire i miei loop, diventare più funzionale, deduplicare.

Tutti i suggerimenti sarebbero apprezzati!

Aggiornamento n. 1 : Progresso, abbiamo la tecnologia! Sono stato in grado di liberarmi degli offset precalcolati e di farli in linea con operatori ternari messi insieme. Inoltre è stato in grado di eliminare la mia istruzione if e convertire i cicli for in whiles.

Aggiornamento n. 2 : è piuttosto frustrante; niente pizza party per me. Ho pensato che andare funzionante e usare la ricorsione avrebbe rasato molti byte, ma i miei primi tentativi hanno finito per essere più grandi di ben 100 caratteri! In preda alla disperazione, ho usato a fondo le funzioni della freccia grassa ES6 per abbatterlo davvero. Poi ho preso la sostituzione di operatori booleani con operatori aritmetici e la rimozione di parentesi, punti e virgola e spazi dove possibile. Ho persino smesso di dichiarare i miei vars e inquinato lo spazio dei nomi globale con i miei simboli locali. Sporco, sporco Dopo tutto questo sforzo, ho battuto il mio punteggio di aggiornamento n. 1 di un enorme 8 caratteri, fino a 256. Blargh!

Se avessi applicato le stesse spietate ottimizzazioni e trucchi ES6 alla mia funzione di aggiornamento n. 1, avrei battuto questo punteggio di un miglio. Potrei fare un aggiornamento n. 3 solo per vedere come sarebbe.

Aggiornamento n. 3 : si scopre che l'approccio ricorsivo della freccia grassa aveva molta più vita, avevo solo bisogno di lavorare direttamente con l'input bidimensionale invece di appiattirlo e migliorare con la leva degli ambiti di chiusura. Ho riscritto due volte i calcoli di offset dell'array interno e ho ottenuto lo stesso punteggio, quindi questo approccio potrebbe essere vicino a quello eliminato!


3

Java, solo 352 350 325 byte ...

class S{public static void main(String[]a){int n=a.length,i=0,j,k,b,c;int[][]d=new int[n][n];for(;i<n;i++)for(j=0;j<n;)d[i][j]=a[i].charAt(j++);for(i=0;i<4;i++){int[][]e=new int[n][n];for(k=0;k<n;k++)for(j=0;j<n;)e[n-j-1][k]=d[k][j++];d=e;for(j=n;j-->(k=c=b=0);System.out.print(c))for(;k<n;k++)b=d[j][k]>b?d[j][k]+0*c++:b;}}}

Inserisci come 43521 54132 15243 21354 32415

Uscita come: 23145343211222233212

rientrato:

class S{
    public static void main(String[]a){
        int n=a.length,i=0,j,k,b,c;
        int[][]d=new int[n][n];
        for(;i<n;i++)
            for(j=0;j<n;)d[i][j]=a[i].charAt(j++);
        for(i=0;i<4;i++){
            int[][]e=new int[n][n];
            for(k=0;k<n;k++)
                for(j=0;j<n;)e[n-j-1][k]=d[k][j++];
            d=e;
            for(j=n;j-->(k=c=b=0);System.out.print(c))
                for(;k<n;k++)b=d[j][k]>b?d[j][k]+0*c++:b;
        }
    }
}

Eventuali suggerimenti sarebbero molto apprezzati!


hai qualche spazio bianco in più tra i forloop
orgoglioso haskeller il

@proud haskeller Grazie!
TheNumberOne,

Si potrebbe cambiare for(;i<n;i++)per for(;++i<n;)e inizializzare ia -1. Quindi usali per fare cose. Puoi fare lo stesso anche con l'altro loop.
orgoglioso haskeller il

È possibile utilizzare a[i].charAt(j)-'0'anziché l'analisi esplicita. Anche questo non richiede delimitatori nell'input (rende il formato di input più simile al formato di output).
Anatolyg,

Inoltre, in for-loops, puoi sempre aggiungere qualcosa di utile nella parte "incremento del ciclo". Questo rende il codice più oscuro e rimuove un punto e virgola. Ad esempio: for(j=n;j-->0;System.out.print(c)).
Anatolyg,

1

Python 2 - 204 byte

def f(l):n=len(l);k=[l[c]for c in range(n)if l[c]>([0]+list(l))[c]];return f(k)if k!=l else n
r=lambda m:(l[::-1]for l in m)
m=input();z=zip(*m);n=0
for t in z,r(m),r(z),m:print map(f,t)[::1-(n>1)*2];n+=1

Questo è probabilmente un golf davvero scadente. Ho pensato che il problema fosse interessante, quindi ho deciso di affrontarlo senza cercare la soluzione di nessun altro. Mentre scrivo questa frase, devo ancora guardare le risposte a questa domanda. Non sarei sorpreso se qualcun altro ha già fatto un programma Python più breve;)

Esempio di I / O

$ ./towers.py <<< '[[4,3,5,2,1],[5,4,1,3,2],[1,5,2,4,3],[2,1,3,5,4],[3,2,4,1,5]]'
[2, 3, 1, 4, 5]
[3, 4, 3, 2, 1]
[1, 2, 2, 2, 2]
[3, 3, 2, 1, 2]

È possibile includere facoltativamente spazi bianchi nell'input. Praticamente ovunque, onestamente. Finché puoi eval(), funzionerà.

Spiegazione

L'unica parte interessante di questo programma è la prima riga. Definisce una funzione f(l)che ti dice quante torri possono essere viste in fila, e il resto del programma sta semplicemente applicando quella funzione in ogni posizione possibile.

Quando viene chiamato, trova la lunghezza di le la salva in una variabile n. Quindi crea una nuova variabile kcon questa comprensione piuttosto mostruosa dell'elenco:

[l[c]for c in range(n)if l[c]>([0]+list(l))[c]]

Non è poi così male quando lo rompi. Da allora n==len(l), tutto ciò ifche rappresenta il giusto rappresenta l. Tuttavia, utilizzando ifpossiamo rimuovere alcuni elementi dall'elenco. Costruiamo un elenco con ([0]+list(l)), che è solo " lcon un 0aggiunto all'inizio" (ignora la chiamata a list(), è lì solo perché a volte lè un generatore e dobbiamo assicurarci che sia effettivamente un elenco qui). l[c]viene inserito nell'elenco finale solo se è maggiore di ([0]+list(l))[c]. Questo fa due cose:

  • Dato che c'è un nuovo elemento all'inizio dell'elenco, l'indice di ciascuno l[c]diventa c+1. Stiamo effettivamente confrontando ciascun elemento con l'elemento a sinistra di esso. Se è maggiore, è visibile. Altrimenti viene nascosto e rimosso dall'elenco.
  • La prima torre è sempre visibile perché non c'è nulla che possa bloccarla. Poiché mettiamo 0 all'inizio, la prima torre è sempre maggiore. (Se non abbiamo fatto questo [0]+senso e solo confrontato l[c]a l[c-1], Python sarebbe confrontare la prima torre per l'ultimo (si possono indicizzare in una lista dalla fine con -1, -2e così via), quindi, se l'ultima torre era più alto rispetto al prima avremmo ottenuto il risultato sbagliato.

Quando tutto è detto e fatto, lcontiene un certo numero di torri e kcontiene ognuna di quelle che non sono più corte del suo vicino immediato a sinistra. Se nessuno di loro fosse (ad esempio per f([1,2,3,4,5])), allora l == k. Sappiamo che non c'è più niente da fare e da restituire n(la lunghezza dell'elenco). Se l != k, ciò significa che almeno una delle torri è stata rimossa questa volta e potrebbe esserci altro da fare. Quindi, torniamo f(k). Dio, adoro la ricorsione. È interessante notare che frecluta sempre un livello più profondo di quanto sia strettamente "necessario". Quando viene generato l'elenco che verrà restituito, la funzione non ha modo di saperlo inizialmente.

Quando ho iniziato a scrivere questa spiegazione, questo programma era lungo 223 byte. Mentre spiegavo le cose mi sono reso conto che c'erano modi per salvare i personaggi, quindi sono contento di averlo scritto! Il più grande esempio è che f(l)originariamente era stato implementato come un ciclo infinito che era stato interrotto da quando il calcolo era stato fatto, prima che mi rendessi conto che la ricorsione avrebbe funzionato. Ciò dimostra che la prima soluzione che pensi non sarà sempre la migliore. :)


0

Matlab, (123) (119)

function r=m(h);p=[h rot90(h) rot90(h,2) rot90(h,3)];for i=2:size(p) p(i,:)=max(p(i,:),p(i-1,:));end;r=sum(diff(p)>0)+1

usato così:

m([
 4     3     5     2     1;
 5     4     1     3     2;
 1     5     2     4     3;
 2     1     3     5     4;
 3     2     4     1     5])

 [2 3 1 4 5 3 4 3 2 1 1 2 2 2 2 3 3 2 1 2]

C #, fino a 354 ...

Approccio diverso rispetto a TheBestOne.

using System;
using System.Linq;

class A
{
    static void Main(string[] h)
    {
        int m = (int)Math.Sqrt(h[0].Length),k=0;
        var x = h[0].Select(c => c - 48);
        var s = Enumerable.Range(0, m);
        for (; k < 4; k++)
        {
            (k%2 == 0 ? s : s.Reverse())
                .Select(j =>
                        (k > 0 && k < 3 ? x.Reverse() : x).Where((c, i) => (k % 2 == 0 ? i % m : i / m) == j)
                                                          .Aggregate(0, (p, c) =>
                                                                        c > p%10
                                                                            ? c + 10 + p/10*10
                                                                            : p, c => c/10))
                .ToList()
                .ForEach(Console.Write);
        }
    }
}

Sembra che tu incolli il computer \ninvece di newline, li ho appena sostituiti da spazi, quindi il codice viene eseguito immediatamente quando qualcuno lo sta copiando. E mi sono permesso di cancellare l'ultimo end(che chiude la funzione, che non è necessario) che salva altri 4 caratteri, spero che fosse ok =)
flawr,

Sembra che Matlab non fosse contento degli spazi, quindi li ho cambiati in punti e virgola. Un buon punto sul finale endperò, grazie :)
zabalajka,
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.