To practise a little F#, I'm building myself a simple game. The game involves resources
that players can spend. There are 3 kinds of resources. Items and actions in the game have an associated cost
that can combine amounts of any number of these resources (or none, for free actions). I started implementing this much along the lines of : Creating a list with multiple units of measurements of floats in F#
[<Measure>] type gold
[<Measure>] type wood
[<Measure>] type stone
type Resource =
| Gold of int<gold>
| Wood of int<wood>
| Stone of int<stone>
Now I need a collection data type to represent a cost
. I want it to :
Contain Resources
. Ideally it would be constrained to no more than 1 Resource of each type, but that safety I could do without.
Be unordered. (1<gold>, 2<wood>)
needs to equal (2<wood>, 1<gold>)
ideally without redefining equality for the type.
Be easily summable with another collection of the same type (actions may have optional costs which will add up to the normal cost) and subtractable (from a player's pool of resources).
What would be a good F# collection type to do that ? I realized not many are unordered. I was looking at Set<'T>
but the "based on binary trees" part has me a little confused and I'm not sure it suits my needs.
What do you think ? Did I miss something obvious in my design ?
If you need to represent resources containing some amount of gold, wood and stone, then it might make more sense to use a record type rather than a collection (e.g. a map or list) of discriminated unions.
For example, if you define your record like this:
type Resources =
{ Gold : int<gold>
Wood : int<wood>
Stone : int<stone> }
Then a value of Resources
satisfies all your criteria - it contains at most one filed for each kind of resource (it contains exactly one field of each kind, but the value can be zero). The fields are ordered, but the order does not matter (when creating the value) and you can also easily define +
operator on the type:
type Resources =
{ Gold : int<gold>
Wood : int<wood>
Stone : int<stone> }
static member (+) (r1:Resources, r2:Resources) =
{ Gold = r1.Gold + r2.Gold
Wood = r1.Wood + r2.Wood
Stone = r1.Stone + r2.Stone }
static member Zero =
{ Gold = 0<gold>; Stone = 0<stone>; Wood = 0<wood> }
I also added Zero
member, which makes it easier to create the record if you only want to set one of the resources. For example:
let r1 = { Resources.Zero with Gold = 2<gold> }
let r2 = { Resources.Zero with Wood = 4<wood> }
r1 + r2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With