我的世界胸部放置


20

电子游戏Minecraft就是要在构成虚拟世界的3D 整数格子中放置和移除不同类型的块。每个晶格点可以仅包含一个块,也可以为空(正式为“ air ”块)。在此挑战中,我们将只关注3D世界的一个水平2D平面和一种块:宝箱

箱子让玩家存放物品。当两个箱子在同一水平面内正交相邻时,它们的纹理会链接在一起,形成容量为两倍的双箱子。没有比双胸大的东西了。没有三联箱,也没有四联箱。

仅当胸块的四个正交相邻点都为空时,或者如果正好包含一个尚未属于双胸的一部分的胸块时,才可以将其放置在空的网格点中。这些放置规则确保了哪个胸块链接在一起形成双胸永远不会有任何歧义。

例如,假设.是一个空白空间并且C是一个箱子:(数字也是空白空间,仅用于标识目的。)

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • 箱子可以放置在位置1,因为它的4个邻居是空的。
  • 可以将胸部放置在位置2中,因为相邻的胸部还不是双胸部的一部分。
  • 不能将箱子放在位置3,因为双箱子的形成方式会含糊不清。
  • 无法将箱子放在位置4,因为相邻的箱子已经是双箱子的一部分。
  • 可以在位置5放置一个箱子。对角相邻的双箱子不会影响任何东西。

假设超出网格的区域是空的,.则将网格中的每个区域更改为一个*是否可以在其中放置箱子的结果:

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

当然,并不是所有的*空间都可以同时被箱子占用,但是如果您只有一个箱子,则可以将其放置在任何一个箱子中。

挑战

编写一个程序和函数,该程序或函数接受.C网格,如果可以在其中放置一个箱子,则将其全部更改.为a *,以打印或返回结果网格。

  • 输入可以来自stdin或文件,也可以来自函数的字符串参数。

  • 您可以假设输入格式正确-即一个完美的矩形文本网格,至少包含1个字符的宽度和高度,仅包含.和。C您可以选择假设最后一行之后有换行符(并且输出中可能有一个换行符) )。

  • 您可以假设输入中的箱子排列与上述规则一致。关于哪个箱子形成双箱子永远不会有任何歧义。

  • 如果需要,你可以使用任何三个不同的打印的ASCII到位的人物.C*。您不能使用其他方式代替换行符。

  • 所有的箱子都是正常的箱子。没有被困的箱子或下者的箱子

计分

字节最少的提交将获胜。

对于与Minecraft相关的挑战,它更具挑战性,请尝试Nether Portal Detection


5
从《我的世界》的角度来看,我在游戏中发现了这种令人讨厌的东西。好东西有被困的箱子:P
Sp3000

从标准输入或单个字符串参数获取网格输入时,将网格尺寸作为附加输入是否可以接受?还是必须从换行符和字符串长度推断出来?
水平河圣

@steveverrill必须推断出来。
加尔文的业余爱好

出于好奇,为什么每个答案(包括我自己的答案)都投下反对票?我只能假设是同一个人,他们愿意解释吗?
水平河圣

如果遇到其他挑战,可以编写程序来找到适合胸部的最佳位置。也就是说,找到一种配置,该配置允许在不破坏新箱子之间规则的情况下放置最大数量的其他箱子。
AJMansfield

Answers:


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个字节

在我用正则表达式回答的最后一个挑战(此挑战中链接到的Nether Portal挑战)之后,我最终着手编写一个命令行工具,该工具充当.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)!)

替换文件

*

regex文件主要只是regex,不同之处在于`,您可以在文件中放置一些选项,在本例中为多行模式。当给定两个文件时,Retina会自动采用全部替换模式。这两个文件定义了一个程序,该程序从STDIN读取输入并将结果打印到STDOUT。

您也可以在RegexHeroRegexStorm对其进行测试。regex可以在尾随换行符的情况下使用,也可以不使用尾随换行符,并且可以_代替来使用.。(显然,如果没有尾随换行符,RegexStorm有时会出现问题,但是RegexHero似乎可以处理两种情况。)

正则表达式中有很多重复,而且我有一些想法可以大大缩短它。同时,请让我知道您是否找到任何产生错误结果的输入。


7

J,75 73字节

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

使用问题中的格式,分别使用./ */ 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

193

2个不必要的换行符,以使内容更加清晰。对非高尔夫代码的更改包括:字符作为ASCII代码而不是字符文字;重新排列v = 0,strlen和strchr以保存字符(strchr是最丑陋的,因为这意味着原本只能执行一次的计算每个单元格要执行5次!)

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或换行符)具有最多1个带有C的邻居,则可以将其转换

...而且那个邻居没有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字节,输给了除了regex中的每个答案,哈哈。老实说,我觉得自己打的不错,所以我猜我的算法还不够理想。

取消高尔夫:

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=''
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.