Created
December 19, 2019 02:53
-
-
Save joinr/306570ae30337c8b6300abedcc2b0aee to your computer and use it in GitHub Desktop.
lanterna demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns lanternademo.core | |
(:require [lanterna.screen :as screen])) | |
;;provides a way to track resources and kill rendering from the outside. we | |
;;could also use an atom and synchronize on it from the rendering loop. I like | |
;;using future here though, since it keeps our REPL thread free. | |
(def renderer (atom nil)) | |
(defn kill-rendering! [] | |
(when @renderer | |
(future-cancel @renderer))) | |
;;helper macro to ensure we cleanup on exit. | |
;;we're not catching all the errors though.... | |
(defmacro with-screen [s & body] | |
`(let [~s (screen/get-screen) | |
out# ~'*out*] | |
(reset! renderer | |
(future | |
(try ~@body | |
(catch ~'Exception e# (binding [~'*out* out#] | |
(println e#))) | |
(finally (screen/stop ~s))))))) | |
(defn next-position [x y cmd] | |
(when-let [[dx dy] (case cmd | |
:right [1 0] | |
:down [0 1] | |
:left [-1 0] | |
:up [0 -1])] | |
[(max 0 (+ x dx)) (max 0 (+ y dy))])) | |
(def terminate? #{:escape :q}) | |
(defn update-state [{:keys [cursor-x cursor-y] :as state} k] | |
(if-let [[x y] (next-position cursor-x cursor-y k)] | |
(assoc state :cursor-x x :cursor-y y) | |
(assoc state :terminate? (terminate? k)))) | |
(defn render-cursor [scr {:keys [cursor-x cursor-y]}] | |
(doto scr | |
(screen/move-cursor cursor-x cursor-y) | |
(screen/put-string cursor-x cursor-y (str \0)))) | |
(defn render-random-blocks [scr] | |
(screen/put-string scr (rand-int 80) (rand-int 24) (str (gensym "x")) )) | |
(defn render-screen [scr {:keys [cursor-x cursor-y] :as state}] | |
(doto scr | |
(render-cursor state))) | |
(defn render [& {:keys [x y] :or {x 0 y 0}}] | |
(with-screen scr | |
(let [_ (doto scr screen/start | |
(screen/move-cursor 0 0))] | |
(loop [state {:cursor-x 0 :cursor-y 0 :terminate? nil}] | |
(screen/redraw scr) | |
(screen/clear scr) | |
(if-not (:terminate? state) | |
(let [nxt (update-state state (screen/get-key-blocking scr))] | |
(do (render-screen scr nxt) | |
(recur nxt))) | |
(println "Goodbye!")))))) | |
(comment | |
;;if we redefine render-screen here, should get picked up. | |
;;just copy/paste this into the repl, or eval it. | |
(defn render-screen [scr {:keys [cursor-x cursor-y] :as state}] | |
(doto scr | |
(render-cursor state) | |
(render-random-blocks))) | |
;;If we go back to normal, we get our old rendering back. | |
(defn render-screen [scr {:keys [cursor-x cursor-y] :as state}] | |
(doto scr | |
(render-cursor state))) | |
;;if we eval this one, the next move will shut down the screen | |
;;and print the error. | |
(defn render-screen [scr state] | |
(throw (ex-info "blowup!" {:msg :forced-error}))) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment