Dekoduj mapę cieplną

32

Heatmaps

Rozważmy prostokątny pokój, na którego suficie mamy kamerę termiczną skierowaną w dół. W pomieszczeniu znajduje się pewna liczba źródeł ciepła o intensywności 1-9, przy czym temperatura tła jest 0. Ciepło rozprasza się z każdego źródła, spadając o jedną jednostkę na (nie przekątny) stopień. Na przykład 20x10pokój

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

zawiera 9 źródeł ciepła, a gradient temperatury pokazywany przez kamerę termiczną wynosi

34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

W formie graficznej może to wyglądać następująco:

mapa termiczna 9 źródeł

Na podstawie gradientu możemy wywnioskować pozycje i natężenia niektórych źródeł ciepła, ale nie wszystkich. Na przykład, 9zawsze można wywnioskować wszystkie s, ponieważ mają one maksymalną temperaturę, podobnie jak 8w tym przypadku, ponieważ daje lokalne maksimum w gradiencie. 2Blisko prawej krawędzi można również wywnioskować, mimo że nie jest na lokalnym maksimum, ponieważ nie ma innego 2jak sąsiada. Z 5drugiej strony nie są one wywnioskowane, ponieważ ich ciepło równie dobrze mogłoby być wytwarzane przez bardziej intensywne źródła w ich pobliżu. Do 0s są znane zawierają żadnych źródeł ciepła, ale wszystkie inne płytki mogą potencjalnie zawierać jeden. Oznaczmy niepewne kafelki łącznikami-, niektóre źródła ciepła według odpowiednich cyfr i pewne puste miejsce według okresów .:

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

Twoim zadaniem będzie wytworzenie tego wywnioskowanego wzoru z gradientu temperatury.

Zasady

Dostajesz dane wejściowe jako ciąg rozdzielony znakami nowej linii lub pionowymi rurami |, w zależności od tego, który jest wygodniejszy, a dane wyjściowe powinny mieć taką samą formę. Na wejściu i / lub wyjściu może znajdować się ogranicznik końcowy, ale żaden poprzedni. Rozmiar danych wejściowych może się różnić, ale jego szerokość i wysokość są zawsze co najmniej 4. Zarówno funkcje, jak i pełne programy są dopuszczalne. Wygrywa najmniej bajtów, a standardowe luki są zabronione.

Dodatkowe przypadki testowe

Wkład:

898778765432100
787667654321100
677656543211210
678765432112321
567654321123210

który wygląda tak w formie graficznej:

przypadek testowy 1

Wydajność:

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

Wkład:

7898
8787
7676
6565

Wydajność:

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

Wkład:

00001
00000
00000
10000

Wydajność:

....1
.....
.....
1....
Zgarb
źródło
1
Czy masz coś przeciwko, jeśli dodam do twojego pytania 2 grafiki termiczne, jeśli uważasz, że dodają one wartości? To tylko 2-minutowy eksperyment.
Logic Knight
@CarpetPython Pewnie, śmiało. Wyglądają mi bardzo ładnie. Możesz również dodać „Dzięki uprzejmości CarpetPython”, aby uzyskać uznanie. ;)
Zgarb
2
Gotowy. Nie wymaga kredytu, ale pomyślałem, że niegrzecznie byłoby nie pytać przed edycją.
Logic Knight
Dlaczego nie zezwolić na wprowadzanie danych w postaci dwuwymiarowej tablicy zamiast ciągu?
feersum
@feersum ogólnie metody wprowadzania są spójne.
Optymalizator

Odpowiedzi:

10

CJam, 73 69 62 55 bajtów

AKTUALIZACJA : Nowy algorytm. Krótszy i większy zakres ulepszeń

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

Jak to działa

Logika jest podobna do poniższego algorytmu, ale tutaj nie sprawdzam wszystkich 4 sąsiadów w jednej iteracji. Zamiast tego używam mniejszego podejścia do iteracji po wszystkich wierszach i kolumnach w obu kierunkach. Oto kroki z tym związane:

  • Przekształć każdy znak w zestawy 5. Pierwsze 4 zostaną zmodyfikowane, aby stwierdzić, czy są większe niż sąsiednia komórka w rzędzie podczas iteracji. Ostatni służy do celów porównawczych.
  • Iteruj w każdym rzędzie i zmniejszaj w każdym rzędzie. Podczas redukcji mam dwa ciągi 5 znaków. Wiem, co to jest iteracja [0 dla wierszy normalnych, 1 kolumny odwrócone, 2 dla wierszy odwróconych i 3 dla kolumn normalnych] Aktualizuję i- ty znak w ciągu pierwszych 5 znaków i zmieniam go na 0, jeśli jest mniejszy niż drugi .
  • Po wszystkich 4 iteracjach, jeśli wszystkie 5 znaków jest takich samych i niezerowych, są to lokalne maksima. Odwzorowuję ciągi wszystkich 5 znaków i przekształcam je w jedną cyfrę .lub -.

Oto przykład uruchamiany na małym wejściu:

7898
8787
7676
6565

Po pierwszym kroku:

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

Po drugim kroku:

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

Po ostatnim mapowaniu na pojedynczy znak końcowy wynik:

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

Kod Objaśnienie :

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.";

Wypróbuj tutaj


Starsze podejście

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

Jak to działa

