# 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
# Bucket type used in this implementation.
type BUCKET: HashSet[Bucketable[G]]
- private var buckets: Array[BUCKET] is noinit
-
private var next_bucket: nullable BUCKET = null
private var current_bucket_key: Int = -1
- init
- do
- var n_buckets = 100
- buckets = new Array[BUCKET].with_capacity(n_buckets)
+ # Number of `buckets`, default at 100
+ #
+ # Must be set prior to using any other methods of this class.
+ var n_buckets = 100
- for b in [0 .. n_buckets [do
- buckets[b] = new HashSet[Bucketable[G]]
- end
- end
+ 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)
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
# 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
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 )