Minecraft Chest Placement

CJam, 82 76 66 62 58 54 bytes

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

Input format expects 0 for air cell and 8 for a chest cell. Output contains 1 for all cells that can be placed with a Chest.

UPDATE : Fixed a bug. Increased by 3 bytes :( golfed further :) . 4 bytes saved thanks to @Sp3000

Example input:

0000000800
0008008000
0000000008
0880008808
0000000000

Output:

1111110811
1110018010
1008800108
0880088008
1008800110

I think I am done golfing for now...

Explanation

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

Try it online here


.NET Regex (Retina), 434 416 310 + 1 = 311 bytes

After the last challenge I answered in regex (the Nether Portal Challenge linked to in this challenge), I finally set out to write a command-line tool, which acts as an interpreter for .NET-style regular expressions, so I can answer questions with regex without being challenged that they're not a stand-alone language. I've named it Retina.

Now, this challenge doesn't lend itself very well to a regex submission, but I just had to use Retina now. ;) (Plus, Sp3000 challenged me to do so in chat.) So here it is:

Regex file

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

Replacement file

*

The regex file is mostly just the regex, except that ` lets you put a few options in the file, in this case simply multiline mode. When given two files, Retina automatically assumes replace-all mode. These two files define a program which reads the input from STDIN and prints the result to STDOUT.

You can also test it on RegexHero and RegexStorm. The regex works both with and without trailing newline, and uses _ in place of .. (Apparently, RegexStorm occasionally has problems if there is no trailing newline, but RegexHero seems to handle either case fine.)

There is a horrible amount of duplication in the regex, and I have a couple of ideas for shortening it significantly... I'll give that a try later and then add an explanation. In the meantime, let me know if you can find any inputs which yield a wrong result.


J, 75 73 bytes

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

Uses the format in the question, using ./*/C for space/usable space/chest, respectively.

Edit: fixes a small bug (I accidentally used a torus instead of properly treating the surrounding as empty space).

Explanation

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

Tags:

Code Golf