19
\$\begingroup\$

Piet is an interesting programming language for a number of reasons. Today we will focus on one reason: the roll command. The roll command was originally from PostScript and is a powerful way to manipulate the stack.

The roll command pops the top two elements of the stack and uses them as parameters. We'll call the first value popped turns and the second depth. A turn to depth n will take the topmost element of the stack, make it the nth element in the stack, and move each of the elements above it up one. If turns is negative this is done in the opposite direction. That is, the nth element is moved to the top and the other elements are moved down. This is repeated abs(turns) times.

Challenge

Write a program or function that takes in a stack and returns that stack after executing a roll.

Rules

  • Input and output may be in a list, array, string with a delimiter, passed in one element at a time, or any other reasonable format. Output must be in the same format as the input.
  • depth will never be negative and will never be greater than the length of the stack.
  • The input stack will always contain at least two elements.
  • This is so the shortest answer in each language wins. As such, I will not be accepting an answer.
  • Standard loopholes are forbidden.

Test Cases

in:  out:
2    
4    
1    3
2    4
3    1
4    2
5    5
6    6

in:  out:
-2   
3
1    2
2    3
3    1

in:  out:
-42
0
1    1
2    2
3    3
4    4
5    5
\$\endgroup\$
10
  • 2
    \$\begingroup\$ shortest answer in each language wins, that's not how [code-golf] works. Shortest answer wins. Period. \$\endgroup\$
    – mbomb007
    Apr 3, 2017 at 21:12
  • 4
    \$\begingroup\$ @mbomb007 ahem what about this \$\endgroup\$
    – user63187
    Apr 3, 2017 at 23:14
  • 7
    \$\begingroup\$ I was very disappointed that this did in no way involve rick rolling \$\endgroup\$
    – user63187
    Apr 4, 2017 at 0:20
  • 2
    \$\begingroup\$ @mbomb007 I don't see that in the tag description or in a quick search on meta so I don't think that is the case. \$\endgroup\$ Apr 4, 2017 at 14:25
  • 2
    \$\begingroup\$ @mbomb007 If you would like me to change it, please provide some sort of argument other than saying "you're wrong and I'm right" over and over. There is precedent for this, which you dismissed, and nowhere does it say that challenges require exactly one winner or that an answer must be accepted. \$\endgroup\$ Apr 4, 2017 at 16:41

10 Answers 10

8
\$\begingroup\$

Haskell, 64 62 bytes

Edit: -2 bytes: @xnor saw something I'd thought wrong about.

r takes and returns a list of Ints.

r(t:d:l)|d<1=l|(x,y)<-d%l,(z,w)<-mod t d%x=w++z++y
(%)=splitAt

Try it online!

splitAt n l splits a list l at index n, mod calculates remainder of division, ++ concatenates lists.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think you can cut 2 bytes by defining (%)=splitAt infix. \$\endgroup\$
    – xnor
    Apr 3, 2017 at 23:20
  • \$\begingroup\$ @xnor Oh, I had somehow convinced myself that wouldn't work \$\endgroup\$ Apr 3, 2017 at 23:32
8
\$\begingroup\$

JavaScript (ES6), 49 47 bytes

(t,d,...a)=>a.splice(t=(t%d+d)%d,d-t).concat(a)

Edit: Saved 2 bytes thanks to @Shaggy by taking the stack elements as separate parameters. Explanation:

  • When the turn is a multiple of the depth, nothing happens. The first step is therefore to calculate turn modulo depth. As JavaScript only knows how to calculate the remainder, I have to do this in two steps.
  • A turn of 1 moves the top element to the depth element. A turn of 2 moves the top two elements, etc. However, you can also achieve this by moving the elements between turn and depth to the front. splice removes those elements and concat prepends them to the remaining elements. (I could have used an array comprehension instead as it is the same length.)
  • Unlike slice, the second parameter to splice is the number of elements to remove.
\$\endgroup\$
4
  • \$\begingroup\$ Isn't (t%d+d)%d the same as t%d? \$\endgroup\$
    – Luke
    Apr 3, 2017 at 21:14
  • \$\begingroup\$ @Luke No, % is remainder, so it gives a negative answer when t is negative. \$\endgroup\$
    – Neil
    Apr 3, 2017 at 21:22
  • \$\begingroup\$ You could save 2 bytes by using (t,d,...a)=> as the rules allow for the input to be passed in one element at a time. \$\endgroup\$
    – Shaggy
    Apr 5, 2017 at 10:41
  • \$\begingroup\$ @Shaggy Thanks, I hadn't noticed that. \$\endgroup\$
    – Neil
    Apr 5, 2017 at 10:47
7
\$\begingroup\$

CJam, 31 bytes

)\):N@\,0a|={NW*1$1$>)\+@@<\+}*

Input and output are arrays on the stack, with the last element representing the top of the stack.

