/// m11 pong model: the same ideas as the snake model, for a different game. module Snake.Pong.Model open Snake.Model /// The ball's direction of travel, one cell per frame on each axis. type Velocity = { Dx: int; Dy: int } /// Which of the player's two keys are being held down right now. type Held = { Up: bool; Down: bool } type Score = { Player: int; Cpu: int } // RequireQualifiedAccess: write `PongStatus.Playing`, `Paddle.Up`, `PongAction.Frame`, so these cases never get // mixed up with the snake's `Playing`, `Up` and `Frame`. [] type PongStatus = | Playing | Over /// The two keys that move the player's paddle. [] type Paddle = | Up | Down /// A whole match. Positions are in cells: `Ball` is a cell of the 80x50 court; `Player` and `Cpu` are the y of the /// top cell of each paddle. `Seed` is the unsigned 32-bit random seed used to pick the direction of each serve. type PongState = { Ball: Point Vel: Velocity Player: int Cpu: int Held: Held Score: Score Status: PongStatus Seed: uint32 Frame: int } /// Everything that can happen in a match, as data. [] type PongAction = | Press of Paddle | Release of Paddle | Frame | Restart // The court, in cells. let W = 80 let H = 50 /// Pixels per cell. let PCELL = 8 /// Paddle height in cells. let PADDLE = 8 /// Column of the player's paddle (left) and of the cpu's paddle (right). let PLAYER_X = 2 let CPU_X = 77 /// Points needed to win the match. let WIN = 5 let initialPong (seed: uint32) : PongState = { Ball = { X = 40; Y = 25 } Vel = { Dx = 1; Dy = 1 } Player = 21 Cpu = 21 Held = { Up = false; Down = false } // `Score.Player` says which record is meant: PongState has Player and Cpu fields too. Score = { Score.Player = 0; Cpu = 0 } Status = PongStatus.Playing Seed = seed Frame = 0 }