Random dice tipping

14

2

In a standard dice (die) the numbers are arranged so that opposite faces add to seven. Write the shortest possible program in your preferred language which outputs a random throw followed by 9 random tippings. A tipping is a quarter turn of the dice, e.g. if the dice is facing 5, all possible tippings are 1,3,4 and 6.

Example of desired output:

1532131356

steenslag

Posted 2011-02-15T22:37:04.490

Reputation: 2 070

Answers

5

GolfScript, 26 chars

0{(.6,5@--\-.,rand=).}10*;

A slight more compressed version of Joey's, basically working around the issue with zero-indexing.

Howard

Posted 2011-02-15T22:37:04.490

Reputation: 23 109

9

Ruby, 44

c=0;10.times{$><<c=([*1..6]-[c,7-c]).sample}

I found the [*1..6] trick by lucky experimenting.

steenslag

Posted 2011-02-15T22:37:04.490

Reputation: 2 070

1Some nice tricks here, great stuff. Hitting myself on the head for missing the Array#sample method. – Lars Haugseth – 2011-02-21T08:49:16.757

4

GolfScript, 28

0:|;{7,[0|7|-]-.,rand=:|}10*

Joey

Posted 2011-02-15T22:37:04.490

Reputation: 12 260

4

JavaScript (71 characters)

You may need to replace print with alert or something else, depending on your JavaScript environment.

for(C=L=T=0;C++<10;print(L=T))while(!(T-L&&T+L-7))T=Math.random()*6+1|0

PleaseStand

Posted 2011-02-15T22:37:04.490

Reputation: 5 369

merge loops by conditionally incrementing the outer one when a value is found : for(b=n=10;n;a-b&&a+b-7&&print(b=a,n--))a=Math.random()*6+1|0 – imma – 2014-02-25T10:53:30.210

3

R, 56 52

for(i in 0:9)cat(F<-sample(setdiff(1:6,c(F,7-F)),1))

Sven Hohenstein

Posted 2011-02-15T22:37:04.490

Reputation: 2 464

1Hi Sven, you can save 4 bytes – JayCe – 2018-08-08T12:14:58.217

@JayCe Great idea, thank for pointing out! – Sven Hohenstein – 2018-08-08T16:41:59.093

My pleasure - and actually you can save 5 more bytes

– JayCe – 2018-08-08T19:54:59.503

3

Bash

#/!bin/bash
f=`expr $RANDOM % 6` 
f=`expr $f + 1`
printf "$f"
for ((i=0; i<9; i++))
do
   ((bad=7-$f))
   next=`expr $RANDOM % 6`
   next=`expr $next + 1`
   while [ $next -eq $bad ] || [ $next -eq $f ]
   do
      next=`expr $RANDOM % 6`
      next=`expr $next + 1`
   done
printf "$next"
f=$next
done

sample code: http://ideone.com/CCfro

Aman ZeeK Verma

Posted 2011-02-15T22:37:04.490

Reputation: 609

The use of ((var=expression)) is very nice - I thought that the shortest way was var=$((expression)) But why do you use that once only and waste tonnes of characters on expr in backticks? – Peter Taylor – 2011-02-16T10:00:45.613

I dont do much of shell scripting, but for some reason ((var=expr)) in some places got failed (yeah weird :P ) Since I started this script, I just somehow completed. :) – Aman ZeeK Verma – 2011-02-16T11:10:47.660

2

Windows PowerShell, 45

-join(0..9|%{($d=1..6-ne(7-$d)-ne$d|random)})

Pretty trivial, actually. I generate a list of possible dice rolls 1..6 and then select only those not equal to seven minus the last roll and then only those not equal to the last roll. From the remaining list I then select a random item and assign it to $d. Since $d is initially treated as 0 it rolls a normal die the first time.

Test script:

for($i=0;$i-lt20;$i++){
    $o=@(./tipping.ps1)
    if ($i-gt0-and$o-eq$o2) { throw "Must have random output" }
    if ($o.count-ne1) { throw "Must only have one line of output" }
    if ($o[0]-match'[^1-6]'){ throw "Invalid characters" }
    if($o[0].length-ne10){ throw "Wrong length: $($o[0].length)" }
    $r=[char[]]($o[0])|%{$_-48}
    for ($x=1;$x-lt$r.count;$x++){
        if ($r[$x-1]+$r[$x]-eq7) { throw "Not a tipping: $($r[$x-1]) and $($r[$x])" }
    }
    $o2=$o
}

History:

  • 2011-02-18 11:57 (61) First attempt.
  • 2011-02-18 11:58 (45) I don't need to generate the first number separately.

Joey

Posted 2011-02-15T22:37:04.490

Reputation: 12 260

I get The term 'random' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and try again. – Peter Taylor – 2011-02-18T12:17:50.947

@Peter: PowerShell v2, please. The Get-Random cmdlet didn't exist in v1. – Joey – 2011-02-18T12:46:44.420

2

Ruby

66 characters

(0..9).reduce([]){|m|m<<((1..6).to_a-[d=m[-1]||0,7-d]).shuffle[0]}

Lars Haugseth

Posted 2011-02-15T22:37:04.490

Reputation: 181

2

GS2, 16 bytes

16 2f 25 08 41 20 17 30 16 2f 31 31 25 09 19 32

Here's how it works

16 2f 25     # make range from 1 to 6 and push random element
08           # start block
    41       # duplicate top of stack twice
    20 17 30 # negate top of stack and add 7
    16 2f    # push range from 1 to 6
    31 31    # do set-wise difference with each of the two previous numbers
    25       # push a random element from the list
09           # end block
19 32        # repeat block 9 times

recursive

Posted 2011-02-15T22:37:04.490

Reputation: 8 616

I think gs2 is newer than this challenge. – lirtosiast – 2015-10-05T17:19:18.480

2

J, 30 characters

>:(?@4:{(i.6)-.],5&-)^:(<10)?6

6 2 3 5 4 2 4 1 3 6

Explanations (read from right to left):

  • ?6 returns a random number between 0 and 5
  • ^:(<10) applies a function 9 times, accumulating the results along the way. The function is:
  • ?@4:{(i.6)-.],5&-
    • ] , 5&- returns an array of the input number and its complement to 5 (we're handling 0-based numbers currently, so the sum of opposite faces is 5)
    • (i. 6) -. removes them from the full set of integers 0 to 5. We're left with all valid positions after a single tipping operation from the input position.
    • ?@4: { picks one of those at random.
  • >: increments the whole sequence to bring the figures back to the 1 to 6 interval.

J B

Posted 2011-02-15T22:37:04.490

Reputation: 9 638

Nice thought to ">:" at then end. – Eelvex – 2011-02-15T23:48:36.773

1@Eelvex I have no idea why real-world dice are 1 to 6 when all sensible reasoning about them uses 0 to 5. :D – J B – 2011-02-16T12:49:56.127

2

J

This should work but unfortunately J's random generator gets stuck after the 3rd iteration:

a=:>:i.6
f=:a#~1-(+&(a=])7&-)
((,(?4)&{@f@(_1&{))^:9)>:?6

6 4 5 4 5 4 5 4 5 4

Eelvex

Posted 2011-02-15T22:37:04.490

Reputation: 5 204

I'm by no measure a J expert, but it seems to me from what I suffered composing my J answer to this thread that (?4) tends to be rolled once and treated as a constant for subsequent iterations if you're not careful around it. I worked around it using a (?@4:)-like construct. – J B – 2011-02-16T12:48:27.360

2

Bash: 97 94 92 90 89 87

Heavily golfed from Aman ZeeK Verma's answer:

for((i=10,f=0;i--;))do
for((n=f;n==f||n+f==7;f=RANDOM%6+1))do :
done
printf $f
done

http://ideone.com/QiuTx

NB arguably it can be shrunk by 5 chars by changing the first line to for((;i++<10;)) but that makes assumptions which aren't always valid. It would work ok in ideone but someone running it from a shell could have i or f exported to something non-zero.

Peter Taylor

Posted 2011-02-15T22:37:04.490

Reputation: 41 901

I'd like to do a version without the inner loop, but I fear it will be longer. – Peter Taylor – 2011-02-16T11:06:59.487

This is extremely awesome, I am too raw for bash I guess :) – Aman ZeeK Verma – 2011-02-16T11:11:22.730

@Aman, most of it isn't bash-specific. It's just several dozen refinements with tests after each one and reversions when I broke something. The only bit which is really a bash trick is the noop, which I had to look up.

If you have time to read man bash, though, I recommend it. I once read it cover to cover, and just having a vague idea of what's possible and worth looking up has served me well. – Peter Taylor – 2011-02-16T11:36:45.937

2

Bash with only one loop: 100 99 98 96

for((i=10,f=RANDOM%6+1;i--;))do
printf $f
((n=RANDOM%4+1,m=f<4?f:7-f,f=n<m||++n<7-m?n:n+1))
done

http://ideone.com/XrZO7

The key idea is that to pick a random number in [1,x] which isn't equal to y you can pick a random number in [1,x-1] and then increment if it's >= y. For this problem we want a random number in [1,6] which isn't equal to f or 7-f. We have to do the two tests in order min(f,7-f), max(f,7-f).

Assuming an initially empty environment could save 2 chars by not initialising i and changing the loop condition to i++<10

Peter Taylor

Posted 2011-02-15T22:37:04.490

Reputation: 41 901

1

QBasic (71 characters)

The two newlines are necessary and included in the character count as one character each.

RANDOMIZE:FOR I=0TO 9
1N=INT(RND*6)+1:IF L=N OR L+N=7THEN 1
?N:L=N:NEXT

PleaseStand

Posted 2011-02-15T22:37:04.490

Reputation: 5 369

1

Java 8, 130 bytes

v->{int d=(int)(Math.random()*6+1),i=10,p;String r=""+d;for(;i-->0;r+=d)for(p=d;p==d|p+d==7;d=(int)(Math.random()*6+1));return r;}

Try it here.

As full program with verbose main-method this would be 178 bytes instead:

interface M{static void main(String[]a){int d=(int)(Math.random()*6+1),i=10,p;String r=""+d;for(;i-->0;r+=d)for(p=d;p==d|p+d==7;d=(int)(Math.random()*6+1));System.out.print(r);}}

Try it here.

Semi-port of @AmanZeeKVerma's Bash answer.

Explanation:

 v->{              // Method with empty unused parameter and String return-type
   int d=(int)(Math.random()*6+1),
                   //  Random dice-roll 1-6
       i=10,       //  Counter-integer, starting at 10
       p;          //  Temp integer to store new side
   String r=""+d;  //  Result-String, starting at the first dice-roll
   for(;i-->0;     //  Loop (1) 10 times:
       r+=d)       //    After every iteration, append the result with a random side
     for(p=d;      //   Set the new side to the current side
         p==d      //   Loop (2) as long as the new side and current side are the same
         |p+d==7;  //   or as long as both combined are exactly 7:
       d=(int)(Math.random()*6+1)
                   //    Set the new side to a random side 1-6
     );            //   End of loop (2)
                   //  End of loop (1) (implicit / single-line body)
  return r;        //  Return the result-String
}                  // End of method

Kevin Cruijssen

Posted 2011-02-15T22:37:04.490

Reputation: 67 575

1

MATLAB 58 bytes

a=randi(6)
for i=1:9;b=1:6;b([a,7-a])=[];a=b(randi(4))
end

aaaaa says reinstate Monica

Posted 2011-02-15T22:37:04.490

Reputation: 381

1

TI-BASIC, 38 34

For(I,1,9
Ans→X
Repeat Ans≠X and Ans≠7-X
randInt(1,6
End
Disp Ans
End

Boring solution, but it's shorter than the previous revision. I take advantage of the fact that on a fresh calculator, Ans is initialized to zero.

lirtosiast

Posted 2011-02-15T22:37:04.490

Reputation: 20 331

I don't know if it's possible, but I'll give 50 rep to anyone who can find a shorter solution. – lirtosiast – 2015-10-05T02:58:33.773

How are you calculating 34? – recursive – 2015-10-05T06:20:05.737

Each token here is one byte in memory; it's standard for TI-BASIC to be scored this way. If you have a calculator, type the program in, look at the memory management screen, then subtract 9 and subract the length of the program's name to get the code size.

– lirtosiast – 2015-10-05T16:47:20.497

0

R, 67 bytes

c(3,5,1,4,2,6)[(sample(1:6,1)+cumsum(sample((-2:2)[-3],9,T)))%%6+1]

Try it online!

There is a golfier R answer but this I think is a different approach from the answers submitted so far.

c(3,5,1,4,2,6)                                                     #A dice and its facets
               (sample(1:6,1)                                      #Initial dice roll
                             +cumsum(sample((-2:2)[-3],9,T)))      #9 tippings in c(-2,-1,1,2)
                                                             %%6+1 #converts to values in [0,6]
              [                                                   ]#

JayCe

Posted 2011-02-15T22:37:04.490

Reputation: 2 655

0

05AB1E, 23 bytes

6LΩUTFX?6LʒDXÊsX+7Ê*}ΩU

Can definitely be golfed, but I'm currently not seeing it..

Try it online.

Explanation:

6LΩ              # Pick a random value from the range [1,6]
                 #  i.e. [1,2,3,4,5,6] → 3
   U             # Save this random value in variable `X`
TF               # Loop 10 times:
  X?             #  Print `X` without newline to STDOUT
  6Lʒ     }      #  Create a range [1,6] again, and filter it by:
     DXÊ         #   Check if the current value is not equal to `X`
                 #    i.e. 1 and 3 → 1 (truthy)
                 #    i.e. 3 and 3 → 0 (falsey)
     sX+         #   Sum the current value with `X`
                 #    i.e. 1 and 3 → 4
                 #    i.e. 3 and 3 → 6
        7Ê       #   And check if it's not equal to 7
                 #    i.e. 4 and 7 → 1 (truthy)
                 #    i.e. 6 and 7 → 1 (truthy)
     *           #   If both checks are truthy, keep it in the filtered list
                 #    i.e. 1 and 1 → 1 (truthy)
                 #    i.e. 0 and 1 → 0 (falsey)
           Ω     #  Pick a random value from the filtered list
                 #   i.e. [1,2,5,6] → 1
            U    #  And save it in variable `X` for the next iteration of the loop

Kevin Cruijssen

Posted 2011-02-15T22:37:04.490

Reputation: 67 575

0

><>, 71 bytes

I'm glad I could showcase ><>'s x code-pointer randomization as I don't recall seeing it here.

a&0 v
 /2v
1x3v 
>x< <<
6x4v
 \5v ~
:{:/ ^?=}
:{:/ ^?=7+}
:~$<^&;!?:-1&n

You can try it on this online interpreter (paste code, submit, start).

Aaron

Posted 2011-02-15T22:37:04.490

Reputation: 3 689

You'll get my upvote once you fix the solution. – lirtosiast – 2015-10-05T21:08:40.647

@ThomasKwa Done, I might be able to golf it down a little bit but at least it's now functional. – Aaron – 2015-10-06T06:12:34.017