Isoraqathedh

Hipster Simulator 2014/5

Nov 25th, 2014
281
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 9.46 KB | None | 0 0
  1. ;;;; HIPSTER SIMULATOR 2014
  2. ;;;; By Isoraqathedh Zorethan <[email protected]>
  3. ;;;; A Common Lisp implmentation of the hipster model as seen in http://arxiv.org/abs/1410.8001.
  4.  
  5. (defpackage info.isoraqathedh.hipster-simulator
  6.   (:use :cl)
  7.   (:nicknames :hipster-simulator))
  8.  
  9. (in-package :hipster-simulator)
  10.  
  11. ;;; Classes
  12.  
  13. (defclass hipster-town-snapshot ()
  14.   ((ticks :initform 0
  15.           :initarg :time
  16.           :accessor ticks
  17.           :documentation "Ticks that have passed since the founding of this town.")
  18.    (population :initform nil
  19.                :initarg :population
  20.                :accessor population
  21.                :documentation "List of everyone who lives in the town, marked by their clothing choice.")
  22.    (styles :initarg :styles
  23.            :accessor styles
  24.            :documentation "Available styles. Styles are always represented by characters.")
  25.    (hipsterish-tendency :initarg :hipsterish-tendency
  26.                         :accessor hipsterish-tendency
  27.                         :documentation "How likely would any inidividual be nonconformist at any given time."))
  28.   (:documentation "A hipster town at a particular time."))
  29.  
  30. (defclass hipster-town-delay (hipster-town-snapshot)
  31.   ((period :initform 2
  32.            :initarg :period
  33.            :accessor period
  34.            :documentation "How long before the individuals know the clothing choice of their peers, measured in ticks.")
  35.    (history :initarg :history
  36.             :accessor town-history
  37.             :documentation "The last iterations of the simulation, for use in computing certain future iterations.")))
  38.  
  39. ;;; Class constructors
  40.  
  41. (defun generate-random-town (population styles)
  42.   "Generates a random town of n people with the given vector of styles."
  43.   (mapcar #'(lambda (a)
  44.               (declare (ignore a))
  45.               (aref styles (random (length styles))))
  46.           (make-list population)))
  47.                
  48. (defun build-new-town (population &key (hipsterish-tendency 2/3) (styles #(#\# #\.)))
  49.   "Builds a new town with a population of population, seeding with the two types of clothes."
  50.   (make-instance 'hipster-town-snapshot
  51.                  :population (generate-random-town population styles)
  52.                  :styles styles
  53.                  :hipsterish-tendency hipsterish-tendency))
  54.  
  55. (defun build-delayed-town (population period &key (hipsterish-tendency 2/3) (styles #(#\# #\.)))
  56.   (make-instance 'hipster-town-delay
  57.                  :population (generate-random-town population styles)
  58.                  :period period
  59.                  :history (make-array (list period))
  60.                  :hipsterish-tendency hipsterish-tendency
  61.                  :styles styles))
  62.  
  63. (defmethod initialize-instance :after ((instance hipster-town-delay) &key)
  64.   (setf (aref (town-history instance) (mod (ticks instance) (period instance))) (population instance)))
  65.  
  66. ;;; Common class methods
  67.  
  68. (defmethod print-object ((object hipster-town-snapshot) stream)
  69.   (with-accessors ((ticks ticks) (population population) (tendency hipsterish-tendency) (styles styles)) object
  70.     (print-unreadable-object (object stream :type t)
  71.       (format stream "~a ~4,2f%-hipsters with styles ~a @ t = ~a" (length population) (* tendency 100) (coerce styles 'list) ticks))))
  72.  
  73. (defmethod print-object ((object hipster-town-delay) stream)
  74.   (with-accessors ((ticks ticks) (population population) (tendency hipsterish-tendency) (styles styles) (period period)) object
  75.     (print-unreadable-object (object stream :type t)
  76.       (format stream  "~a ~4,2f%-hipsters with styles ~a, period ~a @ t = ~a" (length population) (* tendency 100) (coerce styles 'list) period ticks))))
  77.  
  78. ;;; Other methods
  79.  
  80. ;;; Methods pertaining to direct simulation
  81.  
  82. (defun true-with-probability (probability)
  83.   (assert (<= 0 probability 1) (probability))
  84.   (< (random 1.0) probability))
  85.  
  86. (defgeneric style-popularity (town &optional delete-1-stat)
  87.   (:documentation "Determines the popularity of each style in the town.")
  88.   (:method ((town hipster-town-snapshot) &optional delete-1-stat)
  89.     (loop with stats = (loop for style across (styles town)
  90.                              collect (cons style (if (eql style delete-1-stat) -1 0)))
  91.           for i in (population town)
  92.           do (incf (cdr (assoc i stats)))
  93.           finally (return (sort stats #'< :key #'cdr))))
  94.   (:method ((town hipster-town-delay) &optional delete-1-stat)
  95.     (call-next-method
  96.      (make-instance 'hipster-town-snapshot
  97.                     :styles (styles town)
  98.                     :population (aref (town-history town) (mod (1+ (ticks town)) (period town))))
  99.      delete-1-stat)))
  100.  
  101. (defgeneric deconform (town)
  102.   (:documentation "Simulates the selection of styles of all hipsters.
  103. In this case, they will attempt at random any style on the less popular half of the style.")
  104.   (:method ((town hipster-town-snapshot))
  105.     (mapcar #'(lambda (style-of-self)
  106.                 (cond
  107.                   ((true-with-probability (hipsterish-tendency town))
  108.                    (let ((candidate-styles
  109.                            (nbutlast
  110.                             (style-popularity town style-of-self)
  111.                             (ceiling (/ (length (styles town))) 2))))
  112.                      (car (nth (random (length candidate-styles)) candidate-styles))))
  113.                   ((true-with-probability 10/11) style-of-self)
  114.                   (t (aref (styles town) (random (length (styles town)))))))
  115.             (population town)))
  116.   (:method ((town hipster-town-delay))
  117.     (mapcar (if (numberp (aref (town-history town) (mod (1+ (ticks town)) (period town))))
  118.                 ;; While the history fills up, randomly wander, changing fashions 1/6 of the time
  119.                 #'(lambda (style-of-self)
  120.                     (if (true-with-probability 1/6)
  121.                         (aref (styles town) (random (length (styles town))))
  122.                         style-of-self))
  123.                 ;; After that, proceed as normal
  124.                 #'(lambda (style-of-self)
  125.                     (cond
  126.                       ((true-with-probability (hipsterish-tendency town))
  127.                        (let ((candidate-styles
  128.                                (nbutlast
  129.                                 (style-popularity town style-of-self)
  130.                                 (ceiling (/ (length (styles town))) 2))))
  131.                          (car (nth (random (length candidate-styles)) candidate-styles))))
  132.                       ((true-with-probability 10/11)
  133.                        style-of-self)
  134.                       (t (aref (styles town) (random (length (styles town))))))))
  135.             (population town))))
  136.  
  137. (defgeneric tick (town)
  138.   (:documentation "Nondestructively returns the next iteration of the simulation.")
  139.   (:method ((town hipster-town-snapshot))
  140.     (make-instance 'hipster-town-snapshot
  141.                    :time                (1+ (ticks town))
  142.                    :population          (deconform town)
  143.                    :styles              (styles town)
  144.                    :hipsterish-tendency (hipsterish-tendency town))))
  145.          
  146. (defgeneric tick! (town)
  147.   (:documentation "Destructively modifies a snapshot to become the next iteration of the simulation.")
  148.   (:method ((town hipster-town-snapshot))
  149.     (setf (population town) (deconform town))
  150.     (incf (ticks town)))
  151.   (:method :after ((town hipster-town-delay))
  152.     (setf (aref (town-history town) (mod (ticks town) (period town))) (population town))))
  153.  
  154. ;;; Reporting methods
  155.  
  156. (defgeneric print-population (town &key stream limit specific-style)
  157.   (:documentation "Prints out the first [limit] members in the population along with a generation number wearing the given style if non-nil.")
  158.   (:method ((town hipster-town-snapshot) &key (stream t) limit specific-style)
  159.     (with-accessors ((age ticks) (members population)) town
  160.       (if specific-style
  161.           (format stream "~&~3d: ~{~a~}~:[~;…~]" age (mapcar #'(lambda (a) (if (char-equal specific-style a)
  162.                                                                                          specific-style
  163.                                                                                          #\Space))
  164.                                                                        (subseq members 0 limit)) limit)
  165.           (format stream "~&~3d: ~{~a~}~:[~;…~]" age (subseq members 0 limit) limit)))))
  166.  
  167. (defgeneric print-popularity (town &key stream limit)
  168.   (:documentation "Prints out the first [limit] styles and its percentage popularity, along with a genreation number.")
  169.   (:method ((town hipster-town-snapshot) &key (stream t) limit)
  170.     (with-accessors ((age ticks) (members population) (styles styles)) town
  171.       (format stream "~&~3d:  " age)
  172.       (loop for i across styles
  173.             for j from 0 below (or limit (length styles))
  174.             do (format stream "~20@<~a ~7,2f%~>" i (/ (count-if #'(lambda (a) (char-equal i a)) members)
  175.                                                  (length members)
  176.                                                  1/100))))))
  177.  
  178. ;;; When seeing the development of the town, we need to repeat things a lot.
  179. (defmacro with-town-iterator ((var town &key (times 20) (tick-time :before)) &body body)
  180.   `(let ((,var ,town))
  181.      (assert (typep ,var 'hipster-town-snapshot))
  182.      (assert (typep ,tick-time '(member :before :after)))
  183.      (loop repeat ,times
  184.            do (progn
  185.                 ,(if (eql tick-time :before) `(tick! ,var))
  186.                 ,@body
  187.                 ,(if (eql tick-time :after) `(tick! ,var))))
  188.      ,var))
Advertisement
Add Comment
Please, Sign In to add comment