Skip to content

Instantly share code, notes, and snippets.

@cwervo
Created October 18, 2018 07:07
Show Gist options
  • Save cwervo/9fe0d083f0a1a63393625b1be963c507 to your computer and use it in GitHub Desktop.
Save cwervo/9fe0d083f0a1a63393625b1be963c507 to your computer and use it in GitHub Desktop.
An entry for my Recurse Center pairing interview! Note: this requires boot to run Clojure!
#!/usr/bin/env boot
;; Note: this script requires Boot to run: https://github.com/boot-clj/boot#install
(def state (atom ["1" "2" "3"
"4" "5" "6"
"7" "8" "9"]))
;; Test state
#_(def state (atom ["X" "X" "3"
"4" "X" "6"
"O" "O" "9"]))
(def current-player (atom 1))
(defn exit [] (System/exit 0))
(defn get-next-line [] (flush) (first (line-seq (java.io.BufferedReader. *in*))))
(defn threeven? [n] (= 0 (mod n 3)))
(defn clear-screen []
; clear screen
(print (str (char 27) "[2J"))
; move cursor to the top left corner of the screen
(print (str (char 27) "[;H")))
(defn print-state [board]
(dorun
(map-indexed
(fn [idx itm]
(let [index-is-threeven (-> idx
inc
threeven?)]
(print (str itm (if index-is-threeven "\n" " | ")))))
board))
(println))
(defn in-board-bounds? [n]
(and (> n 0)
(< n 10)))
(defn string-is-number? [s] (some? (re-find #"^-?\d+$" s)))
(defn parse-int [s]
(Integer. s))
(defn spot-not-taken? [n]
(let [current-char (get @state n)]
(and (not= "X" current-char)
(not= "O" current-char))))
(defn retake-input [error-prompt]
(println error-prompt)
(get-next-line))
(defn validate-input [input]
(loop [recursiveInput input]
(when (re-matches #"^q(uit)?" recursiveInput)
(println "👋🏼")
(exit))
(if (string-is-number? recursiveInput)
;; First case (is a number):
(let [n (parse-int recursiveInput)]
(if (in-board-bounds? n)
;; Need to decriment because UI numbering is +1 of indexes :)
(if (spot-not-taken? (dec n))
n
(recur (retake-input (str "whoops, try again, spot " recursiveInput " is already taken"))))
(recur (retake-input (str "whooops, try again, " recursiveInput " is out of bounds")))))
;; Second case (not a number):
(recur (retake-input (str "whooops, try again, " recursiveInput " is not a number"))))))
(defn all-same? [collection-of-three]
(= 1 (count (distinct collection-of-three))))
(defn check-collection [collection]
(when (all-same? collection)
(let [row-symbol (first collection)
player-number (if (= "X" row-symbol)
1
2)]
(println (str "Game over! Player " player-number " ("row-symbol") wins! 🎉"))
(exit))))
(defn get-from-state [one two three]
[(get @state one)
(get @state two)
(get @state three)])
(defn check-for-win []
;; Brute force check
;; first row
(check-collection (subvec @state 0 3))
;; second row
(check-collection (subvec @state 3 6))
;; third row
(check-collection (subvec @state 6 9))
;; first column
(check-collection (get-from-state 0 3 6))
;; second column
(check-collection (get-from-state 1 4 7))
;; thrid column
(check-collection (get-from-state 2 5 8))
;; diagonal-1-9 column
(check-collection (get-from-state 0 4 8))
;; diagonal-7-3 column
(check-collection (get-from-state 6 4 2)))
(defn current-sign []
(get ["X" "O"] (dec @current-player)))
(defn evaluate-game-info []
(clear-screen)
(println "current state of the board:")
(print-state @state)
(check-for-win)
(println (str "Current player: " @current-player " ("(current-sign)"'s)")))
(while true
(evaluate-game-info)
(let [index (dec (validate-input (get-next-line)))]
;; Process current player move
(swap!
state
assoc index (current-sign))
(swap! current-player #(if (= %1 2) 1 2))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment