Skip to content

Instantly share code, notes, and snippets.

@Nectarineimp
Created April 21, 2014 20:16
Show Gist options
  • Select an option

  • Save Nectarineimp/11155095 to your computer and use it in GitHub Desktop.

Select an option

Save Nectarineimp/11155095 to your computer and use it in GitHub Desktop.
2048 Machine Learning Mucking About
;; 2048 machine learning analysis
;; Order, Free Space, Weight Distribution
;; Scoring Analysis, Nabla ∇ Divergence
;; initial board state - choose wisest direction for move (up down left right)
;; 2 0 2 4 0 pairs (actually a scoring pair is in there once the space is crossed.)
;; 2 2 4 0 1 pair
;; 4 4 0 0 1 scoring pair, 1 blank pair
;; 4 0 8 0 1 blank pair
(def board '((2 0 2 4) (2 2 4 0) (4 4 0 0) (4 0 8 0)))
(def max-spaces 16)
(def max-pairs 24)
(def half-board (/ (count board) 2))
;; Order Analysis
;; We want to determine how ordered the board is. A board with a lot
;; of space is considered very ordered as is one with lots of pairs
;; of numbers on it. Order is good because it means we can score.
(defn get-vertical [coll]
(apply map list coll))
(defn count-pairs [coll]
(->> coll
(partition 2 1)
(filter (fn [[a b]] (= a b)))
count))
(def rotated-board (get-vertical board))
(partition 2 1 board)
(defn pairs [coll rotated-coll] (+ (apply + (map count-pairs coll))
(apply + (map count-pairs rotated-coll))))
(pairs board rotated-board)
(def ratio-pairs (/ (pairs board rotated-board) max-pairs))
ratio-pairs
;; This is how ordered the board is. Bigger is Better!
;; Free Space Analysis
;; The less space we have the less movement we will have. We need
;; space to make good pairs. If we are running low on space we
;; want to put empahasis on moves that reduce space.
(defn filter-zero [coll]
(filter (fn [a] (= 0 a)) coll))
(defn count-spaces [coll] (count (flatten (map filter-zero coll))))
(defn space-ratio [coll] (/ (count-spaces coll) max-spaces))
;; This is how much free space is in the board as a ratio. Bigger is Better!
;; Weight Distribution
;; We can tell which direction has the most high value numbers.
;; Since we know 2's and 4's come up as new tiles, we can set it
;; up so the most 2's and 4's are exposed.
(def weight-vector (vector
(apply + (flatten (take half-board board)))
;; Top
(apply + (flatten (nthrest board half-board)))
;; Bottom
(apply + (flatten (take half-board rotated-board)))
;; Left
(apply + (flatten (nthrest rotated-board half-board)))
;; Right
))
;; This will help us decide which direction to choose
;; if we end up with a tie.
;; Scoring Analysis
;; Determine the current scoring potential, the density
;; of points on tiles, and total points on tiles.
(defn total-points [coll]
(apply + (flatten board)))
(def total-points-initial (total-points board))
(def not-zero? (complement zero?))
(defn point-density [coll]
(/
(total-points coll)
(count (filter not-zero? (flatten board)))))
(point-density board)
;; Bigger is better!
(defn get-runs [coll]
(map #(partition-by identity %) (map #(filter not-zero? %) coll)))
(def runs-board (get-runs board))
(def runs-rotated-board (get-runs rotated-board))
(def two-plus? (fn [x]
(> (count x) 1)))
(defn get-scoring-runs [coll]
;; reduces the total runs into just scoring runs
(map #(filter two-plus? %) (get-runs coll))
)
(defn get-scoring-run-sizes [coll]
(map #(map count %) (get-scoring-runs coll))
)
(get-scoring-run-sizes board)
(get-scoring-run-sizes rotated-board)
(def scoring-runs-board (get-scoring-runs board))
(def scoring-runs-rotated-board (get-scoring-runs rotated-board))
(defn sub-score [coll]
;; Calculate score depending on how many numbers are in the run.
;; Count 2 and 3, double the first number.
;; Count 4, quadruple the first number.
(if (> 4 (count coll)) (* 2 (first coll)) (* 4 (first coll))))
(defn score-potential [coll]
(apply + (flatten (map #(map sub-score %) coll))))
;; Board should score 4+4+8 = 16
;; Rotated Board should score 4
scoring-runs-board
scoring-runs-rotated-board
(score-potential scoring-runs-board)
(score-potential scoring-runs-rotated-board)
;; This tells us that a left or right shift will get us more points
;; than an up or down shift.
;; Nabla ∇ Divergence
;; This is an analysis of how many options of movement will be left
;; within the board. It produces three numbers. The first two are
;; the number of rows and columns which can still move.
;; The third is the number of new spaces created. Calculating
;; existing divergence and future divergence of choices presents
;; an interesting analysis that fits in with the mathmatical
;; statement of intelligence which says choose the path of greater
;; divergence.
(defn agility [coll]
;; agility is the movement potential based on a row having
;; free space. A row has either 0 or 1 agility and
;; a board has 0 thru 4 agility.
;; If a row has nothing but spaces it has 0 agility.
;; So given a board with one clear row and 3 full rows,
;; for example, then the agility of left-right would be 0
;; and up-down would be 4.
(apply + (map #(if (and (not-empty? %) (> 4 (count %))) 1 0) (map filter-zero coll)))
)
(agility board)
;; left-right agility
(agility rotated-board)
;; up-down agility
(defn created-space [coll]
;; This is a prediction of how much space could be created by choosing a particular direction.
;; When space is at a premium this becomes a very important strategy. Ignoring high value moves
;; for low value but space clearing moves becomes an important option.
(->> coll
get-scoring-run-sizes
(map #(apply + %))
(map #(cond (= 2 %) 1 (= 3 %) 1 (= 4 %) 2 (= 0 %) 0))
(apply +))
)
(created-space board)
;; left-right swipe
(created-space rotated-board)
;; up-down swipe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment