Playing slot machines can be pretty fun, but don't be fooled by claims that the casino has the "loosest slots", odds are probably still against you. I thought it would be fun (and cheaper!) to build a slot machine simulator using Factor.
Our slot machine is going to be a console application that will look something like this:
Spinning
Even though our slot machine is text-only, we can still make use of some nice unicode characters to be our symbols:
CONSTANT: SYMBOLS "☀☁☂☃"
Each spin chooses a different symbol at random (each being equally likely):
: spin ( value -- value' )
SYMBOLS remove random ;
To reproduce the feel of spinning a slot machine, we will introduce a slight delay so that the wheel spins fast at the beginning and then slower and slower until it stops on a symbol:
: spin-delay ( n -- )
15 * 25 + milliseconds sleep ;
Spinning the slot machine takes a spin number, delays for a bit, then rotates each wheel (we stop spinning the first column after 10 spins, the second after 15, and the last after 20):
: spin-slots ( a b c n -- a b c )
{
[ spin-delay ]
[ 10 < [ [ spin ] 2dip ] when ]
[ 15 < [ [ spin ] dip ] when ]
[ drop spin ]
} cleave ;
Display
Each "spin" of the slot machine will be printed out. Using ANSI escape sequences, we move the cursor to the top left ("0,0") of the screen and then issue a clear screen instruction. Then we print out the current display and flush the output to screen:
: print-spin ( a b c -- a b c )
"\e[0;0H\e[2J" write
"Welcome to the Factor slot machine!" print nl
" +--------+" print
" | CASINO |" print
" |--------| *" print
3dup " |%c |%c |%c | |\n" printf
" |--------|/" print
" | [_] |" print
" +--------+" print flush ;
Playing
The player will have won if, after all the spins, the "pay line" shows three of the same characters:
: winner? ( a b c -- )
3array all-equal? nl "You WIN!" "You LOSE!" ? print nl ;
Playing the slot machine consists of spinning the wheels 20 times, displaying each spin to the user, then checking if the user has won the game.
: play-slots ( -- )
f f f 20 iota [ spin-slots print-spin ] each winner? ;
Since our casino wants the user to keep playing, we make it really easy to just hit ENTER to continue:
: continue? ( -- ? )
"Press ENTER to play again." write flush readln ;
And, to finish it off, we define a "MAIN" entry point that will be run when the script is executed:
: main-slots ( -- )
[ play-slots continue? ] loop ;
MAIN: main-slots
The code for this is on my Github.