Stack trace:

                   e# Stack:                [6 5 4 3 2 1 4 2]
)                  e# Take out first value: [6 5 4 3 2 1 4] 2
\                  e# Swap:                 2 [6 5 4 3 2 1 4]
)                  e# Take out first value: 2 [6 5 4 3 2 1] 4
:N                 e# Store in N:           2 [6 5 4 3 2 1] 4; N=4
@                  e# Rotate:               [6 5 4 3 2 1] 4 2
\                  e# Swap:                 [6 5 4 3 2 1] 2 4
,                  e# Range:                [6 5 4 3 2 1] 2 [0 1 2 3]
0                  e# Push 0:               [6 5 4 3 2 1] 2 [0 1 2 3] 0
a                  e# Wrap in array:        [6 5 4 3 2 1] 2 [0 1 2 3] [0]
|                  e# Logical or:           [6 5 4 3 2 1] 2 [0 1 2 3]
                   e# (This will replace an empty array with [0] to handle a special case of n=0)
=                  e# Get array value:      [6 5 4 3 2 1] 2
{NW*1$1$>)\+@@<\+} e# Push block:           [6 5 4 3 2 1] 2 {NW*1$1$>)\+@@<\+}
*                  e# Preform n times:      [6 5 4 3 2 1]
  N                e# Push N:               [6 5 4 3 2 1] 4
  W*               e# Negate:               [6 5 4 3 2 1] -4
  1$               e# Copy element 1 back:  [6 5 4 3 2 1] -4 [6 5 4 3 2 1]
  1$               e# Copy element 1 back:  [6 5 4 3 2 1] -4 [6 5 4 3 2 1] -4
  >                e# Slice a[-4:]          [6 5 4 3 2 1] -4 [4 3 2 1]
  )                e# Take first value:     [6 5 4 3 2 1] -4 [4 3 2] 1
  \                e# Swap:                 [6 5 4 3 2 1] -4 1 [4 3 2]
  +                e# Append:               [6 5 4 3 2 1] -4 [1 4 3 2]
  @@               e# Rotate twice:         [1 4 3 2] [6 5 4 3 2 1] -4
  <                e# Slice a[:-4]:         [1 4 3 2] [6 5]
  \                e# Swap:                 [6 5] [1 4 3 2]
  +                e# Append:               [6 5 1 4 3 2]
e# Preform the block again:                 [6 5 2 1 4 3]
\$\endgroup\$
6
\$\begingroup\$

Mathematica, 58 50 bytes

Edit: Thanks to Martin Ender for saving 8 bytes.

