This is how we roll

18

1

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

Mike Bufardeci

Posted 2017-04-03T17:57:31.100

Reputation: 1 680

2shortest answer in each language wins, that's not how [code-golf] works. Shortest answer wins. Period. – mbomb007 – 2017-04-03T21:12:18.090

4

@mbomb007 ___ahem___ what about this

– Christopher – 2017-04-03T23:14:05.037

7I was very disappointed that this did in no way involve rick rolling – Christopher – 2017-04-04T00:20:10.683

2@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. – Mike Bufardeci – 2017-04-04T14:25:15.990

1@DownChristopher The OP can specify that he's doing a catalog, but it's not the [code-golf] tag itself that makes it that. Code golf by itself simply means shortest wins. Considering that this isn't a trivial example worth cataloging, I'd recommend just doing shortest answer wins. "Hello, World!" is worth a catalog, but this isn't. – mbomb007 – 2017-04-04T15:54:21.867

2@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. – Mike Bufardeci – 2017-04-04T16:41:51.727

"Questions without an objective primary winning criterion are off-topic, as they make it impossible to indisputably decide which entry should win." The precedent for a catalog is only for questions worth cataloging, as in, the question will receive hundreds of answers. A "hello world" question is such a question. This one isn't. – mbomb007 – 2017-04-04T18:14:20.987

2

@mbomb007 If you think that this answer doesn't have an objective winning criterion just because I said I was not accepting an answer then you should vote to close it. No objections were raised in the sandbox but there could still be issues.

There isn't a strict definition of this "catalog" you keep bringing up and I even recall you taking catalog status away from a question. Since there is no clear definition of a catalog I don't see why this can't be one, even though we both deem it unnecessary.

– Mike Bufardeci – 2017-04-04T18:24:55.090

1Can we use Piet? :P – Feathercrown – 2017-04-04T19:41:26.053

@Feathercrown Yes. Piet, PostScript and other languages with a roll builtin are allowed. – Mike Bufardeci – 2017-04-04T19:50:06.433

Answers

8

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.

Ørjan Johansen

Posted 2017-04-03T17:57:31.100

Reputation: 6 914

1I think you can cut 2 bytes by defining (%)=splitAt infix. – xnor – 2017-04-03T23:20:08.467

@xnor Oh, I had somehow convinced myself that wouldn't work – Ørjan Johansen – 2017-04-03T23:32:32.460

8

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.

Neil

Posted 2017-04-03T17:57:31.100

Reputation: 95 035

Isn't (t%d+d)%d the same as t%d? – Luke – 2017-04-03T21:14:42.737

@Luke No, % is remainder, so it gives a negative answer when t is negative. – Neil – 2017-04-03T21:22:35.533

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. – Shaggy – 2017-04-05T10:41:51.540

@Shaggy Thanks, I hadn't noticed that. – Neil – 2017-04-05T10:47:21.770

7

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]

Esolanging Fruit

Posted 2017-04-03T17:57:31.100

Reputation: 13 542

6

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}.

ngenisis

Posted 2017-04-03T17:57:31.100

Reputation: 4 600

1Nice! 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 – Greg Martin – 2017-04-03T20:04:49.510

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 @@#&.) – Martin Ender – 2017-04-03T20:06:59.537

5

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.

Uriel

Posted 2017-04-03T17:57:31.100

Reputation: 11 708

Why not just take f(s,t,d)? – cole – 2017-04-03T19:56:46.997

@Cole Thanks for the unpacking! However, I can't see what did you mean by f(s,t,d) (input is the whole stack). – Uriel – 2017-04-03T20:22:54.927

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." – cole – 2017-04-03T21:21:13.017

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. – Ben Frankel – 2017-04-04T16:47:26.377

@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. – Uriel – 2017-04-04T16:51:14.017

@BenFrankel that would fail for d == abs(t) (try [6, 5, 4, 3, 2, 1, 4, 4] for example) – Uriel – 2017-04-04T17:01:43.683

@Uriel, Yeah, I hadn't tested it properly, it actually fails whenever d divides t. – Ben Frankel – 2017-04-04T17:06:13.047

5

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.

Ventero

Posted 2017-04-03T17:57:31.100

Reputation: 9 842

3

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.

fəˈnɛtɪk

Posted 2017-04-03T17:57:31.100

Reputation: 4 166

3

Python 2, 48 bytes

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

Try it online!

Keerthana Prabhakaran

Posted 2017-04-03T17:57:31.100

Reputation: 759

2

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

pizzapants184

Posted 2017-04-03T17:57:31.100

Reputation: 3 174

I think you need code to deal with the 2-element list case, too; currently it will error at the seq(. – lirtosiast – 2017-04-06T18:52:23.023

1

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.

Neil

Posted 2017-04-03T17:57:31.100

Reputation: 95 035