いくつの塔が見えますか?


29

この質問は、オンラインでプレイできる番号配置パズルタワー(スカイスクレイパーとも呼ばれます)に基づいています。あなたの目標は、パズルの解決策を見つけて、手がかり(各行と列に沿って見える塔の数)を決定することです。これはコードゴルフなので、バイト数が最も少なくなります。

タワーの仕組み

-タワーパズルの解決策は、ラテン方陣であるn*nすべての行と列が数字の順列を含有するグリッド1を介しn。例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 

各行と列には、両端に次のような手がかりが付いています。

       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

各手がかりから数である1n、その数字は、その高さの塔として扱われる場合は、その方向からの行/列に沿って見て「を参照してください」どのように多くの塔を示します。各タワーは、背後にある短いタワーをブロックします。言い換えれば、あなたが見ることができる塔は、それらの前のどの塔よりも高い塔です。

Conceptisパズルからの画像

たとえば、最初の行を見てみましょう。

 2 >   4 3 5 2 1   < 3

それはの手がかりがある2あなたが見ることができるので、左からを4して54ブロック3からの光景と5他のブロックのすべて。右から、あなたが見ることができます3:塔を125

プログラム要件

数字のグリッドを取り込んで、左上から時計回りに手がかりを出力または印刷するプログラムまたは関数を作成します。

入力

n*nラテン方格2<=n<=9

形式は柔軟です。数字または数字を含むグリッドまたはリストを表す任意のデータ構造を使用できます。行間にセパレーターが必要な場合や、セパレーターがまったく必要ない場合があります。いくつかの可能性は、リスト、リストのリスト、マトリックス、トークンで区切られた文字列です

43521 54132 15243 21354 32415,

またはスペースなしの文字列。

あなたはn入力の一部として与えられていません。

出力

手がかりを左上から時計回りに戻すか、印刷します。したがって、最初に上の手がかりが右向きに読み、次に右の手がかりが下向きに読み、次に下の手がかりが左向きに読み、左の手がかりが上向きに読みます。

これは23145 34321 12222 33212前の例になります

       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

入力と同様に、リスト、文字列、または任意の順序付けられた構造を使用できます。4つの「グループ」は、ネスト構造またはフラット構造で分離することも、分離しないこともできます。ただし、形式は各グループで同じである必要があります。

テストケースの例:

(入力/出力形式はこれらと同じである必要はありません。)

>> [[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]

便宜上、フラット文字列形式の同じテストケースを以下に示します。

>> 1221

21
12
21
12

>> 312231123

122
221
123
321

>> 4352154132152432135432415

23145
34321
12222
33212

>> 264137589729683145597461823618572934153926478375248691831794256942815367486359712

422333321
133222233
432123322
312433225

回答:


22

APL 19

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

(NGNの提案の後、もう少しゴルフをしました、ありがとう)

説明:

(⍉⍪⌽⍪⊖∘⌽∘⍉⍪⊖)  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

tryapl.orgで試してください


1
あなたは1を加えることを避けることができます:≢¨∪¨↓⌈\(⍉⍪⌽⍪⍉∘⌽∘⊖⍪⊖)
NGN

@ngnあなたは正しい、ありがとう!また、applied /を適用したため、1文字少なくなりました:)
Moris Zucca 14

うわー-これはAPLが得意とする一種の課題です。
isaacg 14

12

Python 2、115バイト

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

そこには非常に多くのリスト反転があります。

ネストされたリストとして入力を受け取ります(例:で呼び出し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]]))。出力は単一のフラットリストです。

ゴルフをしていない:

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

代替案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

私はこれがリストの理解で機能する理由がNameErrorわかりませんが、セットの理解でチャックします...

少し長すぎますが、誰かが興味を持っているなら、はい、これをラムダに落とすことは可能です!

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

V4=Q_CQ~Yml{meS<dhkUd_Q)Y

必須のPythポート。

STDIN経由でリストを入力します(例:)[[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]]

