deimos-lang/sketching/september_2026/tiles.md
2026-09-04 21:13:23 -05:00

5.7 KiB

Deimos in a Game of Tiles

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<Tile>
  
  pub extern mut fn tilesMut() -> mut List<Title>
  
  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
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);
            }
        }
    }
}