Explain generic types and add DebugLevel to Player
This simulation engine is intended for people who are interested in game design, not computer programming -- the engine wants to do all the engine stuff so the simulation can be implemented with less familiarity with the language. Generics, however, are not widely regarded as a "new programmer" thing -- even though they're surprisingly familiar, in the end (slice-of-T, map-from-K-to-V). So a long comment explaining a bit about what's going on seems warranted.
This commit is contained in:
parent
7f8dcd63d6
commit
b324a39918
@ -2,7 +2,55 @@ package cardsim
|
||||
|
||||
import "math/rand"
|
||||
|
||||
// Player stores all gameplay state for one player.
|
||||
// Player stores all gameplay state for one player at a specific point in time.
|
||||
// Game-specific data is stored in Stats.
|
||||
//
|
||||
// Player is a generic type -- see https://go.dev/blog/intro-generics for more
|
||||
// information on how these work. Think of "Player" as a "type of type" --
|
||||
// when you create one, you tell it what kind of data it needs to keep for
|
||||
// the simulation itself, and each Player that works with a different kind of
|
||||
// data is a different kind of Player and the compiler will help you with that.
|
||||
// This is the same idea as "slice of something" or "map from something to
|
||||
// something" -- different kinds of Players are different from each other and
|
||||
// "know" what type of data they use, so the compiler can tell you if you're
|
||||
// using the wrong type.
|
||||
//
|
||||
// Generic types have to use a placeholder to represent the type (or types --
|
||||
// consider maps, which have both keys and values) that will be more specific
|
||||
// when the type is actually used. They're called "type parameters", like
|
||||
// function parameters, because they're the same kind of idea. A function puts
|
||||
// its parameters into variables so you can write a function that works with
|
||||
// whatever data it gets; a generic type takes type parameters and represents
|
||||
// them with type placeholders so you can write a *type* that works with
|
||||
// whatever specific other types it gets.
|
||||
//
|
||||
// Just like function parameters have a type that says what kind of data the
|
||||
// function works with, type parameters have a "type constraint" that says what
|
||||
// kind of types the generic type works with. Go already has a familiar way
|
||||
// to express the idea of "what a type has to do": `interface`. In Go, type
|
||||
// constraints are just interfaces.
|
||||
//
|
||||
// But wait, why use generics at all? Can't we just use an interface in the
|
||||
// normal way instead of doing this thing? Well, yes, we could, but then the
|
||||
// compiler doesn't know that the "real types" for things matching these
|
||||
// interfaces all have to actually be the same type. The compiler will stop
|
||||
// you from putting an `Orange` into a `[]Apple`, but it wouldn't stop you from
|
||||
// putting a `Fruit` into a `[]Fruit` because, well, of course it wouldn't,
|
||||
// they're the same type.
|
||||
//
|
||||
// Different simulation games made with `cardsim` are different. Rules made for
|
||||
// simulating the economy of a kobold colony and mine wouldn't work at all with
|
||||
// data for a simulation about three flocks of otter-gryphons having a
|
||||
// territory conflict over a river full of fish. By using generics, the compiler
|
||||
// can recognize functions and data and types intended for different simulation
|
||||
// games and prevent you from using the wrong one, when it wouldn't be able to
|
||||
// if all this stuff was written for "some simulation game, don't care what".
|
||||
//
|
||||
// Generic interfaces (like `Card[C]`, `Rule[C]`, `InfoPanel[C]`, and more)
|
||||
// don't mean you have to write generics of your own. It's exactly the opposite!
|
||||
// Because the interface has this extra type in it, you only need to implement
|
||||
// the specific kind of interface that works with your game. There's more detail
|
||||
// on this in the comment on `Rule[C]`.
|
||||
type Player[C StatsCollection] struct {
|
||||
Stats C
|
||||
Name string
|
||||
@ -19,4 +67,6 @@ type Player[C StatsCollection] struct {
|
||||
Turn int
|
||||
TemporaryMessages []Message
|
||||
TemporaryPanels []InfoPanel[C]
|
||||
|
||||
DebugLevel int
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user