Decodifica una mappa di calore


32

heatmaps

Considera una stanza rettangolare, sul cui soffitto abbiamo una termocamera rivolta verso il basso. Nella stanza ci sono un certo numero di fonti di calore di intensità 1-9, essendo la temperatura di fondo 0. Il calore si dissipa da ogni fonte, scendendo di un'unità per passo (non diagonale). Ad esempio, la 20x10stanza

...........1........
....................
...8................
..5...............2.
....................
.1..................
................1...
.................65.
....................
............2.......

contiene 9 fonti di calore e il gradiente di temperatura mostrato dalla termocamera è

34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

In forma grafica questo potrebbe apparire come:

mappa di calore di 9 fonti

Dal gradiente, possiamo dedurre le posizioni e le intensità di alcune fonti di calore, ma non tutte. Ad esempio, tutti gli 9s possono sempre essere dedotti, poiché hanno la temperatura massima, e anche 8in questo caso, poiché produce un massimo locale nel gradiente. Si 2può anche dedurre il confine vicino alla destra, anche se non è al massimo locale, poiché non ne ha un altro 2come vicino. Le 5s, d'altra parte, non sono dedotte, poiché il loro calore potrebbe anche essere prodotto dalle fonti più intense vicino a loro. È 0noto che le s non contengono fonti di calore, ma tutte le altre tessere possono potenzialmente contenerne una. Indichiamo le piastrelle incerte di trattini-, determinate fonti di calore in base alle cifre corrispondenti e determinati spazi vuoti per periodi .:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Il tuo compito sarà quello di produrre questo schema inferito dal gradiente di temperatura.

Regole

|Viene fornito l'input come stringa delimitata da newline o pipe verticali , a seconda di quale sia più conveniente e l'output deve avere la stessa forma. Potrebbe esserci un delimitatore finale nell'input e / o output, ma nessuno precedente. La dimensione dell'input può variare, ma la sua larghezza e altezza sono sempre almeno 4. Sono accettabili sia funzioni che programmi completi. Vince il conteggio di byte più basso e sono vietate le scappatoie standard.

Casi di prova aggiuntivi

Ingresso:

898778765432100
787667654321100
677656543211210
678765432112321
567654321123210

che assomiglia a questo in forma grafica:

test case 1

Produzione:

-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.

Ingresso:

7898
8787
7676
6565

Produzione:

--9-
8---
----
----

Ingresso:

00001
00000
00000
10000

Produzione:

....1
.....
.....
1....

1
Ti dispiace se aggiungo 2 grafici heatmap alla tua domanda se pensi che aggiungano valore? Sono solo un esperimento di 2 minuti.
Logic Knight,

@CarpetPython Certo, vai avanti. Mi stanno molto bene. Puoi anche aggiungere un "Per gentile concessione di CarpetPython" per darti il ​​merito. ;)
Zgarb,

2
Fatto. Nessun credito richiesto, ma ho pensato che sarebbe stato scortese non chiedere prima della modifica.
Logic Knight,

Perché non consentire l'input come array bidimensionale anziché come stringa?
feersum

@feersum generalmente i metodi di input sono coerenti.
Ottimizzatore,

Risposte:


10

CJam, 73 69 62 55 byte

AGGIORNAMENTO : nuovo algoritmo. Più breve e più possibilità di miglioramento

qN/5ff*{{[{_@_@<{I'0t}*\}*]W%}%z}4fI{):X-'-X~X'.??}f%N*

Come funziona

La logica è simile all'algoritmo di seguito, ma qui non sto controllando tutti e 4 i vicini in un'unica iterazione. Invece, uso un approccio più piccolo per scorrere tutte le righe e le colonne in entrambe le direzioni. Ecco i passaggi coinvolti:

  • Converti ogni personaggio in set di 5. I primi 4 saranno modificati per dire se sono più grandi della cella adiacente nella riga durante l'iterazione. L'ultimo è a scopo di confronto.
  • Scorrere su ciascuna riga e ridurre su ciascuna riga. Riducendo, ho due stringhe da 5 caratteri. So che tipo di iterazione è [0 per le righe normali, 1 colonne invertite, 2 per le righe invertite e 3 per le colonne normali] aggiorno l'i- esimo carattere nella prima stringa di 5 caratteri e lo faccio 0 se è più piccolo del secondo .
  • Dopo tutte e 4 le iterazioni, se tutti e 5 i caratteri sono uguali e diversi da zero, questo è il massimo locale. Eseguo il mapping di tutte le stringhe di 5 caratteri e le converto in una singola cifra .o -.

Ecco un esempio eseguito su un piccolo input:

7898
8787
7676
6565

Dopo il primo passo:

["77777" "88888" "99999" "88888"
 "88888" "77777" "88888" "77777"
 "77777" "66666" "77777" "66666"
 "66666" "55555" "66666" "55555"]

Dopo il secondo passo:

["00777" "08888" "99999" "88088"
 "88888" "07007" "88808" "77007"
 "77707" "06006" "77707" "66006"
 "66606" "05005" "66606" "55005"]

Dopo l'ultima mappatura su singolo carattere, output finale:

--9-
8---
----
----

Spiegazione del codice :

qN/5ff*                         "Split the input on new line and convert each character";
                                "to string of 5 of those characters.";
{{[{             }*]W%}%z}4fI   "This code block runs 4 times. In each iteration, it";
                                "maps over each row/column and then for each of them,";
                                "It reduce over all elements of the row/column";
                                "Using combination of W% and z ensures that both rows and";
                                "columns are covered and in both directions while reducing";
    _@_@                        "Take a copy of last two elements while reducing over";
        <                       "If the last element is bigger than second last:";
         {I'0t}*\               "Convert the Ith character of the 5 char string of"
                                "second last element to 0";
                                "We don't have to compare Ith character of last two 5 char";
                                "string as the smaller one will be having more leading";
                                "0 anyways. This saves 4 bytes while comparing elements";
{):X-'-X~X'.??}f%N*             "This part of code converts the 5 char back to single char";
 ):X                            "Remove the last character and store in X. This last char";
                                "was not touched in the prev. loop, so is the original char";
    -                           "Subtract X from remaining 4 char. If string is not empty";
                                "then it means that it was not all same characters";
                                "In other words, this character was smaller then neighbors";
     '-      ?                  "If non-empty, then replace with - else ...";
       X~X'.?                   "if int(X) is zero, put . else put X";
               f%N*             "The mapping code block was run for each row and then";
                                "The rows are joined by newline.";

Provalo qui


Approccio precedente

qN/~_,):L0s*]0s*:Q_,{QI=:A[W1LL~)]If+Qf=$W=<'-A?A~\'.?I\t}fIL/W<Wf<N*

Come funziona

La logica è semplice, scorrere la griglia e vedere se il valore corrente è maggiore o uguale ai restanti quattro vicini: su, giù, sinistra e destra. Quindi trasforma il valore corrente in base alla regola sopra e se il valore è uguale a 0, rendilo "." .

Spiegazione del codice

qN/~_,):L0s*]0s*:Q         "This part of code pads the grid with 0s";
qN/~                       "Read the input, split on new lines and unwrap the arrays";
    _,):L                  "Copy the last row, taken length, increment and store in L";
         0s*               "Get L length 0 string";
            ]0s*           "Wrap everything in an array and join the rows by 0";
                :Q         "Store this final single string in Q";

_,{        ...      }fI    "Copy Q and take length. For I in 0..length, execute block";
   QI=:A                   "Get the I'th element from Q and store in A";
   [WiLL~)]If+             "This creates indexes of all 4 neighboring cells to the Ith cell";
              Qf=          "Get all 4 values on the above 4 indexes";
                 $W=       "Sort and get the maximum value";
<'-A?                      "If the current value is not the largest, convert it to -";
     A~\'.?                "If current value is 0, convert it to .";
           I\t             "Update the current value back in the string";
{ ... }fIL/                "After the loop, split the resulting string into chunks of L";
           W<Wf<           "Remove last row and last column";
                N*         "Join by new line and auto print";

Provalo online qui


5
Devo dire che raramente sento "troppo a lungo" quando descrivo il codice CJam.
Alex A.

6

JavaScript (ES6) 99

F=h=>[...h].map((c,i)=>[o=~h.search('\n'),-o,1,-1].some(d=>h[d+i]>c)&c>0?'-':c=='0'?'.':c).join('')

Test nella console di Firefox / FireBug

console.log(F('\
34565432100100000000\n\
45676543210000000000\n\
56787654321000000110\n\
45676543210000001221\n\
34565432100000012321\n\
23454321000000123432\n\
12343210000001234543\n\
01232100000012345654\n\
00121000000011234543\n\
00010000000121123432\n'),'\n\n',
F('\
898778765432100\n\
787667654321100\n\
677656543211210\n\
678765432112321\n\
567654321123210\n'), '\n\n',
F('7898\n8787\n7676\n6565\n'))

Produzione

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------


-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.


--9-
8---
----
----

4

Python 2: 154 byte

b=input()
l=b.index('\n')+1
print''.join(('\n.'+('-'+v)[all([v>=b[j]for j in i-l,i-1,i+l,i+1if 0<=j<len(b)])])[('\n0'+v).index(v)]for i,v in enumerate(b))

L'input deve essere nella forma "00001\n00000\n00000\n10000".

La conversione di una stringa in una matrice 2D è piuttosto lunga in Python. Quindi mantengo il formato stringa originale. Elenco per l'input, iè l'indice, vè il carattere (infine enumerare i byte salvati in una soluzione golf !!). Per ogni coppia (i,v)computo il carattere corretto di output e li unisco. Come faccio a scegliere il carattere di output corretto? Se v == '\n', il carattere di output è \n, allora v == '0', rispetto al carattere di output è '.'. Altrimenti collaudo i 4 vicini di v, che sono b[i-b.index('\n')-1](sopra), b[i-1](sinistra, b[i+1](destra) e b[i+b.index('\n')+1](sotto), se lo sono <= ve scelgo il carattere '-'ov. Qui sto confrontando i caratteri non i numeri, ma funziona abbastanza bene, perché i valori ASCII sono nell'ordine corretto. Inoltre non ci sono problemi, se b[i-1]o b[i+1]uguali '\n', perché ord('\n') = 10.

Pyth: 61 58

JhxQbVQK@QN~k@++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)Kx+b\0K)k

Più o meno una traduzione dello script Python. Abbastanza brutto ;-)

Provalo online: Pyth Compiler / Executor Stesso formato di input della soluzione Python.

JhxQb      Q = input()
  xQb      Q.index('\n')
 h         +1
J          store in J

VQK@QN~k.....)k   k is initialized as empty string
VQ           )    for N in [0, 1, 2, ..., len(Q)-1]:
  K@QN                K = Q[n]
      ~k              k += ... (a char, computed in the next paragraph)
             )    end for
              k   print k

@...x+b\0K   ... is a char of len 3 (is constructed below)
     +b\0    the string "\n0"
    x    K   find Q[d] in this string and return index, if not found -1
@...         lookup in string at the computed position (this is done mod 3 automatically!)

++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)K   not to the string
                       [tNhN-NJ+NJ)    the list [d-1, d+1, d-J, d+j]
        f                              filter the list for indices T which
           gT0                            T >= 0
          &                               and
              <TlQ                        T < len(Q)
         &                                and
                  <K@QT                   Q[d] < Q[T]
     ?\-                           K   use "-" if len(filter) > 0 else Q[d]
                                       this creates the third char
++b\.                                  "\n" + "." + third char

4

Perl, 77, 75, 72 70

Trucchi di corrispondenza regex standard 2d.

#!perl -p0
/
/;$x="(.{@-})?";y/0/./while s/$.$x\K$"|$"(?=$x$.)/-/s||($"=$.++)<9

Esempio:

$ perl heat.pl <in.txt
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Provalo qui


3

Java, 307 , 304 , 303 , 299 298

Questa è sicuramente una sfida "perfetta" per alcuni codegolf Java :)

class M{public static void main(String[]a){int c=a[0].indexOf('|'),i=c,d,v;char[]r=a[0].replace("|","").toCharArray(),m=new char[(v=r.length+c)+c];for(;i<v;){m[i]=r[i++-c];}for(i=c;i<v;i++){a[0]=i%c<1?"\n":"";d=m[i];System.out.print(a[0]+(d<49?'.':m[i-c]>d|m[i+c]>d|m[i-1]>d|m[i+1]>d?'-':m[i]));}}}

Input (metodo pipe | |):

34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432

Produzione:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

1
Questo può essere 288 se si rimuove lo spazio in char[]r=a[0].replace("|", <--here"").toCharArray().
bcsb1001,