それをオンラインで試してみてください ...私が言うことですが、残念なことに、セキュリティ上の理由から、オンラインインタープリターはネストされた括弧でのevalの使用を許可していません。JcQ5V4=J_CJ~Yml{meS<dhkUd_J)Y代わりに回避策のコードを試して、のようなフラット化されたリストとして入力してください[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]

(数バイトのゴルフを手伝ってくれた@isaacgに感謝)


いくつかのPythゴルフ:<>は片側スライスオペレーターなので、:d0hkに変換できます<dhkUコレクションの入力はと同じなのでUlUldに変換できますUd
isaacg 14

@isaacgありがとう-私のPythを更新する必要があるようです。私が持っているドキュメントは古くなっています。
Sp3000 14

11

CJam、29 27バイト

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

のような入力

[[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]

使い方

基本的な考え方は、コードを行に沿って機能させ、グリッドを反時計回りに4回回転させることです。タワーを数えるために、「視覚的な違い」が生じない範囲で各タワーを上げています(つまり、見える場合は変更しないでください。それ)、そして私は明確な高さを数えています。

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




4

Mathematica、230,120,116,113 110バイト

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}])&

使用法:

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]]ですa[[y,x]]。そして、使用Arrayするよりも短いかもしれませんTable
マーティンエンダー14

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,[],[])

ブラウザのJavaScriptコンソールで評価します(Firefox 34.0を使用しましたが、Chrome 39では動作しないようです??):

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

これが現在の未改変コードの化身です-従うのが難しくなっています:

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, [], [])
}

私は意図的に他の答えを調べませんでした。自分で何かを解決できるかどうかを見たかったのです。私のアプローチは、入力配列を1次元配列に平坦化し、4方向すべてからの行へのオフセットを事前計算することでした。次に、右シフトを使用して、次のタワーが偽造されているかどうかをテストし、偽造されている場合は、各行のカウンターをインクリメントします。

私はこれを改善する方法がたくさんあることを望んでいます、おそらくオフセットを事前に計算するのではなく、1D入力配列で何らかのオーバーフロー/モジュロを使用しますか?そして、おそらく私のループを組み合わせて、より機能的で重複排除を行います。

任意の提案をいただければ幸いです!

更新#1:進捗状況、技術があります!事前に計算されたオフセットを取り除き、三項演算子を一緒に並べてインラインで行うことができました。また、ifステートメントを削除し、forループをwhileに変換することもできました。

アップデート#2:これはかなりイライラします。私にはピザパーティーはありません。私は機能的になり、再帰を使用すると多くのバイトを削ることができると考えましたが、最初の数回の試行は100文字も大きくなりました!必死になって、私はES6の太い矢印関数を使用して、それを実際に削減しました。その後、ブール演算子を算術演算子に置き換え、可能な限り括弧、セミコロン、スペースを削除しました。varsの宣言をやめ、ローカルシンボルでグローバル名前空間を汚染しました。汚い、汚い。すべての努力の後、私はUpdate#1スコアをなんと8文字、256まで下げました。ブラー!

Update#1関数に同じ冷酷な最適化とES6トリックを適用した場合、このスコアを1マイルも上回ることになります。それがどのように見えるかを確認するためだけに、アップデート#3を行うかもしれません。

更新#3:太い矢印の再帰的アプローチには多くの寿命があったことが判明しました。2次元入力を平坦化するのではなく、直接操作し、クロージャースコープを活用することで改善する必要がありました。内側の配列オフセットの計算を2回書き直して同じスコアを得たので、このアプローチは間近に迫っています。


3

Java、のみ 352 350 325バイト...

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

のような入力 43521 54132 15243 21354 32415

次のような出力: 23145343211222233212

インデント:

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

ヒントは大歓迎です!


forループ間にいくつかの余分な空白があります
誇りに思ってhaskeller 14

@proud haskellerありがとうございます!
TheNumberOne

あなたは、変更される可能性for(;i<n;i++)for(;++i<n;)して初期化iします-1。次に、これらを使用して作業を行います。他のループでも同じことができます。
誇りに思ってhaskeller 14

a[i].charAt(j)-'0'明示的な解析の代わりに使用できます。また、これは入力に区切り文字を必要としません(入力形式を出力形式のようにします)。
アナトリグ14

また、for-loopsでは、「ループ増分」部分に有用なものをいつでも詰めることができます。これにより、コードがより不明瞭になり、セミコロンが1つ削除されます。例:for(j=n;j-->0;System.out.print(c))
アナトリグ14

1

Python 2-204バイト

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

これはおそらく本当に悪いゴルフです。私はこの問題が面白いと思ったので、他の誰かの解決策を見ずに取り組むことにしました。この文を入力するとき、この質問に対する答えをまだ見ていない。他の誰かがすでに短いPythonプログラムをすでに実行していても、私は驚かないでしょう;)

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]

オプションで入力に空白を含めることができます。ほとんどどこでも、正直に。できる限り機能しますeval()

説明

このプログラムの唯一の興味深い部分は、最初の行です。これは、f(l)連続していくつの塔を見ることができるかを示す関数を定義し、プログラムの残りの部分は、すべての可能な位置にその関数を適用しています。

呼び出されると、の長さを見つけてl変数に保存しますn。次にk、この非常に巨大なリスト内包表記を使用して新しい変数を作成します。

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

分解してもそれほど悪くはありません。以来n==len(l)ifちょうど前のすべてが表しlます。ただし、使用ifすると、リストからいくつかの要素を削除できます。私たちは、とリストの構築([0]+list(l))「だけである、l0先頭に追加する」(への呼び出しを無視list()時にはので、そこだけだ、l発電機であるが、我々はそれがここで実際にリストだことを確認する必要があります)。l[c]は、より大きい場合にのみ最終リストに入れられ([0]+list(l))[c]ます。これは2つのことを行います。

  • リストの先頭に新しい要素があるため、それぞれのインデックスはにl[c]なりc+1ます。各要素をその左側の要素と効果的に比較しています。大きい場合は表示されます。それ以外の場合は非表示になり、リストから削除されます。
  • 最初の塔は、それをブロックできるものがないため、常に表示されています。最初に0を入力するため、最初の塔は常に大きくなります。我々はこのしなかった場合([0]+ナンセンスとだけ比較l[c]l[c-1]て、Pythonは端からリストにすることができます(最後の1へのインデックスを最初の塔を比較するだろう-1-2など)、その最後の塔がより背が高いだった場合まず、間違った結果が得られます。

すべてを言いl終えると、いくつかの塔kが含まれ、左隣の塔よりも短くない塔がそれぞれ含まれます。それらのどれも(用などなかった場合はf([1,2,3,4,5])、その後、) l == k。行うことと返すことn(リストの長さ)が残っていることはわかっています。の場合はl != k、今回は少なくとも1つのタワーが取り外されたことを意味し、さらに行うことがあります。したがって、戻りf(k)ます。神様、私は再帰が大好きです。興味深いことに、f常に「必須」よりも1レベル深い再帰を行います。返されるリストが生成されるとき、関数は最初にそれを知る方法がありません。

この説明を書き始めたとき、このプログラムの長さは223バイトでした。物事を説明しながら、キャラクターを保存する方法があることに気づいたので、これをタイプして良かったです!最大の例は、f(l)再帰が機能することに気付く前に、もともと計算が行われたときに中断された無限ループとして実装されたものです。それは、あなたが考える最初の解決策が常に最良であるとは限らないことを示すだけです。:)


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

このように使用します:

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#、最少354 ...

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

\n改行の代わりにコンピューターのペーストのように見えますが、スペースに置き換えただけなので、誰かがコピーしたときにコードがすぐに実行されます。そして、私は自分自身が最後に削除させてend)= OKだった私の希望、追加の4つの文字が保存されます(必要でない機能を、閉じている)
flawr

matlabはスペースに満足していないようで、セミコロンに変更しました。endしかし、末尾についての良い点、thx :)
zabalajka 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.