ヒートマップのデコード


32

ヒートマップ

天井に下向きのサーマルカメラがある長方形の部屋を考えます。部屋には、いくつかの強度の熱源があり1-9、背景温度は0です。熱は各ソースから放散され、(非対角線)ステップごとに1単位低下します。たとえば、20x10部屋

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

9つの熱源が含まれており、サーマルカメラによって示される温度勾配は

34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

グラフィカル形式では、これは次のようになります。

9つのソースのヒートマップ

勾配から、すべてではなく一部の熱源の位置と強度を推測できます。たとえば、すべて9のsは最高温度を持っているので、常に推測できます8。この場合は、勾配で極大値を生成するため、常に推測できます。2それは別のものを持っていないので、右の境界近くにも、それは地元の最大値ではないにもかかわらず、推測できる2隣人として。5その熱は同様にそれらの近くにより強い源によって生成される可能性がありますので、sが、一方で、推測されていません。0Sはない熱源を含まないことが知られているが、他のすべてのタイルができる潜在的なものを含みます。不確実なタイルをハイフンで示しましょう-、対応する数字による特定の熱源、および期間による特定の空きスペース.

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

あなたの仕事は、温度勾配からこの推測されたパターンを生成することです。

ルール

入力は、改行または垂直パイプの|どちらか適切な方で区切られた文字列として与えられ、出力は同じ形式になります。入力および/または出力に末尾の区切り文字がありますが、先行する区切り文字はありません。入力のサイズはさまざまですが、幅と高さは常に少なくとも4です。機能と完全なプログラムの両方が許容されます。最小のバイトカウントが優先され、標準の抜け穴は禁止されています。

追加のテストケース

入力:

898778765432100
787667654321100
677656543211210
678765432112321
567654321123210

グラフィカル形式では次のようになります。

テストケース1

出力:

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

入力:

7898
8787
7676
6565

出力:

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

入力:

00001
00000
00000
10000

出力:

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

1
付加価値があると思われる場合、質問に2つのヒートマップグラフィックを追加しても構いませんか?それらは2分間の実験です。
ロジックナイト

@CarpetPythonもちろんです。彼らは私にはとても似合います。「CarpetPythonの礼儀」を追加して、自分にクレジットを与えることもできます。;)
ズガルブ

2
できた クレジットは必要ありませんが、編集する前に質問しないのは失礼だと思いました。
ロジックナイト

入力を文字列ではなく2次元配列として許可しないのはなぜですか?
feersum

通常、@ feersumの入力メソッドは一貫しています。
オプティマイザー

回答:


10

CJam、73 69 62 55バイト

更新:新しいアルゴリズム。より短く、改善の余地がある

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

使い方

ロジックは以下のアルゴリズムに似ていますが、ここでは、1回の反復で4つすべての近傍をチェックしていません。代わりに、より小さなアプローチを使用して、すべての行と列を双方向に繰り返し処理します。手順は次のとおりです。

  • 各文字を5のセットに変換します。最初の4つは、反復中に行内の隣接セルよりも大きいかどうかを判断するために変更されます。最後は比較目的です。
  • 各行で繰り返し、各行で減らします。削減しながら、5文字の文字列が2つあります。どのような種類の反復があるかを知っています[通常行の場合は0、逆行の場合は1、逆行の場合は2、通常列の場合は3] 最初の5文字の文字列のi 番目の文字を更新し、2番目より小さい場合は0にします。
  • 4回の反復すべての後、5文字すべてが同じでゼロ以外の場合、それが局所的最大値です。5文字の文字列すべてをマップし、1桁の数字.またはに変換します-

以下は、小さな入力で実行される例です。

7898
8787
7676
6565

最初のステップの後:

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

2番目のステップの後:

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

単一文字への最後のマッピングの後、最終出力:

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

コードの説明

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

ここで試してみてください


古いアプローチ

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

使い方

ロジックは単純で、グリッドを反復処理して、現在の値が残りの4つの隣人(上、下、左、右)より大きいか等しいかどうかを確認します。次に、上記のルールに基づいて現在の値を変換し、値が0に等しい場合は「。」にします。。

コードの説明

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

こちらからオンラインでお試しください


5
私は言わなければならない、私はCJamコードを記述するときに「長すぎる」ということはめったに聞かない。
アレックス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('')

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

出力

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


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


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

4

Python 2:154バイト

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

入力はの形式でなければなりません"00001\n00000\n00000\n10000"

Pythonでは、文字列を2Dマトリックスに変換するのは非常に時間がかかります。したがって、元の文字列形式を保持します。入力を列挙し、iインデックス、vcharです(ゴルフソリューションで保存されたバイトを最後に列挙します!!)。各ペアについて(i,v)、出力の正しい文字を計算し、それらを結合します。正しい出力文字を選択するにはどうすればよいですか?場合はv == '\n'、出力charがある\n、それは、v == '0'出力charがあるよりも、'.'。そうでなければ私は4つの近隣テストvされ、b[i-b.index('\n')-1](上記)、(b[i-1]b[i+1](右)およびb[i+b.index('\n')+1]それらがある場合、()の下に<= v及びチャーを選択'-'またはv。ここでは数値ではなく文字を比較していますが、ASCII値が正しい順序であるため、非常にうまく機能します。また、等しいb[i-1]b[i+1]等しい場合'\n'、問題はありませんord('\n') = 10

ピス:61 58

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

多かれ少なかれ、Pythonスクリプトの翻訳。かなりい;-)

オンラインで試す:Pyth Compiler / Executor 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

標準の2D正規表現マッチングトリック。

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

例:

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

ここで試してみてください


3

Javaの、307304303299 298

これは確かにいくつかの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]));}}}

入力(パイプ「|」メソッド):

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

出力:

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

1
のスペースを削除すると、288になりますchar[]r=a[0].replace("|", <--here"").toCharArray()
bcsb1001

1
あれを見つけられなかった、ありがとう!まあ、これは298
ロルフツ

2

APL、92

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

例:

       ('.-',⎕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-------

私が見た中で最長のAPLプログラム。dfnsを使用するため、これは標準のAPLではないことに注意してください。
-FUZxxl

2

ルビー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}

特にない; マップを反復処理し、現在の値を4つの隣接する値と比較するだけです。

テストでオンラインで実行します:http : //ideone.com/AQkOSY


1

R、223

現時点で思いつく最高のものについて。文字列の処理は非常に高価です。改善の余地はあると思うが、現時点では見えない

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

テスト結果

> 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バイト

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

例:

   ([: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)は文字列を指定する標準的なJの方法です。|区切り文字列を使用することもできます(末尾に|)。


1

Excel VBA-426

VBAが任意のコードゴルフゲームで勝つことはまれですが、私が最もよく使用しているので、VBAで遊ぶのは楽しいです。最初の行は、必要以上に長くなったエッジケースです。

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

カウントには、最初の行の空白は含まれません。

入力をシートに送信してそこから作業するというアイデアで遊んでみましたが、渡された文字列を文字ごとにループすることでコードを節約できると思います。

イミディエイトウィンドウからの呼び出し:

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

出力(ウィンドウ内):

---------..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}

ideoneで試すことができます。誰かが説明に興味があるなら、私に知らせてください。


私はあなたが226文字ではなく、227持っていると思う
クリスティアンLupascu

@ w0lfそのとおりです。Windowsを使用しているので、改行は2カウントされます。
hmatt1

1

ハスケル-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は、フォーム内の文字列を受け取り0001\n0000\n0000\n1000、必要な文字列を返す機能です。

g は、文字のリストのリストを取り、((左、上)、これ、(右、下))のリストのリストを返す関数です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.