Minecraftのチェストの配置


20

ビデオゲームMinecraftは、仮想世界を構成する3D 整数ラティスにさまざまな種類のブロックを配置および削除することをすべて目的としています。各格子点には、ブロックを1つだけ含めるか、空にすることができます(公式には「空気」ブロック)。この課題では、3Dワールドの1つの水平な2Dプレーンと、1つのタイプのブロック、チェストのみを考慮します。

チェストはプレイヤーにアイテムを保存させます。2つのチェストが同じ水平面で直交して隣接している場合、それらのテクスチャはリンクし、2倍の容量を持つダブルチェストが形成されます。ダブルチェストより大きなものは作れません。トリプルチェストもクワッドプルチェストもありません。

チェストブロックは、直交する隣接する4つのポイントがすべて空であるか、ダブルチェストの一部ではないチェストブロックが含まれている場合にのみ、空のラティスポイントに配置できます。これらの配置ルールにより、どのチェストブロックがリンクしてダブルチェストを形成するかについて、あいまいさが生じないことが保証されます。

たとえば、.空のスペースとCチェストであると仮定します:(数字は、単に識別のために空のスペースでもあります。)

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • 4つの隣人が空いているため、チェストをスポット1に配置できます。
  • チェストはスポット2に配置できます。これは、隣接するチェストが(まだ)ダブルチェストの一部ではないためです。
  • ダブルチェストの形成方法にはあいまいさがあるため、チェストをスポット3に配置することはできません。
  • 隣接するチェストは既にダブルチェストの一部であるため、チェストをスポット4に配置することはできません。
  • チェストはスポット5に配置できます。斜めに隣接するダブルチェストは何の影響も及ぼしません。

グリッドを超える領域が空であると仮定すると、グリッド.内のすべてを*チェストを配置できるかどうかに変更すると、次のようになります。

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**

もちろん、すべての*スペースが同時にチェストで占められるわけではありませんが、チェストが1つしかない場合は、どのチェストにも置くことができます。

チャレンジ

かかるプログラムや機能書く.Cグリッド、およびすべての変更.には*胸を印刷したり、結果のグリッドを返し、そこに配置することができる場合を。

  • 入力は、stdinまたはファイルから、または関数の文字列引数として指定できます。

  • 、テキストのすなわちA完全な矩形グリッド、少なくとも1つの文字の幅と身長のみを含む-あなたが入力がうまく形成されていると仮定してもよい.し、C必要に応じて最後の行の後の最後の改行があると仮定してもよい(出力中の1つが存在してもよいです)。

  • 入力のチェストの配置が上記のルールと一致していると仮定することができます。どのチェストがダブルチェストを形成するかについてあいまいさはありません。

  • 必要に応じて、任意の三つの異なる使用することができ、印刷可能なASCII文字の代わりに文字を.C*。改行の代わりに他のものを使用することはできません。

  • すべてのチェストは通常​​のチェストです。ない胸トラップされたか、エンダーチェストを

得点

最少バイト送信が勝ちです。

もう少し難しいMinecraft関連のチャレンジについては、Nether Portal Detectionをお試しください。


5
Minecraftingの観点から見ると、これはかなり面倒なゲーム内であることがわかりました。良いことは、閉じ込められた胸がある:P
Sp3000

stdinまたは単一の文字列引数からグリッド入力を取得する場合、グリッドの次元を追加入力として取得しても問題ありませんか?または、改行と文字列の長さから推測する必要がありますか?
レベルリバーセント

@steveverrill推測する必要があります。
カルバンの趣味

好奇心から、私自身を含むすべての答えに1つのダウン票があるのはなぜですか?私はそれが同じ人だと仮定することができますが、彼らは説明したいと思いますか?
レベルリバーセント

追加の課題として、胸に最適な配置を見つけるためのプログラムを作成できます。つまり、新しいチェスト間でもルールを破らずに、最大数の追加チェストを配置できる構成を見つけます。
AJMansfield

回答:


11

CJam、82 76 66 62 58 54バイト

qN/::~4{[8_]f/[9_]f*z{[{1$8-g)+}*]W%}%}*{_8<\2<8?}f%N*

入力形式は0、気室および8胸部細胞を想定しています。出力には1、チェストに配置できるすべてのセルが含まれます。

更新バグを修正しました。3バイト増加:(さらにゴルフ:)。@ Sp3000のおかげで4バイト節約

入力例:

