# The Double Slit Experiment

A lazy physicist has the job to perform the double slit experiment. However, they are lazy and can't be bothered to set up all the equipment themselves and so are going to simulate the effects. They can't program though so are going to need some help. As they are lazy your program should be as short as possible.

Given an odd positive integer n (n >= 1 and n % 2 == 1), perform the simulation.

How it works

You will start off with an empty canvas and each frame a single particle of light will go through the slits and land on the canvas. The particle will land at a maxima with a chance of:

n = 1:

+-----+
|     |
| 1/2 |
|     |
+-----+


n = 3:

+-----+ +-----+ +-----+
|     | |     | |     |
| 1/4 | | 1/2 | | 1/4 |
|     | |     | |     |
+-----+ +-----+ +-----+


n = 5:

+-----+ +-----+ +-----+ +-----+ +-----+
|     | |     | |     | |     | |     |
| 1/8 | | 1/4 | | 1/2 | | 1/4 | | 1/8 |
|     | |     | |     | |     | |     |
+-----+ +-----+ +-----+ +-----+ +-----+


etc.

For example for n=5 we check the middle box, there's a 50% chance of falling in it. If it falls end of frame, if not move to the next two, there's a 25% chance of falling in those. If it falls end of frame, if not move to the next two, there's a 12.5% chance of falling in those. If it doesn't fall it doesn't matter, it's still the end of the frame.

There has been some confusion over how to calculate the chances, most of this is due to people thinking of them as probabilities that should add up to 1. Remove that idea from your mind and it should clear it up a bit for you.

• At most one particle will lad per frame, this means a particle may not land at all on that frame.
• A particle can be represented by any printable character.
• The particle will land anywhere in the box with a random chance.
• The width of the boxes should be 2n-1 the size of the canvas. So for n=5 they should be 1/9th of the canvas's width.
• The height of the boxes should be the height of the canvas.
• The particle should not land outside of the boxes at all.
• If a particle has already landed at a spot that is chosen that doesn't matter it can land there again.
• The above ascii boxes are for clarity, they should not be drawn.
• You may choose your own canvas size as long as it is reasonable. For example, it mustn't just be a few pixels high. It also should be able to fit all of the boxes on it.
• If your code sleeps between frames you do not need to add that into your byte count.

There should be gaps between each of the maxima, a minima. This should be the same width as a box but no particles will land there. See the following diagram:

+---+---+---+---+---+
|   |   |   |   |   |
|max|min|max|min|max|
|   |   |   |   |   |
+---+---+---+---+---+


The program should run until it is stopped manually.

Rules

• A pseudo random number generator (pRNG) is fine.
• Standard loopholes are forbidden.
• Input may be taken by any reasonable format.
• You should output to STDOUT.
• This is so the shortest answer wins.

Example

The following GIF is an example run for n = 5. I only knocked it up quickly so the chances may be off slightly.

• Comments are not for extended discussion; this conversation has been moved to chat. – Martin Ender Sep 3 '17 at 13:34

# Python 2, 207 200 bytes

There is a method to this madness, I promise. Follows the probability interpretation I commented in the OP.

Edit: -7 bytes through some clever lazy evaluation (and removing some signs)

import time  # not counted for byte total
import random as R,curses as C
r=R.randint
c=C.initscr()
h,w=c.getmaxyx()
n=input()
w/=2*n-1
while 1:
c.refresh()
time.sleep(0.1)  # not counted for byte total


# BASH, 396 - 11 = 385 bytes

E='echo -en';$E "\e[2J\e[99A";while :;do sleep 0.01;for i in seq$((($1+1)/2)) -1 1;do p=$(((($1+1)/2 -$i)));[ $p -lt 0 ]&&p=$((-$p));p=$((2**(p+1)));if [ $RANDOM -lt$((32768/$p)) ];then [$(($RANDOM%2)) -eq 1 ]&&i=$((($1+1)-i));sector=$(((i*2-1)-1));C=tput cols;R=tput lines;SS=$((C/($1*2-1)));SX=$((SS*sector));X=$((SX+(RANDOM%SS)));Y=$((RANDOM%R));$E "\e[$Y;${X}H*";break;fi;done;done


