X-Git-Url: http://nitlanguage.org diff --git a/lib/bucketed_game.nit b/lib/bucketed_game.nit index eba5d69..213d875 100644 --- a/lib/bucketed_game.nit +++ b/lib/bucketed_game.nit @@ -14,24 +14,31 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Provides basic game logic utilities using buckets to coordinate and -# optimize actions on game turn ends. Supports both action at each -# end of turn as well as actions on some end of turns. +# Game framework with an emphasis on efficient event coordination # -# Allows for fast support of a large number of entities with rare actions, -# such as a forest with many individual trees. -module bucketed_game +# Provides basic game logic entities to manage a game where the logic is executed by turns: +# `Game`, `GameTurn`, `GameEvent`, `Turnable`. +# Also offers a bucket system to plan future events at a known number of turns in the future: +# `Bucketable` and the services `act_next` and `act_in`. +# +# Efficiently support large number of entities with rare or sparse actions, +# such as a forest with many individual trees growing slowly. +module bucketed_game is serialize + +import serialization +import counter # Something acting on the game -class Turnable[G: Game] +abstract class Turnable[G: Game] # Execute `turn` for this instance. fun do_turn(turn: GameTurn[G]) is abstract end # Something acting on the game from time to time -class Bucketable[G: Game] +abstract class Bucketable[G: Game] super Turnable[G] + private var act_at: nullable Int = null # Cancel the previously registered acting turn @@ -49,7 +56,7 @@ class Buckets[G: Game] type BUCKET: HashSet[Bucketable[G]] private var next_bucket: nullable BUCKET = null - private var current_bucket_key: Int = -1 + private var current_bucket_key = -1 # Number of `buckets`, default at 100 # @@ -59,6 +66,9 @@ class Buckets[G: Game] private var buckets: Array[BUCKET] = [for b in n_buckets.times do new HashSet[Bucketable[G]]] is lazy + # Stats on delays asked when adding an event with `act_in` and `act_next` + private var delays = new Counter[Int] + # Add the Bucketable event `e` at `at_tick`. fun add_at(e: Bucketable[G], at_tick: Int) do @@ -100,6 +110,26 @@ class Buckets[G: Game] end end end + + # Get some statistics on both the current held events and historic expired events + fun stats: String + do + var entries = 0 + var instances = new HashSet[Bucketable[G]] + var max = 0 + var min = 100000 + for bucket in buckets do + var len = bucket.length + entries += len + instances.add_all bucket + min = min.min(len) + max = max.max(len) + end + var avg = entries.to_f / buckets.length.to_f + + return "{buckets.length} buckets; uniq/tot:{instances.length}/{entries}, avg:{avg.to_precision(1)}, min:{min}, max:{max}\n" + + "history:{delays.sum}, avg:{delays.avg}, min:{delays[delays.min.as(not null)]}, max:{delays[delays.max.as(not null)]}" + end end # Game related event @@ -117,20 +147,20 @@ end # Game logic on the client class ThinGame - # Game tick when `self` should act. + # Current game tick # # Default is 0. - var tick: Int = 0 is protected writable + var tick: Int = 0 is writable end # Game turn on the client class ThinGameTurn[G: ThinGame] - # Game tick when `self` should act. + # Game tick when happened this turn var tick: Int is protected writable - # List of game events occured for `self`. - var events = new List[GameEvent] is protected writable + # Game events occurred for `self`. + var events = new Array[GameEvent] is protected writable end # Game turn on the full logic @@ -147,10 +177,18 @@ class GameTurn[G: Game] end # Insert the Bucketable event `e` to be executed at next tick. - fun act_next(e: Bucketable[G]) do game.buckets.add_at(e, tick + 1) + fun act_next(e: Bucketable[G]) + do + game.buckets.add_at(e, tick + 1) + game.buckets.delays.inc(1) + end # Insert the Bucketable event `e` to be executed at tick `t`. - fun act_in(e: Bucketable[G], t: Int) do game.buckets.add_at(e, tick + t) + fun act_in(e: Bucketable[G], t: Int) + do + game.buckets.add_at(e, tick + t) + game.buckets.delays.inc(t) + end # Add and `apply` a game `event`. fun add_event( event : GameEvent )