The Double Slit Experiment

16

1

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.

Double slit example

TheLethalCoder

Posted 2017-08-02T09:38:26.823

Reputation: 6 930

Comments are not for extended discussion; this conversation has been moved to chat.

– Martin Ender – 2017-09-03T13:34:47.323

Answers

4

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:
 all(r(0,1)or c.addch(r(0,h-1),(i*(2-4*r(0,1))+n)*w-r(1,w),42)for i in range(n/2+1))
 c.refresh()
 time.sleep(0.1)  # not counted for byte total

algmyr

Posted 2017-08-02T09:38:26.823

Reputation: 858

4

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

Andrew Dunai

Posted 2017-08-02T09:38:26.823

Reputation: 321

1

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, tryfor((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 – 2017-08-02T15:20:54.730

3

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

enter image description here

J42161217

Posted 2017-08-02T09:38:26.823

Reputation: 15 931

This appears to be invalid, for n=5 there should only be 5 boxes, you have 9 – TheLethalCoder – 2017-08-02T18:20:21.177

I realised that I counted like {...3,2,1,2,3...}.I can fix it if it is not accepted – J42161217 – 2017-08-02T18:47:59.263

2@TheLethalCoder Fixed! Improved! Golfed! – J42161217 – 2017-08-02T22:37:04.197

Looks good, upvote from me – TheLethalCoder – 2017-08-03T07:50:55.480

2

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.

Ian H.

Posted 2017-08-02T09:38:26.823

Reputation: 2 431

Compile to an Action<int> to save bytes, while(true)->(while(1>0)->for(;;). using C=Console; or using static Console;. – TheLethalCoder – 2017-08-02T11:28:09.477

That application is allowed to be a delegate aswell? Didn't know that. I'll update it in a sec. – Ian H. – 2017-08-02T11:29:08.657

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 – 2017-08-02T11:31:31.497

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 – 2017-08-02T11:43:11.363

@TheLethalCoder That code doesn't work :/ Just gives alot of Variable is not existing in the current context errors. – Ian H. – 2017-08-02T12:38:53.837

Have you checked for the zero width characters that SE likes to add in? – TheLethalCoder – 2017-08-02T12:39:26.993

@TheLethalCoder Didn't even know that SE does that. I updated it, it's 256 on my counter though. – Ian H. – 2017-08-02T12:50:56.823

254 still, There's one after Next at r.Next(0,WindowHeight) and one in the Write at Write('*') – TheLethalCoder – 2017-08-02T14:08:35.663

@TheLethalCoder You were right. – Ian H. – 2017-08-02T14:12:53.680

1

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.

GIF

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)))))))

Carcigenicate

Posted 2017-08-02T09:38:26.823

Reputation: 3 295

0

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

                    Threading.Thread.Sleep(25);
                }
            };

            f(5);
        }
    }
}

TheLethalCoder

Posted 2017-08-02T09:38:26.823

Reputation: 6 930