DWEMTHY_S ARRAY^H^H^H^H^HLIST IN SCALLYDWEMTHY_S ARRAY^H^H^H^H^HLIST IN SCALLY

Last week the satanic Dwemthy’s Array was released into the quiet, pious town of Java programming. { AB } Both Java permutations used reflection to emulate some dynamic properties of the original, a recipe for sad exception handling if there ever was one. But it was helpful to be reminded of a few techniques to fight the clutter beast in Java code, even if defeating it is impossible.

The crux of the Ruby original is probably that method_missing can make an array act as one of its elements, which is the sort of thing Ruby is good at. An interesting topic to explore! But the game itself is cool, and after seeing the comment

# lettuce will build your strength and extra ruffage 
# will fly in the face of your opponent!!

it became pretty impossible not to translate it into the house favorite language, Scala.

There is no sense in imitating the dynamic typing pirouettes of the original using Scala, but this Dwemthy permutation will try to make up for the lost dynamic awesome with other kinds of awesome that Scala is good at, like functional programming and mostly painless typing.

And, Scala like Ruby allows you to define methods that look like operators, declare multiple base types in one file, and it has an interpreter. That way the player can load a single source and play within the interpreter, which is the real ultimate power of Dwemthy. The Java implementations, with their class source file ensembles and keyboard input loops, have shown up at the beach wearing business casual yet again.

// clock-seeded pseudorandom sequences are for sharing!
object Random extends Random

trait Creature {
  val life: Int
  val strength: Int
  val charisma: Int
  val name: String

  // abstract type to escape from square braces[][][][]
  type Copy <: Creature
  def copy(life: Int): Copy

  def rand(until: Int) = Random.nextInt(until)

  def hit(damage: Int) = copy(
    (rand(charisma) match {
      case p_up if p_up % 9 == 7 => 
        printf("[%s magick powers up %d!]\n", name, p_up)
        p_up / 4
      case _ => 0
    }) + life - damage match {
      case death if death <= 0 => 
        printf("[%s has died.]\n", name)
        death
      case l => l
    }
  )
}

A Creature is something that can be hit with damage and that has certain attributes. Note that these are immutable. The hit method returns a new copy of the Creature with a new life value, thus it requires an abstract method to produce this copy and an abstract type to say what that copy will be. Otherwise, the value returned by hit would simply be a Creature and we could no longer use the wonderful weapons that only the rabbit possesses. You can do the same thing with type parameters, but the abstract type is self-documenting and doesn’t clutter up the class/trait introduction with distracting symbols.

Pattern matching! If you want to know why it’s used here instead of a plain old ifs, the answer is that match gives you a nicely scoped reference to its input object. That makes it easier to write functions that evaluate to a single expression instead of a series of expressions and a bunch of values for things that you need to use just twice. Although, it seems like there may be an even more awesome way to do this kind of thing; if you know one, please don’t keep it to yourself!

trait Enemy extends Creature {
  // enemies beget enemies
  type Copy = Enemy
  // and hold one (1) weapon
  val weapon: Int
}

Yep. In the Ruby version, rabbit has a weapon value that isn’t used in normal gameplay, so here in pedantic typing land we will just put that right in Enemy where it belongs. Also now the Copy type is set once and for all enemies with this trait.

case class Rabbit(rem_life: Int, bombs: Int) extends Creature {
  // and rabbits make... MORE RABBITS
  type Copy = Rabbit
  val life = rem_life
  val strength = 2
  val charisma = 44
  val name = "Rabbit"

  def fight(enemy: Enemy, weapon: Int) =
    if (life <= 0) {
      printf("[%s is too dead to fight!]\n", name)
      (this, enemy)
    } else {

      // Attack the opponnent
      val your_hit = rand(weapon + strength)
      printf("[You hit with %d points of damage!]\n", your_hit)
      val damaged_enemy = enemy hit your_hit
  
      //Retaliation
      println(damaged_enemy)
      ( if (damaged_enemy.life > 0) {
          val enemy_hit = rand(damaged_enemy.weapon + damaged_enemy.strength)
          printf("[Your enemy hit with %d points of damage!]\n", enemy_hit)
          this hit enemy_hit
        } else this
      , damaged_enemy)
    }

  def copy(life: Int) = new Rabbit(life, bombs)

  // little boomerang
  def ^ (enemy: Enemy) = fight(enemy, 13)

  // the hero's sword is unlimited!!
  def / (enemy: Enemy) =
    fight(enemy, rand(4 + (enemy.life % 10) * (enemy.life % 10)))

  // lettuce will build your strength and extra ruffage
  // will fly in the face of your opponent!!
  def % (enemy: Enemy) = {
    val lettuce = rand(charisma)
    printf("[Healthy lettuce gives you %d life points!!]\n", lettuce)
    Rabbit(life + lettuce, bombs).fight(enemy, 0)
  }

  // bombs, but you only have three!!
  def * (enemy: Enemy) =
    if (bombs <= 0) {
      println("[UHN!! You're out of bombs!!]")
      (this, enemy)
    } else
      Rabbit(life, bombs-1).fight(enemy, 86)
}