1
Non l'ho individuato, grazie! Bene, questo fa 298
Rolf ツ

2

APL, 92

('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]

Esempio:

       ('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Il programma APL più lungo che abbia mai visto. Si consiglia di notare che questo non è APL standard in quanto utilizza i DNS.
FUZxxl,

2

Ruby 140

f=->s{
r=s.dup
l=s.index(?\n)+1
(0...s.size).map{|i|
s[i]<?0||r[i]=r[i]<?1??.:[i-1,i+1,i-l,i+l].map{|n|n<0??0:s[n]||?0}.max>r[i]??-:s[i]}
r}

Niente di speciale; basta scorrere la mappa e confrontare il valore corrente con il valore dei quattro vicini.

Eseguilo online con i test: http://ideone.com/AQkOSY


1

R, 223

Per quanto riguarda il meglio che posso trovare al momento. Trattare con la corda è piuttosto costoso. Penso che ci siano margini di miglioramento, ma al momento non riesco a vederlo

s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')

Risultato del test

> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 898778765432100|787667654321100|677656543211210|678765432112321|567654321123210
2: 
Read 1 item
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432
2: 
Read 1 item
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
> 

1

J - 69 byte

[:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2

Esempi:

   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432
)
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
898778765432100
787667654321100
677656543211210
678765432112321
567654321123210
)
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.

PS: (0 : 0)è il modo J standard per specificare le stringhe. Puoi anche usare |stringhe delimitate (con un finale |).


1

Excel VBA - 426

Sarà una rara occasione in cui VBA vince qualsiasi gioco di golf, ma dato che è quello che utilizzo di più, è divertente giocarci. La prima riga è un caso limite che lo ha reso più lungo di quanto dovrebbe essere.

Sub m(a)
    b = InStr(a, "|")
    For i = 1 To Len(a)
        t = Mid(a, i, 1)
        Select Case t
            Case "|"
                r = r & "|"
            Case 0
                r = r & "."
            Case Else
                On Error Resume Next
                x = Mid(a, i - 1, 1)
                y = Mid(a, i + 1, 1)
                Z = Mid(a, i + b, 1)
                If i < b Then
                    If t < x Or t < y Or t < Z Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                Else
                    If t < x Or t < y Or t < Z Or t < Mid(a, i - b, 1) Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                End If
        End Select
    Next
    MsgBox r
End Sub

Il conteggio non include gli spazi bianchi della riga iniziale.

Ho giocato con l'idea di inviare l'input a un foglio e lavorare da lì, ma penso che il looping della stringa passata carattere per carattere salva il codice.

Chiama dalla finestra immediata:

m "34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432"

Output (in una finestra):

---------..1........|----------..........|---8-------......--.|----------......--2-|---------......-----|--------......------|-------......-------|.-----......-----6--|..---.......--------|...-.......-2-------

1

Perl - 226

sub f{for(split'
',$_[0]){chomp;push@r,r($_);}for(t(@r)){push@y,r($_)=~s/0/./gr}$,=$/;say t(@y);}sub r{$_[0]=~s/(?<=(.))?(.)(?=(.))?/$1<=$2&&$3<=$2?$2:$2eq'0'?0:"-"/ger;}sub t{@q=();for(@_){for(split//){$q[$i++].=$_;}$i=0;}@q}

Puoi provarlo su ideone . Se qualcuno è interessato a una spiegazione, fammi sapere.


Penso che tu abbia 226 caratteri, non 227.
Cristian Lupascu,

@ w0lf hai ragione, la nuova riga è stata contata per 2 poiché sono su Windows.
hmatt1,

1

Haskell - 193

z='0'
r=repeat z
g s=zipWith3(\u t d->zip3(zip(z:t)u)t$zip(tail t++[z])d)(r:s)s$tail s++[r]
f=unlines.map(map(\((l,u),t,(r,d))->case()of _|t==z->'.'|maximum[u,l,t,r,d]==t->t|0<1->'-')).g.lines

fè una funzione che accetta una stringa nel modulo 0001\n0000\n0000\n1000e restituisce la stringa richiesta.

g è una funzione che accetta un elenco di elenchi di caratteri e restituisce un elenco di elenchi di ((sinistra, su), questo, (destra, giù)).

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.