Voters
April 6, 2012
To keep the display simple, we will use ansi terminal sequences to display a grid with 0 cells shown as spaces and 1 cells shown as asterisks. Here are the ansi terminal sequences we will need:
(define esc (integer->char 27))
(define (cls)
(display esc) (display #\[)
(display #\2) (display #\J))
(define (hide-cursor)
(display esc) (display #\[) (display #\?)
(display #\2) (display #\5) (display #\l))
(define (show-cursor)
(display esc) (display #\[) (display #\?)
(display #\2) (display #\5) (display #\h))
(define (goto x y)
(display esc) (display #\[) (display x)
(display #\;) (display y) (display #\H))
Show-cursor
isn’t used by the program, but you will need it when you interrupt the program and the cursor remains hidden. Be sure not to write at column 80, because doing so causes the screen to scroll.
We represent the grid as a two-dimensional matrix. The neighbor of a cell is chosen as a random x plus -1, 0 or 1, and likewise for y. This means that occasionally a cell is its own neighbor, but in that case the state of the grid is unchanged, and the simulation goes on to the next state.
The voters
function performs the simulation; first it initialized each cell to a random 0 or 1, then enters an infinite loop, at each step choosing a random cell and its random neighbor:
(define (voters)
(cls) (hide-cursor)
(let ((grid (make-matrix max-x max-y)))
(for (x 0 max-x)
(for (y 0 max-y)
(matrix-set! grid x y (randint 2))
(show x y (matrix-ref grid x y))))
(do () (#f)
(let* ((x (randint max-x))
(y (randint max-y))
(xx (modulo (+ x (randint 3) -1) max-x))
(yy (modulo (+ y (randint 3) -1) max-y)))
(matrix-set! grid x y (matrix-ref grid xx yy))
(show x y (matrix-ref grid x y))))))
The show
function displays a single cell. Showing 40 cells across the screen, with a space between each, gives the grid approximately the same spacing in both directions:
(define (show x y v)
(goto x (+ y y 1))
(display (if (zero? v) #\space #\*)))
(define max-x 24) (define max-y 39)
And that’s it. It’s fun to watch as one voting block gains dominance, the other fights back, and eventually one or the other dies. It is also fun to watch the anti-voters simulation, in which a random cell takes the opposite value of a random neighbor; as you might guess, where the normal voting simulation tends toward totalitarianism, the anti-voting simulation tends toward anarchy, where neither side can gain dominance over the other.
We used matrices and random numbers from the Standard Prelude. You can see the entire program at http://programmingpraxis.codepad.org/v3UEyvwd.
here’s my python version; much the same idea.
voters
Python 2.7 version with graph display using the built-in turtle graphics module.
if i could vote up comments, +1 to Mike for turtle graphics
Here’s a perl implementation, with comments!
[…] It’s called “Voters” and the full description of the problem can be found here. I wrote a terminal output version and then deleted that when I started working on a GTK3+Cairo GUI […]
[…] An exercise described here. […]
Written for Ruby 1.9.3, using Curses, run it in a terminal, and give it two arguments, the width and height in grid units of the grid:
In JavaScript:
http://jsbin.com/azebew/edit#preview
Python implementation: