Skip to content

Instantly share code, notes, and snippets.

@d4hines
Created March 1, 2019 22:39
Show Gist options
  • Save d4hines/9cce1849b3b9bdf6e4ddeceb550629eb to your computer and use it in GitHub Desktop.
Save d4hines/9cce1849b3b9bdf6e4ddeceb550629eb to your computer and use it in GitHub Desktop.
Perfect Square Gists
(ns constrained.core
(:require [reagent.core :as reagent]
[goog.dom :as dom]))
(set! *warn-on-infer* true)
(defn collision? [x y w h other-rectangles]
(some
(fn a-collision? [{:keys [left top width height]}]
(and
(< x (+ left width))
(> x (- left w))
(< y (+ top height))
(> y (- top h))))
other-rectangles))
(defn solve [current-x current-y target-x target-y w h other-rectangles]
(cond
(and (< current-x target-x) (not (collision? (inc current-x) current-y w h other-rectangles)))
(recur (inc current-x) current-y target-x target-y w h other-rectangles)
(and (> current-x target-x) (not (collision? (dec current-x) current-y w h other-rectangles)))
(recur (dec current-x) current-y target-x target-y w h other-rectangles)
(and (< current-y target-y) (not (collision? current-x (inc current-y) w h other-rectangles)))
(recur current-x (inc current-y) target-x target-y w h other-rectangles)
(and (> current-y target-y) (not (collision? current-x (dec current-y) w h other-rectangles)))
(recur current-x (dec current-y) target-x target-y w h other-rectangles)
:else
[current-x current-y]))
(defn move [{:keys [rectangles] :as app-state} idx target-x target-y]
(let [{:keys [left top width height]} (get rectangles idx)
other-rectangles (concat (take idx rectangles)
(drop (inc idx) rectangles))
[next-x next-y]
(if (collision? target-x target-y width height other-rectangles)
(solve left top target-x target-y width height other-rectangles)
[target-x target-y])]
(update-in app-state [:rectangles idx]
assoc :left next-x :top next-y)))
(defn main-view [app-state]
(let [rectangles (:rectangles @app-state)]
[:div
[:h2 "Drag the rectangles around..."]
(into
[:div {:style {:position "relative"}}]
(map-indexed
(fn [idx {:keys [left top width] :as rectangle}]
[:div {:draggable true
:style (merge rectangle
{:position "absolute"
:display "flex"
:align-items "center"
:justify-content "center"
:color "blue"
:height width
:font-size "50px"})
:on-drag-start
(fn rectangle-drag-start [^js/MouseEvent e]
(.setDragImage (.-dataTransfer e) (js/Image.) 0 0)
(swap! app-state assoc :drag-from
{:dx (- (.-clientX e) left)
:dy (- (.-clientY e) top)}))
:on-drag
(fn rectangle-drag [^js/MouseEvent e]
(let [{:keys [dx dy]} (:drag-from @app-state)
mouse-x (.-clientX e)
mouse-y (.-clientY e)]
;; TODO: better way to detect last event?
(when (or (not= mouse-x 0) (not= mouse-y 0))
(let [target-x (- mouse-x dx)
target-y (- mouse-y dy)]
(swap! app-state move idx target-x target-y)))))
:on-drag-end
(fn rectangle-drag-end [e]
(swap! app-state dissoc :drag-from))}
[:span (/ width multiplier)]])
rectangles))]))
(def multiplier 20)
(defn m [x] (* multiplier x))
(defn random-rect [top left width color]
{:top (m top) :left (m left)
:width (m width)
:background-color color})
(def rects [[22 14 10 "#090300"]
[0 0 18 "#db2d20"]
[0 18 15 "#fded02"]
[18 14 4 "#01a0e4"]
[15 18 7 "#a16a94"]
[15 25 8 "#01a252"]
[22 24 1 "#b5e4f4"]
[18 0 14 "#a5a2a2"]
[23 24 9 "turquoise"]])
(def app-state
(reagent/atom
{:rectangles (vec (map #(apply random-rect %) rects))}))
(reagent/render-component [main-view app-state]
(dom/getElement "klipse-container"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment