does somebody know a good “design pattern” to simplify this kind of code?
money!(player, money(player) + 100)
In other languages it would be something like this, via getters/setters:
player.money += 100
But I have no “money” attribute, only the methods to read/write the money. I thought about introducing a new type like “PlayerMoney”, which implements += etc.
And why are you against using a money field in the Player struct? This seems like the most natural way of doing things. If Player is only a thin immutable wrapper of an integer, then there is no point defining it, I think. But it seems more natural to throw in all the information of a player in that struct and then pass it around as a whole so you don’t have to worry about many vectors, just a single vector of players.
I don’t like a fixed set of attributes, since depending on the gametype or depending of the entities used inside a map, there might be money or not.
E.g. some maps and gametypes got no shop, so I dont wanna have a “money attribute” in a map without shops.
So if I would put all possible attributes into the player, I would loose this epic composability that Julia offers. I also like that I can quickly define a player by just using Player(23) e.g. This is perfect for C callbacks to go from a Int32 to a real player instance.
Yea, at the beginning I somehow worried about those extra playersMoney vectors, but I started to like this concept, since I can mix up everything dynamically just as I need it.
Hmm, the way I see it you have a couple of options:
Define a vector players and put the list of all possible info fields of the players, optional ones can be made Nullable or Union{T,Missing} using Missings.jl.
using Missings
mutable struct Player
id::Int
money::Union{Float64, Missing}
end
Define a single struct for all players’ info and put your field vectors in there. Then you can define getters and setters on the PlayersInfo struct directly using the player id.
struct PlayerID
id::Int
end
struct PlayersInfo
money::Vector{Union{Float64,Missing}}
end
getmoney(ps::PlayersInfo, pid::PlayerID) = ps.money[pid.id]
setmoney(ps::PlayersInfo, money, pid::PlayerID) = ps.money[pid.id] = money
Also consider using a Dict field in the player struct.
Hi, thanks you two for your inputs, but I am not quite happy with it yet. The custom properties would probably turn out nice, but currently I got dependencies, which only work on 0.6.2
I realised I need some kind of reference into the playersMoney array, so I came up with this:
importall Base
type ArrayElement{T}
array::Vector{T}
index::Int32
end
function (+)(this::ArrayElement{T}, other)::ArrayElement{T} where T
this.array[this.index] += T(other)
return this
end
So I can add a new money! method, but with only one argument:
That doesn’t make it any nicer/shorter and is just unnecessary term mixing. I don’t money players, I operate on the money of players, hence overloading the + operator (or -, * or / etc.). Shall I also make up terms for decreasing money, or shall I pay them negative values? That’s leading nowhere.
money! is a ridiculous name for that operation. And the operator overloading is odd, and makes the code unintuitive and hard to read.
pay! is indeed much nicer. But if you need to arbitrarily set their assets (which you did not make very clear), then something like setmoney!, setassets! or whatever.
Now you could just say: @set player money += 100, etc.
@macroexpand just returns the resulting expression, useful for debugging macros.
Notice that using esc in a whole expression is bad practice, but this is just a simple example, so it doesn’t do much error checking either about the shape of update_expr or str_op.