object Rabbit extends Rabbit(
    10, // life
    3)  // bombs

(Ruffage is condensed roughage.) This is pretty self explanatory maybe. All case classes get a halfway decent automatic toString that prints their constructor values. The deal with fight and all the weapon-specifc methods is, they return a tuple made up of your guy and the enemy. We need this because both usually change in one turn, thanks to retaliation.

// the P is for ''''PRIME''''
case class EnemyP(life:Int, strength:Int, charisma: Int, weapon: Int, 
    name: String) extends Enemy {
  // https://lampsvn.epfl.ch/trac/scala/ticket/321 grrr!!!
  def copy(life: Int): Enemy = EnemyP(life, strength, charisma, weapon, name)
}

// Critters are easy to define
trait Critter extends Enemy {
  def copy(life: Int): Enemy = EnemyP(life, strength, charisma, weapon, name)
}

Done! Now we can conjure ScubaArgentine.

object ScubaArgentine extends Critter {
  val life = 46
  val strength = 35
  val charisma = 91
  val weapon = 2
  val name = "Scuba Argentine"
}

And have an interpretive fight.

scala> var play = Rabbit / ScubaArgentine
[You hit with 5 points of damage!]
EnemyP(41,35,91,2,Scuba Argentine)
[Your enemy hit with 27 points of damage!]
[Rabbit has died.]
play: (Rabbit, Enemy) = (Rabbit(-17,3),EnemyP(41,35,91,2,Scuba Argentine))

Aw. You can see that toString is not ideal. We’ll get back to that, and the names. For now, replay the match until rabbit survives a round. play is the only variable in this game, so that it can be updated and reused with each turn.

scala> play = Rabbit / ScubaArgentine
[You hit with 2 points of damage!]
EnemyP(44,35,91,2,Scuba Argentine)
[Your enemy hit with 0 points of damage!]
play: (Rabbit, Enemy) = (Rabbit(10,3),EnemyP(44,35,91,2,Scuba Argentine))

Now we’re talking. And to play the next turn:

scala> play = play._1 % play._2

Or

scala> play = play match { case (r, e) => r % e }

And so on! (The interpreter’s input history is helpful.) Now for the evil DwemthysList.

// is-NOT-a-list-but-*has*-one and that will have to do
class DwemthysList(head: Enemy, tail: List[Enemy]) extends EnemyP(
    head.life, head.strength, head.charisma, head.weapon, head.name) {

  override def copy(life: Int) =
    if (life <= 0) {
      if (tail.isEmpty) {
        println("[Whoa.  You decimated Dwemthy's Array!]")
        head.copy(life)
      } else {
        printf("[Get ready. %s has emerged.]\n", tail.head.name)
        new DwemthysList(tail.head, tail.tail)
      }
    } else new DwemthysList(head.copy(life), tail)
}

// but can-construct-as-a-list!
implicit def list2dwemthy(list: List[Enemy]) = new DwemthysList(list.head, list.tail)

The awesome dynamicy implicit was J. I.’s idea.

That list2dwemthy will turn a regular list into a DwemthysList whenever one is required. And finally, code is data or whatever.

object IndustrialRaverMonkey extends Critter {
  val life = 46
  val strength = 35
  val charisma = 91
  val weapon = 2
  val name = "IndustrialRaverMonkey"
}

object DwarvenAngel extends Critter {
  val life = 540
  val strength = 6
  val charisma = 144
  val weapon = 50
  val name = "DwarvenAngel"
}

object AssistantViceTentacleAndOmbudsman extends Critter {
  val life  = 320
  val strength = 6
  val charisma = 144
  val weapon = 50
  val name = "AssistantViceTentacleAndOmbudsman"
}

object TeethDeer extends Critter {
  val life = 655
  val strength = 192
  val charisma = 19
  val weapon = 109
  val name = "TeethDeer"
}

object IntrepidDecomposedCyclist extends Critter {
  val life  = 901
  val strength = 560
  val charisma = 422
  val weapon = 105
  val name = "IntrepidDecomposedCyclist"
}

object Dragon extends Critter {
  val life = 1340     // tough scales
  val strength = 451  // bristling veins
  val charisma = 1020 // toothy smile
  val weapon = 939    // fire breath
  val name = "Dragon"
}

val dwlist = List(IndustrialRaverMonkey,
                  DwarvenAngel,
                  AssistantViceTentacleAndOmbudsman,
                  TeethDeer,
                  IntrepidDecomposedCyclist,
                  Dragon)

Now you can attack the list.

scala> var play = Rabbit / dwlist

Maybe you will win—anything is possible! Hint, try not to forget the game is played in a programming environment. Dwemthy didn’t say anything about writing recursive functions, so, why not. Simple algorithms have been known to get to the dragon, but probably can’t beat him without overflowing int. Yeah it’s that serious.

dwemthy.scala

