   (Math/round
     (/ (Math/log x)
        (Math/log 2))))
+
+(defn ->tournament-teams
+  "Transform a sequence of team data into a map of team name->tournament team data."
+  [team-data]
+  (->> team-data
+       (remove (comp nil? :seed))
+       (map #(vector (:name %) (assoc % :weight 1 :avg-pts 0 :expected-value 0)))
+       (into {})))
+
+(defn ->tournament-bracket
+  "Transforms a bracket of team names and a map of tourament team data into a bracket of tournament teams."
+  [bracket tournament-teams]
+  (walk/postwalk-replace
+    tournament-teams
+    bracket))
+
+(defn- treeify-dispatch [node]
+  (cond
+    (and (coll? node) (= (count node) 2) (map? (first node)) (map? (last node)))
+    :branch
+
+    (and (map? node) (not (contains? node :upper)) (not (contains? node :lower)))
+    :leaf))
+
+(defmulti #^{:private true} treeify
+          treeify-dispatch)
+(defmethod treeify :default [node]
+  node)
+(defmethod treeify :branch [[upper lower]]
+  {:upper upper :lower lower})
+(defmethod treeify :leaf [node]
+  {:data {:teams (list node)} :upper nil :lower nil})
+
+(defn ->tournament-tree [bracket]
+  (walk/postwalk
+    treeify
+    bracket))
+
+(defn- compute-round-dispatch [_ node]
+  (when (and (map? node) (contains? node :upper) (contains? node :lower))
+    (if (get-in node [:data :round])
+      :branch
+      :root)))
+
+(defmulti #^{:private true} compute-round
+  compute-round-dispatch)
+(defmethod compute-round :default [_ node]
+  node)
+(defmethod compute-round :branch [_ node]
+  (let [current-round (get-in node [:data :round])]
+    (-> (assoc-in node [:upper :data :round] (dec current-round))
+        (assoc-in [:lower :data :round] (dec current-round)))))
+(defmethod compute-round :root [max-rounds node]
+  (compute-round max-rounds (assoc-in node [:data :round] max-rounds)))
+
+(defn round-info [max-rounds tree]
+  (walk/prewalk
+    (partial compute-round max-rounds)
+    tree))
 
 (defn weighted-pairing-log5
   "Compute and update the chance that Team a and Team b will advance when playing against each other,

  (vector
    (map
      #(update-in % [:expected-value] (fnil + 0 0)
        (get-in parent-team-map [(:name %) :expected-value])
        (:avg-pts %))
      field)
    children))


      (mapcat (partial apply weighted-pairing-pts pick-pts upset-pts)) ;calculate expected pts per game
      (reduce                                               ;aggregate game results together
        #(let [name (:name %2)]
          (if (contains? %1 name)
            (-> (update-in %1 [name :weight] + (:weight %2))
                (update-in [name :avg-pts] + (:avg-pts %2)))
            (assoc %1 name %2)))
        {})
      vals                                                  ;get the aggregation
      (#(vector % fields)))))                               ;preserve the tree
