Skip to content

Instantly share code, notes, and snippets.

@Kodiologist
Created April 20, 2015 00:21
Show Gist options
  • Save Kodiologist/8edb48eeea49ceecaaef to your computer and use it in GitHub Desktop.
Save Kodiologist/8edb48eeea49ceecaaef to your computer and use it in GitHub Desktop.
; https://www.reddit.com/r/mylittleprogramming/comments/335gc2/particularly_perplexing_programming_puzzle_2/
(require kodhy.macros)
(import
[hy [HySymbol]]
[kodhy.util [ret]]
[minesweeper [*]]) ; http://pastebin.com/HgHkuKZj, http://pastebin.com/u0Xg0JGz
(defmacro g [method-name &optional a1 a2]
(import re)
(setv method-name (HySymbol (+ "."
(re.sub r"_([0-9a-zA-Z])" (fn [m] (.upper (.group m 1)))
(str method-name)))))
(cond
[(not (none? a2))
`(~method-name grid ~a1 ~a2)]
[(not (none? a1)) (do
(unless (or (none? a1) (instance? HySymbol a1))
(raise (ValueError a1)))
`(~method-name grid (first ~a1) (second ~a1)))]
[True
`(~method-name grid)]))
(defn solve [grid]
(setv mines (set))
(setv cleared (set))
; Start at the center.
(g guess (// (g n-rows) 2) (// (g n-cols) 2))
; Main loop.
(while (not (g solved?)) (block
(for [visible (g iter-visible)]
(when (in visible cleared)
(continue))
(setv ns (list (g iter-neighbors visible)))
(setv n-mines-around (g n-mines-around visible))
; Clear all neighbors of 0-marked cells.
(when (= n-mines-around 0)
(for [neighbor ns]
(when (not (g visible? neighbor))
(g guess neighbor)))
(.add cleared visible)
(ret))
; Clear all unmarked neighbors of n-marked cells with
; exactly n marked neighbors.
(when (= n-mines-around (len (filt (in it mines) ns)))
(for [neighbor ns]
(when (and (not (g visible? neighbor)) (not-in neighbor mines))
(g guess neighbor)))
(.add cleared visible)
(ret))
; Mark all neighbors of n-marked cells with exactly n
; hidden neighbors.
(when (= n-mines-around (g n-hidden-around visible))
(for [neighbor ns]
(when (and (not (g visible? neighbor)) (not-in neighbor mines))
(.add mines neighbor)))
(.add cleared visible)
(ret)))
; Well, shoot, we're in an ambiguous situation. Choose a
; square that might not have a mine in it and hope for the
; best.
(setv x (block
(setv mine-probs {})
(for [visible (g iter-visible)]
(setv ns (list (g iter-neighbors visible)))
(setv n-mines-around (g n-mines-around visible))
(setv n-known (len (filt (in it mines) ns)))
(when (> n-mines-around n-known)
(setv maybes (filt
(and (not (g visible? it)) (not-in it mines))
ns))
(for [m maybes]
(setv (get mine-probs m) (max
(.get mine-probs m 0)
(/ (- n-mines-around n-known) (len maybes)))))))
(setv uninformed-mine-prob (/
(- (g n-mines) (len mines))
(len (filt (not-in it mines) (g iter-hidden)))))
(setv interior (list (g iter-interior)))
(when (not mine-probs)
; (print "no mine-probs")
(ret (first interior)))
; (print "(min (.values mine-probs))" (min (.values mine-probs)))
; (print "uninformed-mine-prob" uninformed-mine-prob)
(if (or (not interior) (< (min (.values mine-probs)) uninformed-mine-prob))
(ret (first (first (kwc sorted (.items mine-probs) :key second))))
; Otherwise, select from the interior. Get the closest
; interior square to the "maybe" squares.
(first (kwc sorted interior :key (fn [x] (sum (amap
(+
(abs (- (first x) (first it)))
(abs (- (second x) (second it))))
(.keys mine-probs)))))))))
; (display grid mines x)
; (print "")
(g guess x))))
(defn display [grid mines spot]
(for [r (range (g n-rows))]
(print (.join "" (amap (cond
[(= (, r it) spot)
"*"]
[(in (, r it) mines)
"m"]
[(not (g visible? r it))
"?"]
[(g n-mines-around r it)
(str (g n-mines-around r it))]
[True
"."])
(range (g n-cols)))))))
(import random)
(random.seed 8)
(testSolver solve)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment