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\$
4
  • 1
    \$\begingroup\$ Sandboxed \$\endgroup\$
    – emanresu A
    Commented May 14, 2021 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\$ Commented May 14, 2021 at 23:23
  • \$\begingroup\$ Is there always exactly 1 piston at (2,4)? \$\endgroup\$
    – l4m2
    Commented Jan 25, 2023 at 3:18
  • \$\begingroup\$ @l4m2, No, it's just a convenient space to put it for testcases \$\endgroup\$
    – emanresu A
    Commented Jan 25, 2023 at 5:16

2 Answers 2

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
    Commented May 15, 2021 at 14:23
  • 1
    \$\begingroup\$ I think 13 should be 14. \$\endgroup\$ Commented May 15, 2021 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 and acknowledge you have read our privacy policy.

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