# Randomly select a character, plinko-style

Let's see how good your language of choice is at selective randomness.

Given 4 characters, A, B, C, and D, or a string of 4 characters ABCD as input, output one of the characters with the following probabilities:

• A should have a 1/8 (12.5%) chance to be chosen
• B should have a 3/8 (37.5%) chance to be chosen
• C should have a 2/8 (25%) chance to be chosen
• D should have a 2/8 (25%) chance to be chosen

This is in-line with the following Plinko machine layout:

   ^
^ ^
^ ^ ^
A B \ /
^
C D


Your answer must make a genuine attempt at respecting the probabilities described. A proper explanation of how probabilities are computed in your answer (and why they respect the specs, disregarding pseudo-randomness and big numbers problems) is sufficient.

## Scoring

This is so fewest bytes in each language wins!

• Can we assume the built-in random function in our language of choice is random? Jul 17, 2017 at 15:14
• @Mr.Xcoder within reason, yes. Jul 17, 2017 at 15:21
• So, for clarity, the input is always exactly 4 characters, and it should assign probabilities to each in accordance with exactly the provided Plinko layout? Generating Plinko layouts or simulating them is entirely unnecessary as long as the probabilities are correct within the accuracy provided by your random source? Jul 17, 2017 at 16:15
• @KamilDrakari correct. Jul 17, 2017 at 16:27
• Not very useful due to its length, but I found out that the expression ceil(abs(i - 6)/ 2.0) will map an index from 0-7 to an index from 0-3 with the appropriate distribution (0 111 22 33) for this challenge... Jul 17, 2017 at 17:18

# Java (OpenJDK 8), 40 38 bytes

s->s[5551>>2*(int)(Math.random()*8)&3]


Try it online!

5551 in base 10 is 01112233 in base 4. So let's randomly pick one of those base-4 digits using bit shift and selection, then pick the n-th character from the originating char[].

• I've been outgolfed! I figured there was a way to do it with bitwise operators, but I don't really know much about them... Nice job! Jul 18, 2017 at 12:11
• @SocraticPhoenix Thank you! I figured the algorithms were different enough that I should make another answer. However, while I came up with this myself, I had not seen until this morning that the same idea had already been posted. Jul 18, 2017 at 12:20

# Mathematica, 25 bytes

RandomChoice@{##,##2,#2}&


input

["A", "B", "C", "D"]

-23 bytes from @MarkS!

• The argument idea is very nice, but you don't need to introduce a random integer or use the byte-heavy StringTake. RandomChoice[{##,##2,#2}]& works in 26 bytes. Jul 18, 2017 at 1:22
• Whoops, I should have used @ to save a byte: RandomChoice@{##... Jul 18, 2017 at 12:24

# braingasm, 17 bytes

4[,>]<4r<#z[2r>].


Works like this:

4[,>]<             Input 4 bytes from stdin and stay in cell 3 (0-indexed).
<          Move left ...
4r           ... randomly between 0 (inclusive) and 4 (exclusive) times.
#z[   ]   If we're at cell 0,
>      move right ...
2r       ... with 50% probability.
.  Print the byte value of the cell.


Given the input ABCD, each character has 1/4 = 2/8 chance of being printed because of 4r, but if we selected A, we have 1/2 chance of printing B instead, giving A (1/4)/2 = 1/8 chance and B 1/4 + 1/8 = 3/8 chance.

# J, 16 bytes

(1?8:){1 3 2 2&#


## how?

• 1 3 2 2&# - copy the input elementwise, ie, 1 copy of A, 3 copies of B, etc, yielding the list ABBBCCDD
• 1?8: - choose 1 element at random from the list 0 1 2 3 4 5 6 7
• { - "From", ie, choose from ABBBCCDD the random index generated by 1?8:

Try it online!

• looks pretty golfy to me. though I don't know much about J.. Jul 18, 2017 at 21:59
• @Uriel thanks. sorry i assumed you knew J since you know APL well.... Jul 18, 2017 at 22:02
• just the basics, I mostly transpile from APL... Jul 18, 2017 at 22:02
• -1 byte: 1 3 2 2&#{~1?8:.
– cole
Mar 13, 2018 at 18:49

# C, 106 bytes

int f(){int r=(int)random()%8;if(!r--)return 'A';if(--r-->0)if(r<2)return 'C';else return 'B';return 'D';}

• Could you use the ternary operator ...?...:... to have only one return and drastically reduce your number of bytes? Jul 18, 2017 at 12:35

# q/kdb+, 15 13 bytes

Solution:

1?a,7#1_a:


Example:

q)1?a,7#1_a:"ABCD"
,"B"


Explanation:

This is pretty much a q version of the jelly solution. Create the list "ABCDBCDB" and then pick one item from it at random

Bonus:

Another q solution in 15 bytes, same style as the APL one:

1?(,/)1 3 2 2#'


A k version of this solution is 13 bytes:

1?,/1 3 2 2#'


# CJam, 11 bytes

XZYY]q.*smR


Try it Online

XZYY]    e# add [1,3,2,2] to stack
q        e# add input string to stack
.*       e# element-wise multiply the two arrays. char * int in CJam = repeat character x times
s        e# flatten result to string
mR       e# pick random char from string


# 05AB1E, 9 bytes

•20åÝ•.Rè


Try it online!

•20åÝ•   # Push 33221110.
.R  # Randomly selected index.
è # Character at that index.


# Octave, 30 28 bytes

@(S)S([1:4 2 2:4])(randi(8))


Try it online!

@(S)S('ABBBCCDD'(randi(8))-64)


Try it online!

Input is taken as a string of 4 characters.

Explanation:

Instead of [1 2 2 2 3 3 4 4 ] we can write 'ABBBCCDD'-64 and randomly select one of indexes and use the index to extract the desired character from the string.

## JavaScript (ES6), 25 bytes / 30 bytes

In both following versions, we're looking for two positive integers m and n such that n MOD (m + i) MOD 4 gives us results in [0...3] at the expected frequencies for i in [0...7].

### Version 1, 25 bytes

If a time-dependent formula is allowed, we can just do:

s=>s[11%(new Date%8+2)%4]


This one is using n = 11 (smallest possible value of n) and m = 2.

i | 2 + i | 11 % (2 + i) | 11 % (2 + i) % 4
--+-------+--------------+-----------------
0 |     2 |            1 |                1
1 |     3 |            2 |                2
2 |     4 |            3 |                3
3 |     5 |            1 |                1
4 |     6 |            5 |                1
5 |     7 |            4 |                0
6 |     8 |            3 |                3
7 |     9 |            2 |                2


### Demo

let f =

s=>s[11%(new Date%8+2)%4]

for(stat = {A:0, B:0, C:0, D:0}, i = 0; i < 80000; i++) {
stat[f("ABCD")]++;
}
console.log(stat);

### Version 2, 30 bytes

With the native JavaScript PRNG -- which generates a floating-point number in [0...1) -- we'd rather do:

s=>s[21%(Math.random()*8|8)%4]


Here, we use n = 21 and m = 8 because it allows us to do the addition and isolate the integer part at the same time with Math.random()*8|8.

i | 8 + i | 21 % (8 + i) | 21 % (8 + i) % 4
--+-------+--------------+-----------------
0 |     8 |            5 |                1
1 |     9 |            3 |                3
2 |    10 |            1 |                1
3 |    11 |           10 |                2
4 |    12 |            9 |                1
5 |    13 |            8 |                0
6 |    14 |            7 |                3
7 |    15 |            6 |                2


### Demo

let f =

s=>s[21%(Math.random()*8|8)%4]

for(stat = {A:0, B:0, C:0, D:0}, i = 0; i < 80000; i++) {
stat[f("ABCD")]++;
}
console.log(stat);

# PowerShell, 64 bytes

$args|%{($_-replace '(^.)(.)',"$1$2$2$2$'")[(Get-Random)%8]}  Try it online! It replaces the string abcd with abbbcdcd using regex witchcraft and then randomizes which of the eight characters it chooses. The regex is expensive; it requires a backtick per grouping, so there may be a better method using recursive lookups. Here's a quick explanation of the regex: For input abcd the full match is ab, grouping $1 is 'a', grouping $2 is 'b', and $' (note quote, not backtick) returns everything after the full match. Then, the pattern $1$2$2$2$' is substituted for the full match: abcd goes to $1$2$2$2$' + cd = abbbcdcd

# Bash, 52 bytes

f(){ c=$1$2$2$2$3$3$4$4;echo ${c:$(($RANDOM%8)):1};}  Usage exemple: $ f a b c d
b
$f a b c d d$ f a b c d
b
$f a b c d a  • the space after { is mandatory. Jul 19, 2017 at 12:15 • on 100000 iterations : a:12.41% , b 37.65%, c 24.93%, d 24,99% . with for i in$(seq 1 100000); do f a b c d ; done | awk '{ t[$1]++ } END { for(i in t){ print i " : " t[i];} }' Jul 19, 2017 at 12:21 # TI-Basic, 25 bytes sub(Ans,randInt(1,8),1 If int(2rand(Ans="A "B  • The characters should be taken as input. Jul 19, 2017 at 6:49 • Ok, fixed that. Jul 19, 2017 at 16:21 # Perl 5, 26 bytes say((A..D,B..D,B)[rand 8])  Try it online! # SmileBASIC, 31 bytes LINPUT S$N=RND(8)?S\$[N+!N*2>>1]


Pick a number from 0 to 7, add 2 if it's 0, then divide by 2.