0000000800
0008008000
0000000008
0880008808
0000000000

出力:

1111110811
1110018010
1008800108
0880088008
1008800110

今はゴルフが終わったと思う...

説明

qN/::~                   "This part converts the input into array of integer array";
qN/                      "Split input on new line";
   ::~                   "Parse each character in each row as integer";

4{[8_]f/[9_]f*z{[{1$8-g)+}*]W%}%}*

4{   ...z{       W%}%}*  "Run the logic 4 times, first, columns in correct order, then,";
                         "columns in reverse order, then for rows";
  [8_]f/[9_]f*           "Convert adjacent chests represented by two 8 into two 9";
                         "This happens for all the rows in the columns iterations and";
                         "for all the columns in the rows iterations";
  {               }%     "For each row/column";
   [{        }*]         "Reduce and wrap it back in the array";
     :I8-                "Store the second number in I, remove 8 from it";
         g               "Do signum. Now we have -1 for < 8 number, 0 for 8 and 1 for > 8";
          )+I            "Increment to get 0, 1 & 2. Add it to first number and put I back";

{_8<\2<8?}f%N*           "This part converts the output from previous iterations";
                         "to 3 character based final output and prints it";
{        }f%             "Map each row using the code block";
 _8<   8?                "If the value is greater than 7, make it 8, else:";
    \2<                  "If the value is greater than 1, make it 0, else 1";
            N*           "Join the arrays using new line";

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


8

.NET正規表現(網膜)、434 416 310 + 1 = 311のバイト

正規表現で最後に答えたチャレンジ(このチャレンジでリンクされているネザーポータルチャレンジ)の後、最終的に.NETスタイルの正規表現のインタープリターとして機能するコマンドラインツールを作成しました。正規表現を使用して、スタンドアロン言語ではないことに異議を唱えません。Retinaと名付けました。

現在、この課題は正規表現の提出にはあまり適していませんが、今はRetinaを使用する必要がありました。;)(さらに、Sp3000はチャットでそうするように私に挑戦しました。)だからここにあります:

正規表現ファイル

m`(?<=(?=.(.)*).*)(?<=((?<=(?<2>C|C(?(1)!)(\n|(?<-1>.))*)?)C(?=(?<2>C|(\n|(?<-1>.))*(?(1)!)C)?)(()(?(6)!)|(?<=^(?(7)!)(?<-7>.)*C).*\n(.)*()(?(8)!)))?){2}_(?=(?<2>((?(10)!)()|(?(11)!)()(.)*\n.*(?=C(?<-12>.)*(?(12)!)$))(?<=(?<2>C|C(?(1)!)(\n|(?<-1>.))*)?)C(?=(?<2>C|(\n|(?<-1>.))*(?(1)!)C)?))?){2}(?<-2>)?(?(2)!)

置換ファイル

*

正規表現ファイルは`、ファイルにいくつかのオプション(この場合は単に複数行モード)を入れることができることを除いて、ほとんど正規表現です。2つのファイルを指定すると、Retinaは自動的に全置換モードになります。これらの2つのファイルは、STDINから入力を読み取り、結果をSTDOUTに出力するプログラムを定義します。

RegexHeroおよびRegexStormでテストすることもできます。正規表現は、末尾の改行の有無にかかわらず機能し_、の代わりに使用します.。(どうやら、末尾の改行がない場合にRegexStormに問題が発生することがありますが、RegexHeroはどちらの場合でもうまく処理できるようです。)

正規表現には恐ろしいほどの重複があり、大幅に短縮するためのアイデアがいくつかあります...後で試してから説明を追加します。それまでの間、間違った結果をもたらす入力を見つけることができるかどうかをお知らせください。


7

J、75 73バイト

((,.|.)0 _1 0 1)(+:@](LF,@:,.~'*.C'{~>.)(2=f)+.[f]*f=.[:+/|.!.0)'C'&=;._2

space / usable space / chestにそれぞれ./ */ Cを使用して、質問の形式を使用します。

編集:小さなバグを修正しました(周囲を空のスペースとして適切に扱う代わりに、誤ってトーラスを使用しました)。

説明

## Preparation
              'C'&=;._2  NB. Map ./C to 0/1, turn into matrix
((,.|.)0 _1 0 1)         NB. Compute offsets to shift into each direction
                         NB. (i.e. [[_1 0], [1 0], [0 _1], [0 1]] in any order)


## "Part B"
(2=f)+.[f]*f=.[:+/|.!.0  NB. This part computes a matrix that is 1 for cells that
                         NB. cannot contain a chest:
              [:+/|.!.0  NB. Sum of shifts: shift in each of the four cardinal
                         NB. directions (using the array above) and then sum up.
           f=.           NB. Define this function as `f`; we'll use it some more.
         ]*              NB. Multiply by the "is chest" matrix: this isolates
                         NB. double-chests.
       [f                NB. Sum of shifts--1 for double-chest neighbours.
(2=f)                    NB. Isolate cells with two neighbouring chest.
     +.                  NB. Boolean or--either two neighbouring chests or next
                         NB. to a double-chest.

## Wrap up the result
(+:@] (fmt >.) PartB)    NB. Maximum of the array from the above and twice the "is
 +:@]      >.  PartB     NB. chest" matrix--this is 0,1,2 for '*', '.' or chest,
                         NB. respectively.

## Output formatting
LF,@:,.~'*.C'{~          NB. Format output...
        '*.C'{~          NB. Map 0,1,2 to '*.C' by using the value as index
LF   ,.~                 NB. Append line feed at end of each line
  ,@:                    NB. Ravel into one line

4

C、193

明確にするために不要な2つの改行。改変されていないコードに関する変更には、次のものがあります。文字リテラルではなく、ASCIIコードとしての文字。文字を保存するためのv = 0、strlen、およびstrchrの再配置

C関数は文字列を引数として受け入れたり、値として返したりしないため、できることは次のとおりqです。入力文字列へのポインタです。この関数は文字列を変更し、関数が戻ると出力が元の文字列で見つかります。

g(char*q){int v,j,w,l;
int f(p,d){int s=0,i=w=strchr(q,10)-q+1,r;for(;w/i;i-=i-1?w-1:2)r=p+i,r>-1&r<l&&q[r]==67&&++s&&d&&f(r,0);v|=s>d;}
for(j=l=strlen(q);j--;f(j,1),46-q[j]||v||(q[j]=42))v=0;}

ルールを要約するには:

空白の正方形(Cまたは改行を含まない)は、Cで最大1つの近傍がある場合に変換できます。

...そして、その隣人にはCを持つ隣人がいない

関数gには、深さ1から深さ0まで再帰する関数fが含まれています。2レベルの再帰のみで、単純なf(r,0)再帰呼び出しが行われるため、f(r,d-1)!は不要です。

テストプログラムのゴルフのないコード

入力テスト文字列はハードコードされています。getsまたscanf、改行を含む入力文字列は受け入れません。彼らはそれを各改行で細かく刻みます。

char n[]=".......C..\n...C..C...\n.........C\n.CC...CC..\n..........";

g(char*q){

  int v,j,w,l;

  int f(p,d){                    //p=cell to be checked,d=recursion depth
    int s=0,i=w,r;               //sum of C's found so far=0, i=width
    for(;w/i;i-=i-1?w-1:2)       //For i in   w,1,-1,-w   = down,right,left,up
      r=p+i,                     //r=cell adjacent to p
      r>-1&r<l&&q[r]=='C'&&++s   //If r not out of bounds and equal to C, increment s...
        &&d&&f(r,0);             //...and if recursion depth not yet at zero, try again one level deeper. 
    v|=s>d;                      //If the local s exceeds d, set global v to true to indicate invalid.
  }

  w=strchr(q,10)-q+1;            //width equals index of first newline + 1                   
  l=strlen(q);                   //length of whole string;
  for(j=l;j--;)                  //for l-1 .. 0 
    v=0,                         //clear v
    f(j,1),                      //and scan to see if it should be set
    '.'-q[j]||v||(q[j]='*');     //if the character is a '.' and v is not invalid, change to '*'
}

main(){
  g(n);
  puts(n);
}

質問例に基づく出力

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**

1

JavaScriptの(ES6)124 129

文字0(*)、6(C)、7(。)を使用する

F=s=>[for(c of(d=[o=~s.search('\n'),-o,1,i=-1],s))
   d.map(j=>t-=s[i+j]==6&&~d.some(k=>s[i+j+k]==6),t=i++)|c<7|t>i&&c
].join('')

非ゴルフと説明

F=s=>
{
  o=~s.search('\n') // offset to prev row (~ is shorter than +1 and sign does not matter)
  d=[o,-o,1,-1] // array of offset to 4 neighbors
  i=-1
  result = '' // in golfed code, use array comprehension to build the result into an array, then join it
  for (c of s) // scan each char
  {
    t = i++ // set a starting value in t and increment current position in i
    d.forEach(j => // for each near cell, offset in j
    {         
      if (s[i+j]==6) // if cell contains a Chest, must increment t
      {  
        // In golfed code "~some(...)" will be -1(false) or -2(true), using decrement instead of increment
        if (d.some(k=>s[i+j+k]==6)) // look for another Cheast in the neighbor's neighbors
        {
          // more than one chest, position invalid
          t += 2
        }
        else
        {
          t += 1
        }
      }
    })
    if (c < 7 // current cell is not blank
        || t > i) // or t incremented more than once, position invalid
    {
       result += c // curent cell value, unchanged
    }
    else
    {
       result += 0 // mark a valid position 
    }
  }
  return result
}

Firefox / FireBugコンソールで テストする

a='\
7777777677\n\
7776776777\n\
7777777776\n\
7667776677\n\
7777777777\n';

console.log(F(a))

出力

0000007600
0006006700
0770007706
7667076670
0770007700

1

Perl、66

胸部のコンフリクトに一致する正規表現は、最終的には長辺になったため、今回はCJamと競合しません。

#!perl -p0
/.
/;$"=".{@-}";s%0%s/\G0/2/r!~/2((.$")?2(.$")?|2$"|$"2)2/s*1%eg

入力の空のスペースと胸のスペースには0と2を使用し、出力のスポットをマークするには1を使用します。

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


0

Python 2-281バイト

f=lambda x,y:sum(m[y][x-1:x+2])+m[y-1][x]+m[y+1][x]
m=[];o=''
try:
 while 1:m+=[map(int,'0%s0'%raw_input())]
except:a=len(m[0]);l=len(m);m+=[[0]*a]
for y in range(l*2):
 for x in range(1,a-1):
    if y<l:m[y][x]*=f(x,y)
    else:o+=`2if m[y-l][x]else +(f(x,y-l)<5)`
 if y>=l:print o;o=''

(行8と9は、SEが4つのスペースに変換する単一のタブ文字を対象としています。このプログラムのすべての行には、先頭または末尾に0バイトまたは1バイトの空白があります。)

入力:0チェストなし、2チェスト
Ouput:チェスト0なし、2既存のチェスト、1可能性のある新しいチェスト


神様、これは恐ろしいことです。私は真剣に練習をしなければなりません。私はそれで知っているすべてのトリックを投げて、それが出てきました...まあ、それは正規表現のハハを除くすべての答えに負けて、281バイトとして出てきました、ハハ。正直に言って、私はそれをちょっとうまくやったように感じているので、自分のアルゴリズムは理想的ではなかったと推測しています。

ゴルフをしていない:

def f(x,y):
    """Given x,y coords of the board, return the sum of that point and all
    adjacent points.
    """
    return (sum(board[y][x-1:x+2]) # (x-1,y) + (x,y) + (x+1,y)
            + board[y-1][x]
            + board[y+1][x])
board=[]
output=''
try:
    while True:
        row = '0%s0' % raw_input() # line from stdin with a leading and trailing 0
        board.append(map(int, row)) # convert to list of ints
except:
    pass # exception is thrown when stdin is empty

board_width = len(board[0])
board_height = len(board)

board.append([0]*board_width) # new row of all 0s

for y in xrange(board_height*2):
    # board_height multiplied by 2 so we can use this loop to simulate two
    for x in xrange(1,board_width-1):
        if y < board_height: # "first loop"
            board[y][x] *= f(x,y) # multiply everything on the board by itself + sum
                                  # of neighbours
                                  # empty cells (0) stay 0 no matter what
                                  # lone chests (2 surrounded by 0) become 2*2==4
                                  # double chests (2 touching another 2) are weird:
                                  # - one chest becomes 2*(2+2)==8
                                  # - the other chest becomes 2*(2+8)==20
        else: # "second loop"
            if board[y - board_height][x] != 0:
                output += '2' # anything not equal to 0 is an existing chest
            else:
                valid = f(x, y - board_height) < 5 # if the sum of neighbours > 4, the
                                                   # current cell is either beside a
                                                   # double chest or more than one
                                                   # single chest
                output += '01'[valid]
    if y >= board_height: # only print during the "second loop"
        print output
        output=''
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.