Logika jest prosta, iteruj po siatce i sprawdź, czy bieżąca wartość jest większa lub równa pozostałym czterem sąsiadom - w górę, w dół, w lewo i w prawo. Następnie przekształć bieżącą wartość na podstawie powyższej reguły, a jeśli wartość jest równa 0, ustaw ją na „.” .

Objaśnienie kodu

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";

Wypróbuj online tutaj

Optymalizator
źródło
5
Muszę powiedzieć, że rzadko słyszę „za długo” przy opisywaniu kodu 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('')

Przetestuj w konsoli 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'))

Wydajność

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


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


--9-
8---
----
----
edc65
źródło
4

Python 2: 154 bajty

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

Dane wejściowe muszą mieć formę "00001\n00000\n00000\n10000".

Konwersja ciągu znaków na macierz 2D jest dość długa w Pythonie. Więc zachowuję oryginalny format ciągu. Wyliczam ponad dane wejściowe, ijest indeksem, vjest char (w końcu wyliczam zapisane bajty w rozwiązaniu golfowym !!). Dla każdej pary (i,v)obliczam poprawny znak wyjściowy i dołączam do nich. Jak wybrać prawidłowy znak wyjściowy? Jeśli v == '\n', wyjściowy char jest \n, to v == '0'niż wyjściowy char jest '.'. W przeciwnym razie testuję 4 sąsiadów v, którzy są b[i-b.index('\n')-1](powyżej), b[i-1](po lewej, b[i+1](po prawej) i b[i+b.index('\n')+1](poniżej), jeśli są, <= vi wybieram znak '-'lubv. Tutaj porównuję znaki nie liczb, ale działa całkiem dobrze, ponieważ wartości ascii są w prawidłowej kolejności. Również nie ma problemów, jeśli b[i-1]lub b[i+1]równa '\n', ponieważ ord('\n') = 10.

Pyth: 61 58

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

Mniej więcej tłumaczenie skryptu Python. Dość brzydka ;-)

Wypróbuj online: Pyth Compiler / Executor Ten sam format wejściowy, co rozwiązanie 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
Jakube
źródło
4

Perl, 77, 75, 72 70

Standardowe sztuczki polegające na dopasowywaniu wyrażeń regularnych 2d.

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

Przykład:

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

Wypróbuj tutaj

nutki
źródło
3

Java, 307 , 304 , 303 , 299 298

Jest to z pewnością „idealne” wyzwanie dla niektórych kodegolfów 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]));}}}

Dane wejściowe (metoda „|” rury):

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

Wydajność:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
Rolf ツ
źródło
1
Może to być 288, jeśli usuniesz spację char[]r=a[0].replace("|", <--here"").toCharArray().
bcsb1001
1
Nie zauważyłem tego, dzięki! To sprawia, że ​​298
Rolf ツ
2

APL, 92

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

Przykład:

       ('.-',⎕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-------
marinus
źródło
Najdłuższy program APL, jaki kiedykolwiek widziałem. Warto zauważyć, że nie jest to standardowa APL, ponieważ używa ona dfns.
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}

Nic specjalnego; po prostu iteruj po mapie i porównaj bieżącą wartość z wartością czterech sąsiadów.

Uruchom online z testami: http://ideone.com/AQkOSY

Cristian Lupascu
źródło
1

R 223

O najlepszych, jakie mogę teraz wymyślić. Radzenie sobie ze sznurkiem jest dość drogie. Myślę, że jest miejsce na poprawę, ale w tej chwili jej nie widzę

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='')

Wynik testu

> 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-------
> 
MickyT
źródło
1

J - 69 bajtów

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

Przykłady:

   ([: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)jest to standardowy sposób określania ciągów w języku J. Równie dobrze możesz użyć |łańcuchów rozdzielanych (z końcowym |).

jpjacobs
źródło
1

Excel VBA - 426

To będzie rzadka okazja, że ​​VBA wygrywa dowolne gry w golfa kodowego, ale ponieważ to jest to, z czego najczęściej korzystam, fajnie się z nią bawić. Pierwsza linia jest obudową krawędzi, która wydłużyła to, niż wydaje się, że powinna być.

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

Liczba nie obejmuje początkowych białych wierszy.

Bawiłem się pomysłem wysłania danych wejściowych do arkusza i pracy stamtąd, ale myślę, że zapętlenie przekazywanego ciągu znak po znaku zapisuje kod.

Zadzwoń z natychmiastowego okna:

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

Dane wyjściowe (w oknie):

---------..1........|----------..........|---8-------......--.|----------......--2-|---------......-----|--------......------|-------......-------|.-----......-----6--|..---.......--------|...-.......-2-------
phrebh
źródło
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}

Możesz spróbować na ideone . Jeśli ktoś jest zainteresowany wyjaśnieniem, daj mi znać.

hmatt1
źródło
Myślę, że masz 226 znaków, a nie 227.
Cristian Lupascu
@ w0lf masz rację, nowa linia została policzona za 2, ponieważ jestem w systemie 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 jest funkcją, która przyjmuje ciąg znaków w formie 0001\n0000\n0000\n1000 i zwraca wymagany ciąg.

g to funkcja, która pobiera listę list znaków i zwraca listę list ((w lewo, w górę), to, (w prawo, w dół)).

Jmac
źródło