                (mapcat (fn [[x y w h]]
                          ; left-transition means bumping into left side of wall
                          [(make-edge :left
-                                     (concat (moving-inc-c :x 16 x)
-                                             (between-c :y 0 100 #_(- y 16) #_(+ y h)))
+                                     [:and
+                                      (moving-inc-c :x 16 x)
+                                      (between-c :y 0 100 #_(- y 16) #_(+ y h))]
                                      #{:required [:this id] [:other [:wall x y w h]]})])
                        walls)
                ; x + 16 < x2 && x + dx*frame + 16 >= x2 + dx2*frame

        intervals))

(defn flatten-intervals [intervals]
  (reduce (fn [sofar interval]
            (if (simple? interval)
              (conj sofar interval)
              (into sofar (flatten-intervals interval))))
          []
          intervals))

(defn merge-overlapping [intervals]
  (let [intervals (flatten-intervals intervals)
        intervals (sort-intervals intervals)
        [last-i merged] (reduce (fn [[[amin amax :as a] merged] [bmin bmax :as b]]
                                  (if (intersection a b)
                                    [[amin (.max js/Math amax bmax)] merged]
                                    [[bmin bmax] (conj merged a)]))
                                [(first intervals) []]
                                (rest intervals))]
    (if (empty? intervals)
      []
      (conj merged last-i))))

(defn constrain-times [interval]
  (if (simple? interval)

         init
         (zipmap (map :id states) states)))

(defn guard? [g]
  (and (vector? g)
       (case (first g)
         (:gt :geq :leq :lt) (or (= (count g) 3) (= (count g) 4))
         (:and :or) (every? guard? (rest g)))))

; edge label is a set containing :required | button masks
(defn make-edge [target guard label]
  (assert (guard? guard) "Guard must be a boolean combination of difference formulae.")
  (println "guard:" guard)
  {:target target :guard guard :label label :update identity})

(defn make-state [id flows & edges]
  (let [edges (flatten [edges])
        edge-guards (map :guard (filter #(:required (:label %)) edges))]
    ; invariant is a disjunction of negated guards
    (println "es" edges "eguards" edge-guards)
    {:id id :flows flows :edges edges}))

(defn valid-for-inputs [transition inputs]
  ;todo: some :inputs label in transition's label must be a subset of inputs
  false)

(defn next-transition [has ha then inputs]