Take[x={##3},#2]~RotateLeft~#~Join~Drop[x,#2]&@@#&

Explanation:

Pure function which expects a list where the beginning of the list represents the top of the stack. We pass the elements of the list into the pure function Take[x={##3},#2]~RotateLeft~#~Join~Drop[x,#2]&. x is set to the sequence of elements starting with the third argument., then we rotate the first #2 (second argument) elements of x to the left # (first argument) times, then Join the remaining elements of x.

It would save 3 bytes if we just passed the stack elements in as arguments to the function directly rather than being in a list initially, but then the input and output formats wouldn't match.

Original solution:

#/.{t_,d_,x___}:>{x}~Take~d~RotateLeft~t~Join~Drop[{x},d]&

There's something really satisfying about this chain of infix functions. Replaces a list with first element t, second element d, and remaining elements x with the result of rotating the first d elements of {x} to the left t times and joining the remaining elements of {x}.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Nice! You can save 3 bytes by using a one-byte prefix function ± insetad of a replacement rule, and another 1 byte by exploiting TakeDrop as follows: ±{t_,d_,x___}:=#~RotateLeft~t~Join~#2&@@{x}~TakeDrop~d \$\endgroup\$ Apr 3, 2017 at 20:04
  • \$\begingroup\$ I was just going to comment the same thing as Greg, but you can actually go even shorter. Either make an unnamed variadic function (although that's a bit dodgy because it takes input ...&[1, 1, 3, 4] and return {3, 4} or do that manually with an Apply in the beginning: Take[x={##3},#2]~RotateLeft~#~Join~Drop[x,#2]&@@#& (just to be clear, my first suggestion omits the @@#&.) \$\endgroup\$ Apr 3, 2017 at 20:06
6
\$\begingroup\$

Ruby, 40 bytes

x=->s{n,d,*s=s;s[0,d]=s[0,d].rotate n;s}

Try it online!

Takes the input as a list, returns a list. The fact that a built-in rotate exists which can handle both positive and negative rotations makes this trivial.

\$\endgroup\$
5
\$\begingroup\$

Python, 141 98 87 74 bytes

11 bytes saved thanks to @Cole

def f(s):*s,d,t=s;n=len(s)-d;return s*0**d or s[:n]+s[-t%d-d:]+s[n:-t%d-d]

Receives input as a list, where the last element is the top of the stack.

Uses the 0ⁿ trick to filter zero-depth and python's sign-adjusting modulo operator to determine the part of the list to-be-chopped.

\$\endgroup\$
7
  • \$\begingroup\$ Why not just take f(s,t,d)? \$\endgroup\$
    – cole
    Apr 3, 2017 at 19:56
  • \$\begingroup\$ @Cole Thanks for the unpacking! However, I can't see what did you mean by f(s,t,d) (input is the whole stack). \$\endgroup\$
    – Uriel
    Apr 3, 2017 at 20:22
  • \$\begingroup\$ awesome idea for unpacking, though I don't think you should credit me for that (I was suggesting just to take the variables separately). The input spec seems to let you take the depth and turns as separate variables from the stack: "Input and output may be in a list, array, string with a delimiter, passed in one element at a time, or any other reasonable format. Output must be in the same format as the input." \$\endgroup\$
    – cole
    Apr 3, 2017 at 21:21
  • \$\begingroup\$ You can save 1 byte with r=-t%d-d. Also, replacing s*0**d with s*(d<1) maintains byte count but maybe improves readability (not that that's the goal). I didn't know that 0**0==1 in Python though, that's interesting. \$\endgroup\$ Apr 4, 2017 at 16:47
  • \$\begingroup\$ @BenFrankel I can't save -t%d-d as a value (as I did before), because when d is 0 this would trigger a division-by-zero exception. \$\endgroup\$
    – Uriel
    Apr 4, 2017 at 16:51
3
\$\begingroup\$

JavaScript ES6, 109 92 bytes

x=>{for(i=x.shift(),i=i>0?i:-i,j=x.shift();i-->0&&j>0;)x=x.splice(j,1).concat(x);return x}

Try it online!

Receives input in the form of an array of integers.
Also has the count to arrow :P

Explanation:

The code uses the shift function to extract the first two elements of the list.

It then gets the absolute value of the first element, which is the number of turns.

Since Javascript is zero indexed, the depth index needs to be decreased by 1.

If the depth index was 0 or 1, nothing should change, but due to the decrease, index of 0 would cause changes. Therefore exit the loop if depth index is not <=0.

The splice(a,b) function returns the sub-array of length b with starting index a from the array and leaves the original array without those elements.

When concatenated with the remainder of the original array, this is a single rotation of the array at the depth index.

By performing this operation n times, where n is the number of turns, the resulting array is the result of the roll operator.

\$\endgroup\$
3
\$\begingroup\$

Python 2, 48 bytes

lambda r:r[2:r[1]+2][r[0]:]+r[2:r[0]]+r[r[1]+2:]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

TI-Basic, 141 150 bytes (noncompeting)

Prompt L1
L1(1→T
L1(2→D
seq(L1(C),C,3,dim(L1→L1
If TD>0
Then
For(A,1,T
L1(1→B
For(C,2,D
L1(C→L1(C–1
End
B→L1(D
End
End
If TD<0
Then
For(A,1,-T
L1(D→B
For(C,D,2,-1
L1(C–1→L1(C
End
B→L1(1
End
End
L1

Edit: fixed case where depth is zero (+9 bytes)

TI-Basic doesn't support 0-length lists, so this approach won't work for a two-length input.

Explanation:

Prompt L1                # 4 bytes, input list
L1(1→T                   # 7 bytes, turns
L1(2→D                   # 7 bytes, depth
seq(L1(C),C,3,dim(L1→L1   # 18 bytes, remove turns and depth from list
If TD>0                  # 6 bytes, if turns is positive and depth is nonzero (can't be negative)
Then                     # 2 bytes
For(A,1,T                # 7 bytes, do this 'turns' times
L1(1→B                    # 7 bytes, backup the first item
For(C,2,D                # 7 bytes, shuffle the rest along
L1(C→L1(C–1               # 12 bytes
End                      # 2 bytes
B→L1(D                   # 7 bytes, restore the backup to where it should be
End                      # 2 bytes
End                      # 2 bytes
If TD<0                  # 6 bytes, if T is negative and D is nonzero
Then                     # 2 bytes
For(A,1,-T               # 8 bytes, do this -'turns' times
L1(D→B                   # 7 bytes, backup the Dth item
For(C,D,2,-1             # 10 bytes, shuffle the items the other way
L1(C–1→L1(C              # 12 bytes
End                      # 2 bytes
B→L1(1                   # 7 bytes, restore backup to where it belongs
End                      # 2 bytes
End                      # 2 bytes
L1                       # 2 bytes, implicitly return
\$\endgroup\$
1
  • \$\begingroup\$ I think you need code to deal with the 2-element list case, too; currently it will error at the seq(. \$\endgroup\$
    – lirtosiast
    Apr 6, 2017 at 18:52
1
\$\begingroup\$

Batch, 163 bytes

@set s=
@set r=
@set/ad=%2,t=(%1%%d+d)%%d
:l
@shift
@set/af=t-=1,f^^=d-=1
@if %f% lss 0 (set r=%r% %2)else set s=%s% %2
@if not "%3"=="" goto l
@echo%r%%s%

Takes input as command-line parameters and outputs a space-separated list. The parameters between t and d are extracted into the r variable so that they can be prepended to the s variable, which receives all of the other parameters.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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