diff --git a/sketching/september_2026/tiles.md b/sketching/september_2026/tiles.md new file mode 100644 index 0000000..a215d5d --- /dev/null +++ b/sketching/september_2026/tiles.md @@ -0,0 +1,212 @@ +# Deimos in a Game of Tiles + +```deimos +pub int TileGameMod + mut fn init(s: mut TileGameState) -> Void + mut fn tick(s: mut TileGameState) -> Void +end + +pub extern class TileGameState + pub extern fn tiles() -> List + + pub extern mut fn tilesMut() -> mut List + + pub extern fn player() -> Player +end + +pub int Tile + fn x() -> Size + fn y() -> Size + fn walkingSpeed() -> Speed + fn runningSpeed() -> Speed + fn draw(s: TileGameState) -> TileDraw +end + +pub record Color(red: Float, green: Float, blue: Float) end + +pub val-class Brightness + brightness: Double + + pub ctor(brightness: Double) + if brightness >= 0 && brightness <= 1 then + self.brightness = brightness + else + throw IllegalArgumentException("Cannot have a brightness outside of 0.0-1.0 range; given ${brightness}") + end + end +end + +pub record TileDraw(color: Color, brightness: Brightness) end + +pub record Speed(speed: Double) end + +pub extern class Player + pub extern fn isRunning() -> Boolean +end + +pub class GrassTile(x: Size, y: Size) : Tile + pub enum Season + Green, Brown + end + + mut season: Season + + pub mut fn flipSeason() -> Void + match self.season + Season::Green => self.season = Season::Brown, + Season::Brown => self.season = Season::Green + end + end + + pub fn x() -> Size = self.size + + pub fn y() -> Size = self.size + + pub fn walkingSpeed() -> Speed = Speed(2.5) + + pub fn runningSpeed() -> Speed = Speed(4.0) + + fn getColor() -> Color + if self.season == Season::Green + Color(0.0F, 1.0F, 0.0F) + else + Color(0.6F, 0.3F, 0.0F) + end + end + + pub fn draw(s: TileGameState) -> TileDraw + let color = self.getColor() + if s.player().isRunning() then + TileDraw(color, Brightness(0.9)) + else + TileDraw(color, Brightness(0.7)) + end + end +end + +pub class CoreMod : TileGameMod + mut tickCount = 0 + + pub mut fn init(s: mut TileGameState) -> Void + for x in 0..10 do + for y in 0..10 do + s.tilesMut() << GrassTile(x, y) + end + end + end + + pub mut fn tick(s: mut TileGameState) -> Void + self.tickCount++ + if tickCount == 16 * 10 then + self.tickCount = 0 + let randomX = std::num::randomSize(0, 10) + let randomY = std::num::randomSize(0, 10) + let tileNumber = randomX * 10 + randomY + let tile = s.tilesMut().getMut(tileNumber) + if tile is GrassTile then + tile.flipSeason() + end + end + end +end +``` + +```rust +struct TileGameState { + tiles: Gc<Object>, + player: Gc<Player> +} + +struct Player { + running: bool, + x: f64, + y: f64 +} + +struct Color { + r: f32, + g: f32, + b: f32 +} + +struct Brightness(f64); + +fn main() { + let mut dvm_context = load_context_with_mods(); + let mut dvm_state = DvmState::new(); + + dvm_context.add_platform_function("TileGameState::tiles", |args: &[Value]| { + let this: Gc<TileGameState> = args[0].unwrap_native_object().downcast::<TileGameState>(); + Value::Object(this.tiles) + }); + + dvm_context.add_platform_function("TileGameState::player", |args: &[Value]| { + let this: Gc<TileGameState> = args[0].unwrap_native_object().downcast::<TileGameState>(); + Value::Object(this.player) + }); + + dvm_context.add_platform_function("Player::isRunning", |args: &[Value]| { + let this: Gc<Player> = args[0].unwrap_native_object().downcast::<Player>(); + if this.running && is_in_bounds(this) { + Value::Boolean(true) + } else { + Value::Boolean(false) + } + }); + + let core_mod: Gc<Object> = construct_object(&mut dvm_state, &dvm_context, "CoreMod"); + let tile_game_state: GcAny = construct_native_object(&mut dvm_state, &dvm_context, "TileGameState", TileGameState { + tiles: construct_object(&mut dvm_state, &dvm_context, "std::collections::List"), + player: construct_native_object(&mut dvm_state, &dvm_context, "Player", Player { + running: false, + }).downcast::<Player>() + }); + + call(&mut dvm_state, &dvm_context, "TileGameMod::init", &[ + Value::Object(core_mod), + Value::NativeObject(tile_game_state), + ]); + + loop { + if tick() { + call(&mut dvm_state, &dvm_context, "TileGameMod::tick", &[ + Value::Object(core_mod), + Value::NativeObject(tile_game_state) + ]); + } + if frame() { + let tile_game_state: TileGameState = tile_game_state.downcast::<TileGameState>(); + let tiles: Array<Gc<Object>> = call( + &mut dvm_state, + &dvm_context, + "std::collections::List::toArray", + &[Value::Object(tile_game_state)] + ).unwrap_array(); + + for tile in tiles { + let x: usize = call(&mut dvm_state, &dvm_context, "Tile::x", &[ + Value::Object(tile) + ]).unwrap_size(); + let y: usize = call(&mut dvm_state, &dvm_context, "Tile::y", &[ + Value::Object(tile) + ]).unwrap_size(); + + let tile_draw: Gc<Object> = call(&mut dvm_state, &dvm_context, "Tile::draw", &[ + Value::Object(tile), + Value::NativeObject(tile_game_state) + ]).unwrap_object(); + let r: f32 = read_field_path(&tile_draw, "color.r").unwrap_float(); + let g: f32 = read_field_path(&tile_draw, "color.g").unwrap_float(); + let b: f32 = read_field_path(&tile_draw, "color.b").unwrap_float(); + let color = Color { + r, + g, + b + }; + let brightness = Brightness(read_field_path(&tile_draw, "brightness.brightness").unwrap_double()); + draw_tile(x, y, color, brightness); + } + } + } +} +``` \ No newline at end of file