22
\$\begingroup\$

In Minecraft, pistons are blocks that can move other blocks. However, they can only move at most twelve blocks, and won't work at all if any obsidian is in the way. Also, slime blocks are sticky and stick to other blocks, except for obsidian.

Your challenge

Take as input a 5x5 matrix or similar, containing one piston at the bottom, and output the result of the single piston pushing upwards, as 5x6. Input format should have five distinct values for obsidian, slime, other block, piston and empty space, here represented by O, S,B,P, and respectively.

For example, say you start with

  B  
  B  
  B  
  B  
  P  

Output the result, if the piston was activated, as 5x6:

  B  
  B  
  B  
  B  
  P  
     

Note that the whole configuration with the piston is moved up, as long as it is legal

Testcases:


BBBBB
BBBBB
SSSSS
  S   
  P  
=> 

BBBBB
BBBBB
SSSSS
  S  
  P  
Because 16 is too many blocks.
     
 SBS 
 SBS 
 SBS 
 SBS 
  P  
=>
  B  
 SBS 
 SBS 
 SBS 
 SPS 
Because slime sticks to blocks, but blocks don't stick to slime.
O    
SSSSS
    S
    S
    P
=>
O    
SSSSS
    S
    S
    P
     
Because the obsidian is in the way, the whole thing can't move.
S S S
     
S S S
     
S P S
=>
     
S S S
     
S S S
  P  
S   S

The stray blocks stay where they are.

SSSSS
B S B
B S B
B S B
B P B
=>
SSSSS
B S B
  S  
B S B
B P B
B   B
The slime pulls the first two blocks, but the rest stay in place. 

 OSO 
 OSO 
 OSO 
 OSO 
 OPO 
=>
  S  
 OSO 
 OSO 
 OSO 
 OPO 
 O O 
Slime doesn't stick to obsidian, so it's free to move. 

Scoring

This is , the shorter the better!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Sandboxed \$\endgroup\$ – A username May 14 at 22:27
  • 5
    \$\begingroup\$ I was about to ask what was going on in test case 5, until I saw the spaces :P \$\endgroup\$ – Unrelated String May 14 at 23:23
9
\$\begingroup\$

J, 121 98 bytes

Takes in POSB as digits 01234. Probably some microgolfs left, these long tacit definitions tend to get confusing. :-)

((0,~*)+0,(*-.))[(]*(2 e.*&,)<14>+/@,@])[(]*@+(2&<@[*[:+/((,-)=i.2)t]*3=[)+*@[*1(t=:|.!.0)])^:_=&1

Try it online!

How it works

  • =&1 Start a will-be-pushed bitmap with the piston
  • ^:_ expand the bitmap until it does not expand further:
  • 1(t=:|.!.0)] Push the bitmap upwards (non-wrapping, thus !.0)
  • *@[* but only if a non-space was pushed.
  • t]*3=[ Extend push of the will-be-pushed slimes towards
  • ((,-)=i.2) all 4 direction
  • 2&<@[*[:+ but only push slimes and blocks.
  • ]*@+…+ OR old bitmap, slime pushes, and up pushes for the next iteration.
  • [(]*…) Set the final bitmap to 0 if …
  • (2 e.#~&,) There is an obsidian block in it
  • <14>+/@,@] or the sum (including the piston) is not less 14.
  • 0,(*-.) Original map * not-pushed bitmap and an empty row above.
  • (0,~*) Original map * pushed bitmap and an empty row under.
  • + Add both maps – as empty spaces are 0 they don't overlap.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Well done and nice explanation. \$\endgroup\$ – Jonah May 15 at 14:23
  • 1
    \$\begingroup\$ I think 13 should be 14. \$\endgroup\$ – Jonathan Allan May 15 at 21:47
8
\$\begingroup\$

Charcoal, 144 120 bytes

WS⊞υι≔⪫υ¶θPθ…θ⌕θP≔⟦⟦ⅈⅉ⟧⟧ηFη«J§ι⁰⊖§ι¹F‹@KK⊞η⟦ⅈⅉ⟧↓F⁼SKKF³«M✳⊗⁺²λF№⪪BS¹KK⊞η⟦ⅈⅉ⟧M✳⊗λ» »Fη«J§ι⁰⁻§ι¹›‹Lη¹⁴⊙η⁼O§§υ§ι¹§ι⁰§§υ⊟ι⊟ι

Try it online! Link is to verbose version of code. Explanation:

WS⊞υι

Input the layout. (I've decided to take input as newline-terminated lines; this allows you to experiment with layouts of different numbers of lines if you so wish.)

≔⪫υ¶θPθ…θ⌕θP

Output the layout and move the cursor to the position of the piston.

≔⟦⟦ⅈⅉ⟧⟧ηFη«

Perform a breadth-first search starting with the position of the piston.

J§ι⁰⊖§ι¹

Jump to the square above the current position.

F‹@KK⊞η⟦ⅈⅉ⟧

Add this position to the list unless it's empty.

↓F⁼SKKF³«

If the current position is a sticky block, then check the other three sides too.

M✳⊗⁺²λF№⪪BS¹KK⊞η⟦ⅈⅉ⟧M✳⊗λ

If there is a (sticky) block on that side then add this position to the list.

» »

Erase the block, assuming it will be moved. This also avoids considering the same block twice.

Fη«

Loop over each block.

J§ι⁰⁻§ι¹›‹Lη¹⁴⊙η⁼O§§υ§ι¹§ι⁰

Jump to its old or new position depending on whether there weren't too many blocks to push or any obsidian in the way.

§§υ⊟ι⊟ι

Print the block.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.