Chapter 6: Patterns all the way down

Role playing game

  • partial record patterns
  • as
  • Option

This one shows off Bea's record patterns. Player(name: None | _) matches any player whose name is None and ignores the other fields. The | _ means "and the rest".

as p keeps the whole value while you take it apart, so Player(p | health: 100) can rebuild it with one field changed. Guards still apply: revive treats high-level players differently.

Open in playground
pub type Player {
  Player(
    name:  Option(String),
    level: Int,
    health: Int,
    mana: Option(Int)
  )
}

pub def introduce(Player(name: None | _)) {
  "Mighty Magician"
}

pub def introduce(Player(name: Some(v) | _)) {
  v
}

pub def revive(Player(health: 0, level: l | _) as p) if l >= 10 {
  Some(Player(p | health: 100, mana: Some(100)))
}

pub def revive(Player(health: 0 | _) as p) {
  Some(Player(p | health: 100))
}

pub def revive(_) {
  None
}

pub def cast_spell(Player(mana: None, health: h | _) as p, cost) {
  updated_health = if h - cost < 0 {
    0
  } else {
    h - cost
  }
  
  (Player(p | health: updated_health), 0)
}

pub def cast_spell(Player(mana: Some(m) | _) as p, cost) if m < cost {
  (p, 0)
}

pub def cast_spell(Player(mana: Some(m) | _) as p, cost) {
  (Player(p | mana: Some(m - cost)), 2 * cost)
}

pub def main() {
  echo introduce(Player(name: None, level: 2, health: 8, mana: None))
  dead_player = Player(name: None, level: 2, health: 0, mana: None)
  echo revive(dead_player)
  alive_player = Player(name: None, level: 2, health: 42, mana: None)
  echo revive(alive_player)
  wizard = Player(name: None, level: 18, health: 123, mana: Some(30))
  echo cast_spell(wizard, 14)
}

An exercism exercise from the Gleam track, solved in Bea: beacode/src/e21_role_playing.bea