And about that toString—lame. Ruby has a much nicer display of the attributes than the case class is giving, at least the way it’s used here. Lamer still is the fact that we’re naming the creatures with Strings instead of using type information, but, that’s harder than it looks. Can you even get that information at construction time? In a trait? Maybe a lazy val would work, but then the case class won’t output it? There has got to a way to improve the name and status printing without a bunch of uglycode. And since the source above is hosted at the new technically.us git node, you can totally clone and branch.

But whatever you do, do not put a variable in there or Dwemthy will personally show you a whole new world of hurt.

Codercomments

I’m not sure that I agree with the decision to make creatures immutable. I mean, I like immutable data as much as the next guy, but some things are just naturally statefull (that’s why Scala has var). It just seems like it would be more natural if you didn’t have to keep worrying about managing the creature by hand-ish.

That is the kind of thinking that will talk you out of ever using immutable state! In theory it’s appropriate for everything; the more state to be maintained, the greater the clarity and reliability advantage. Not that I buy that necessarily, but it worked nicely in this trial. And otherwise it would have been boringly too much like the Ruby version.

Actually, immutable data is even better for a game than for everything else.

Want a nice display of the game’s history at the end? No problem, just keep all of the data objects and iterate over them to tell the story (mostly).

Want a magic weapon that rewinds time? With immutable state, you just hang onto the old objects for a bit. With mutable state, you have to keep enough data to reverse whatever you did.

Yeah, having a state history is sweet. If you play this game in the Scala interpreter and don’t assign a play variable, you get automatic incremental references to character snapshots. But then you also have to increment your input for the next turn.

Does anybody know of good immutable examples around the web, preferably in a language that most people can read? I couldn’t find squat. Mostly I wanted to know the typical names for functions and values that would have to be common in this kind of programming, but I’m sure there’s also a lot of techniques I didn’t arrive at on my own.

The best examples of advanced immutable programming are going to be in languages like Haskell, ML, and Scheme. That kind of design isn’t as well used in any of the more popular languages. But that’s okay, learning those languages builds even more strength and ruffage than eating lettuce.

A thought: instead of object DwemthysList {def apply…}, how ‘bout this?

implicit def list2Enemy(enemies:List[Enemy]) = new DwemthysList(enemies.head, enemies.tail)

val dwlist = List(ScubaArgentine,...)
var play = r / dwlist

Seems to capture some of the spirit of the original method_missing.

As for getting names of classes and properties and such, Scala doesn’t currently offer a better answer than Java reflection. You can “pimp” the reflection library a bit to make it a little cleaner to use, but it’s still reflection in the end.

Perhaps some day Scala will offer template meta-programming or at least something along the lines of Haskell’s SYB.

Hi James, I suppose it would at least be worth learning to read those languages. Maybe then I will understand MONADS. (I did enjoy your series on them, but my brief, partial cognizance of flatMap has since evaporated.)

I love the implicit List conversion idea, will definitely make that change.

The thing with using reflection for the name is it can’t produce a value for the case class.

scala> case class A(val name: String)
defined class A

scala> class NamedThing extends A(getClass.getName)
defined class NamedThing

scala> new NamedThing
res29: NamedThing = A()

I guess Scala makes a fake this for the constructor and the class it gives back is nameless. Fine. I mean, I wouldn’t expect that work anyway. :\

What you’re doing there is equivalent to val name = getClass.getName class NamedThing extends A(name)

It is interesting that the interpreter’s top level object has a class with no name. I had never even thought to look.

Anyway, to achieve the desired effect would require overriding toString with a bunch of reflective stuff. So it’s right back to the Java solution :(

Yes, I suppose that’s how it’s interpreted. Dwemthy is going to have to be satisfied with this for the time being. If a reflective class and property pretty-printer (like Ruby’s) ever shows up in stdlib, that would be cool. Or some way to do classOf on abstract types/type parameters. (I don’t see why those can’t be statically inserted by the compiler.)

That is a fun read, n8! Thanks for sharing.

Regarding state, one place where it helps is when you want to have references between the objects and you always want to point to the current version. For example, imagine if you had an arena that had pointers to all the fighters. If you insist on no state, then whenever any fighter changes, you have to update the whole arena. This can require a lot of boilerplate code, plus if you leave out an update, you can end up using the wrong version of something without even getting any error from the runtime system at all.

So, long story short, my instinct matches some others and I’d suggest making the creatures statefull but have as many as possible of their fields being vals or at least referencing data that is itself immutable.

For run-time type information, a pattern that is often used is to have a TypeDescriptor hierarchy and then to pass these around as implicit parameters. In this case, though, nothing should prevent you from writing some toString() methods, but I admit I haven’t thought about what the implementation of those methods would look like.

Hey, Lex, thanks for Programming in Scala!

I see what you’re saying about the arena. I guess the question with immutable state is always going to be, where does it stop? Here I think it works out the way it is, but it would be interesting to compare it to a less aggressively immutable version. (The LoC would go down a little I bet.)

Add a comment