<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" href="../../coverage.css"/> <title> the_great_game/merchants/planning.clj </title> </head> <body> <span class="covered" title="1 out of 1 forms covered"> 001 (ns the-great-game.merchants.planning </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 002 "Trade planning for merchants, primarily. This follows a simple-minded </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 003 generate-and-test strategy and currently generates plans for all possible </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 004 routes from the current location. This may not scale. Also, routes do not </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 005 currently have cost or risk associated with them." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 006 (:require [the-great-game.utils :refer [deep-merge make-target-filter]] </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 007 [the-great-game.merchants.merchant-utils :refer :all] </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 008 [the-great-game.world.routes :refer [find-route]] </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 009 [the-great-game.world.world :refer [actual-price default-world]])) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 010 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 011 (defn generate-trade-plans </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 012 "Generate all possible trade plans for this `merchant` and this `commodity` </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 013 in this `world`. </span><br/> <span class="blank" title="0 out of 0 forms covered"> 014 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 015 Returned plans are maps with keys: </span><br/> <span class="blank" title="0 out of 0 forms covered"> 016 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 017 * :merchant - the id of the `merchant` for whom the plan was created; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 018 * :origin - the city from which the trade starts; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 019 * :destination - the city to which the trade is planned; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 020 * :commodity - the `commodity` to be carried; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 021 * :buy-price - the price at which that `commodity` can be bought; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 022 * :expected-price - the price at which the `merchant` anticipates </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 023 that `commodity` can be sold; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 024 * :distance - the number of stages in the planned journey </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 025 * :dist-to-home - the distance from `destination` to the `merchant`'s </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 026 home city." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 027 [merchant world commodity] </span><br/> <span class="partial" title="3 out of 4 forms covered"> 028 (let [m (cond </span><br/> <span class="covered" title="3 out of 3 forms covered"> 029 (keyword? merchant) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 030 (-> world :merchants merchant) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 031 (map? merchant) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 032 merchant) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 033 origin (:location m)] </span><br/> <span class="covered" title="3 out of 3 forms covered"> 034 (map </span><br/> <span class="covered" title="11 out of 11 forms covered"> 035 #(hash-map </span><br/> <span class="covered" title="3 out of 3 forms covered"> 036 :merchant (:id m) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 037 :origin origin </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 038 :destination % </span><br/> <span class="covered" title="1 out of 1 forms covered"> 039 :commodity commodity </span><br/> <span class="covered" title="5 out of 5 forms covered"> 040 :buy-price (actual-price world commodity origin) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 041 :expected-price (expected-price </span><br/> <span class="covered" title="1 out of 1 forms covered"> 042 m </span><br/> <span class="covered" title="1 out of 1 forms covered"> 043 commodity </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 044 %) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 045 :distance (count </span><br/> <span class="covered" title="5 out of 5 forms covered"> 046 (find-route world origin %)) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 047 :dist-to-home (count </span><br/> <span class="covered" title="3 out of 3 forms covered"> 048 (find-route </span><br/> <span class="covered" title="1 out of 1 forms covered"> 049 world </span><br/> <span class="covered" title="3 out of 3 forms covered"> 050 (:home m) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 051 %))) </span><br/> <span class="covered" title="12 out of 12 forms covered"> 052 (remove #(= % origin) (-> world :cities keys))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 053 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 054 (defn nearest-with-targets </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 055 "Return the distance to the nearest destination among those of these </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 056 `plans` which match these `targets`. Plans are expected to be plans </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 057 as returned by `generate-trade-plans`, q.v.; `targets` are expected to be </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 058 as accepted by `make-target-filter`, q.v." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 059 [plans targets] </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 060 (apply </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 061 min </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 062 (map </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 063 :distance </span><br/> <span class="not-covered" title="0 out of 2 forms covered"> 064 (filter </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 065 (make-target-filter targets) </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 066 plans)))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 067 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 068 (defn plan-trade </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 069 "Find the best destination in this `world` for this `commodity` given this </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 070 `merchant` and this `origin`. If two cities are anticipated to offer the </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 071 same price, the nearer should be preferred; if two are equally distant, the </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 072 ones nearer to the merchant's home should be preferred. </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 073 `merchant` may be passed as a map or a keyword; `commodity` should be </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 074 passed as a keyword. </span><br/> <span class="blank" title="0 out of 0 forms covered"> 075 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 076 The returned plan is a map with keys: </span><br/> <span class="blank" title="0 out of 0 forms covered"> 077 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 078 * :merchant - the id of the `merchant` for whom the plan was created; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 079 * :origin - the city from which the trade starts; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 080 * :destination - the city to which the trade is planned; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 081 * :commodity - the `commodity` to be carried; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 082 * :buy-price - the price at which that `commodity` can be bought; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 083 * :expected-price - the price at which the `merchant` anticipates </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 084 that `commodity` can be sold; </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 085 * :distance - the number of stages in the planned journey </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 086 * :dist-to-home - the distance from `destination` to the `merchant`'s </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 087 home city." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 088 [merchant world commodity] </span><br/> <span class="covered" title="6 out of 6 forms covered"> 089 (let [plans (generate-trade-plans merchant world commodity) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 090 best-prices (filter </span><br/> <span class="covered" title="2 out of 2 forms covered"> 091 (make-target-filter </span><br/> <span class="covered" title="3 out of 3 forms covered"> 092 [[:expected-price </span><br/> <span class="covered" title="2 out of 2 forms covered"> 093 (apply </span><br/> <span class="covered" title="1 out of 1 forms covered"> 094 max </span><br/> <span class="covered" title="7 out of 7 forms covered"> 095 (filter number? (map :expected-price plans)))]]) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 096 plans)] </span><br/> <span class="covered" title="2 out of 2 forms covered"> 097 (first </span><br/> <span class="covered" title="3 out of 3 forms covered"> 098 (sort-by </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 099 ;; all other things being equal, a merchant would prefer to end closer </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 100 ;; to home. </span><br/> <span class="not-covered" title="0 out of 6 forms covered"> 101 #(- 0 (:dist-to-home %)) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 102 ;; a merchant will seek the best price, but won't go further than </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 103 ;; needed to get it. </span><br/> <span class="covered" title="2 out of 2 forms covered"> 104 (filter </span><br/> <span class="covered" title="2 out of 2 forms covered"> 105 (make-target-filter </span><br/> <span class="covered" title="3 out of 3 forms covered"> 106 [[:distance </span><br/> <span class="covered" title="10 out of 10 forms covered"> 107 (apply min (filter number? (map :distance best-prices)))]]) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 108 best-prices))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 109 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 110 (defn augment-plan </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 111 "Augment this `plan` constructed in this `world` for this `merchant` with </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 112 the `:quantity` of goods which should be bought and the `:expected-profit` </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 113 of the trade. </span><br/> <span class="blank" title="0 out of 0 forms covered"> 114 </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 115 Returns the augmented plan." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 116 [merchant world plan] </span><br/> <span class="covered" title="4 out of 4 forms covered"> 117 (let [c (:commodity plan) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 118 o (:origin plan) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 119 q (min </span><br/> <span class="partial" title="4 out of 5 forms covered"> 120 (or </span><br/> <span class="covered" title="9 out of 9 forms covered"> 121 (-> world :cities o :stock c) </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 122 0) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 123 (can-carry merchant world c) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 124 (can-afford merchant world c)) </span><br/> <span class="covered" title="11 out of 11 forms covered"> 125 p (* q (- (:expected-price plan) (:buy-price plan)))] </span><br/> <span class="covered" title="7 out of 7 forms covered"> 126 (assoc plan :quantity q :expected-profit p))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 127 </span><br/> <span class="covered" title="1 out of 1 forms covered"> 128 (defn select-cargo </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 129 "A `merchant`, in a given location in a `world`, will choose to buy a cargo </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 130 within the limit they are capable of carrying, which they can anticipate </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 131 selling for a profit at a destination." </span><br/> <span class="not-tracked" title="0 out of 0 forms covered"> 132 [merchant world] </span><br/> <span class="partial" title="2 out of 4 forms covered"> 133 (let [m (cond </span><br/> <span class="covered" title="3 out of 3 forms covered"> 134 (keyword? merchant) </span><br/> <span class="covered" title="5 out of 5 forms covered"> 135 (-> world :merchants merchant) </span><br/> <span class="not-covered" title="0 out of 3 forms covered"> 136 (map? merchant) </span><br/> <span class="not-covered" title="0 out of 1 forms covered"> 137 merchant) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 138 origin (:location m) </span><br/> <span class="covered" title="7 out of 7 forms covered"> 139 available (-> world :cities origin :stock) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 140 plans (map </span><br/> <span class="covered" title="2 out of 2 forms covered"> 141 #(augment-plan </span><br/> <span class="covered" title="1 out of 1 forms covered"> 142 m </span><br/> <span class="covered" title="1 out of 1 forms covered"> 143 world </span><br/> <span class="covered" title="5 out of 5 forms covered"> 144 (plan-trade m world %)) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 145 (filter </span><br/> <span class="covered" title="10 out of 10 forms covered"> 146 #(let [q (-> world :cities origin :stock %)] </span><br/> <span class="partial" title="9 out of 10 forms covered"> 147 (and (number? q) (pos? q))) </span><br/> <span class="covered" title="3 out of 3 forms covered"> 148 (keys available)))] </span><br/> <span class="covered" title="1 out of 1 forms covered"> 149 (if </span><br/> <span class="covered" title="5 out of 5 forms covered"> 150 (not (empty? plans)) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 151 (first </span><br/> <span class="covered" title="3 out of 3 forms covered"> 152 (sort-by </span><br/> <span class="not-covered" title="0 out of 6 forms covered"> 153 #(- 0 (:dist-to-home %)) </span><br/> <span class="covered" title="2 out of 2 forms covered"> 154 (filter </span><br/> <span class="covered" title="2 out of 2 forms covered"> 155 (make-target-filter </span><br/> <span class="covered" title="3 out of 3 forms covered"> 156 [[:expected-profit </span><br/> <span class="covered" title="10 out of 10 forms covered"> 157 (apply max (filter number? (map :expected-profit plans)))]]) </span><br/> <span class="covered" title="1 out of 1 forms covered"> 158 plans)))))) </span><br/> <span class="blank" title="0 out of 0 forms covered"> 159 </span><br/> </body> </html>