Unfortunately I cannot demonstrate this on TryItOnline because of the endless loop & ANSI escape sequences that move cursor, but you can still copy-paste it into your terminal!

Unminified version:

E='echo -en'
$E "\e[2J\e[99A" while : do sleep 0.01 for i in seq$((($1+1)/2)) -1 1 do p=$(((($1+1)/2 -$i)))
[ $p -lt 0 ] && p=$((-$p)); p=$((2**(p+1)))
if [ $RANDOM -lt$((32768/$p)) ] then [$(($RANDOM%2)) -eq 1 ] && i=$((($1+1)-i)); sector=$(((i*2-1)-1))
C=tput cols
R=tput lines
SS=$((C/($1*2-1)))
SX=$((SS*sector)) X=$((SX+(RANDOM%SS)))
Y=$((RANDOM%R))$E "\e[$Y;${X}H*"
break
fi
done
done

• Check out the tips for golfing in bash. There are quite a few easy low-hanging fruit for you to harvest here - e.g. $[ ] instead of $(( )). Instead of for i in seq $((($1+1)/2)) -1 1;do ...;done, try for((i=($1+1)/2;i>0;i--));{ ...;}. Instead of [$((\$RANDOM%2)) -eq 1 ], try ((RANDOM%2)). sector, SS, etc should be replaced with 1 char variable names. – Digital Trauma Aug 2 '17 at 15:20

# Mathematica, 231 bytes

(R=RandomInteger;p=20(#+1)+10;s=Array[0&,{20,6p-3}];i=(#+1)/2;Monitor[While[1<2,y=RandomChoice[Join[q=Riffle[Array[2^#&,i,0],Table[0,i-1]],Reverse@Most@q]->Array[Range[4#+1]&,i,0][[i]]];s[[R@19+1,10y-R@9]]=1;s],Grid[s//. 0->" "]])&


input

[5]

output

• This appears to be invalid, for n=5 there should only be 5 boxes, you have 9 – TheLethalCoder Aug 2 '17 at 18:20
• I realised that I counted like {...3,2,1,2,3...}.I can fix it if it is not accepted – J42161217 Aug 2 '17 at 18:47
• @TheLethalCoder Fixed! Improved! Golfed! – J42161217 Aug 2 '17 at 22:37
• Looks good, upvote from me – TheLethalCoder Aug 3 '17 at 7:50

# C# (.NET 4.5), 319 254 bytes

Saved 65 bytes thanks to TheLethalCoder!

namespace System{using static Console;n=>{for(var r=new Random();;)for(int w=WindowWidth/(2*n-1),i=(n-1)/2,c=0,m=2,l;i>-1;i--,c+=2)if((l=r.Next(0,(m*=2+1)*2))<2){SetCursorPosition((i+(l<1?c:0))*2*w+r.Next(0,w),r.Next(0,WindowHeight));Write('*');break;}}}


Phew, that was a lot of work, but it works somehow.

Since this uses Console specific functions and Thread sleeping, it won't work on TIO, sadly.

• Compile to an Action<int> to save bytes, while(true)->(while(1>0)->for(;;). using C=Console; or using static Console;. – TheLethalCoder Aug 2 '17 at 11:28
• That application is allowed to be a delegate aswell? Didn't know that. I'll update it in a sec. – Ian H. Aug 2 '17 at 11:29
• Programs/functions are allowed by default and anonymous lambdas count as functions (Though the rules on them get a bit deeper when you need to call them). – TheLethalCoder Aug 2 '17 at 11:31
• 255 bytes namespace System{using static Console;n=>{for(var r=new Random();;)for(int w=WindowWidth/(2*n-1),i=(n-1)/2,c=0,m=2,l;i>-1;i--,c+=2)if((l =r.Next(0,(m*=2+1)*2))<2){SetCursorPosition((i+(l<1?c:0))*2*w+r.Next(0,w),r.Next(0,WindowHeight));Write('*');break;}}} – TheLethalCoder Aug 2 '17 at 11:43
• @TheLethalCoder That code doesn't work :/ Just gives alot of Variable is not existing in the current context errors. – Ian H. Aug 2 '17 at 12:38

# Clojure + Quil, 394 bytes

(use '[quil.core])(defn -main[n](let[w 999 h 100 c(/ w(-(* n 2)1))s(range 0 w c)a(vec(take-nth 2 s))v(fn[x](<(rand)x))q(fn[a b](+ a(rand-int(- b a))))g(for[i(range(int(/ n 2))-1 -1)][i(- n 1 i)])z(for[[j i](map vector(range 1(inc(count g)))g)][(/ 1(Math/pow 2 j))i])](defsketch m :size[w h]:draw #(loop[[[p i]& r]z](when p(if(v p)(let[o(a(rand-nth i))](point(q o(+ o c))(q 0 h)))(recur r)))))))


Well, I certainly didn't win, but this was a good brain workout! I may have picked a overly roundabout way of doing this, but it works! Basically, how it works is:

1. The x-values of each column are calculated based on n. Then, the "active colums" that will contain the dots are filtered out. The columns are then zipped with the possibilities that they'll be chosen.

2. The animation starts, and each frame, a loop is entered. Starting from the middle, each pair of columns is tried. Once one pair of columns is chosen, one column from the pair is randomly chosen.

3. A dot is drawn at a random position within the chosen column, the inner loop exits, and a new frame begins.

Uses the Quil graphics library, which is essentially a Processing wrapper for Clojure.

Note, the golfed code doesn't produce the same animation as shown in the GIF. In the golfed code, the background is grey, and the window and dots are smaller. It has the same effect, it's just not as pretty.

See the ungolfed code for an in-depth explanation:

(ns bits.golf.interference.interference
(:require [quil.core :as q]))

; Canvas size
(def width 1800)
(def height 800)

(defn -main [n]
(let [col-width (/ width (- (* n 2) 1))
; The left-most x of each column
col-starts (range 0 width col-width)

; The columns that need to be drawn. Need "vec" so I can index it later.
active-cols (vec (take-nth 2 col-starts))

; Function taking a decimal percentage, and returning whether or not it's satisfied.
; (chance? 0.5) would be used to simulate a coin toss.
chance? (fn [perc] (< (rand) perc))

; Function that returns a random int between a and b
r-int (fn [a b] (+ a (rand-int (- b a))))

; Generates index pairs for each complimentary column.
indices (for [i (range (int (/ n 2)) -1 -1)]
[i (- n 1 i)])

; Zips each index pair from above with the chance that it will be" chosen"
zipped-perc (for [[j i] (map vector (range 1 (inc (count indices))) indices)]
[(/ 1 (Math/pow 2 j)) i])]

; Animation boilerplate
(q/defsketch Interference
:size [width height]
:draw
; The animation loop. It contains a loop over each complimentary column. It tries each column pair starting
;  from the middle, and works outward. Once it picks a pair of columns, it randomly chooses one of them.
#(loop [[[p i] & r] zipped-perc]
(when p
; Pick this column?
(if (chance? p)
; Pick one of the column pairs
(let [col (active-cols (rand-nth i))]
; Set the coloring and dot size
(q/fill 0 0 0)
(q/stroke-weight 5)
; And finally draw the dot
(q/point (r-int col (+ col col-width))
(r-int 0 height)))

; If the column wasn't chosen, loop again to try the next one
(recur r)))))))


# C#, 238 bytes

namespace System{using static Console;n=>{for(var r=new Random();;)for(int i=0,p=1,w=WindowWidth/(2*n-1),x;i<n+1;i+=2)if(r.Next(p*=2)<1){SetCursorPosition(r.Next(x=(n-1+(r.Next(2)<1?i:-i))*w,x+w),r.Next(WindowHeight));Write("*");break;}}}


Try it online! (It won't work but y'know).

Full/Formatted version:

namespace System
{
using static Console;

class P
{
static void Main()
{
Action<int> f = n =>
{
for (var r = new Random(); ;)
{
for (int i = 0, p = 1, w = WindowWidth / (2 * n - 1), x; i < n + 1; i += 2)
if (r.Next(p *= 2) < 1)
{
SetCursorPosition(r.Next(x = (n - 1 + (r.Next(2) < 1 ? i : -i)) * w, x + w), r.Next(WindowHeight));
Write("*");
break;
}