import scala.math._ import scala.util._ import scala.language.postfixOps /////////////////////////////////////////Classes implicit class Point(p: (Int, Int)) { def +(o: (Int, Int)) = (o._1 + p._1, o._2 + p._2) def -(o: (Int, Int)) = (o._1 - p._1, o._2 - p._2) def *(o: (Int, Int)) = (o._1 * p._1, o._2 * p._2) def /(o: (Int, Int)) = (o._1 / p._1, o._2 / p._2) def >(o: (Int, Int)) = (o._1 < p._1 && o._2 < p._2) def <(o: (Int, Int)) = (o._1 > p._1 && o._2 > p._2) def ==(o: (Int, Int)) = (o._1 == p._1 && o._2 == p._2) def length = sqrt(p._1 * p._1 + p._2 * p._2) def scale(s: Double): (Int, Int) = (p._1 * s toInt, p._2 * s toInt) } object Math { def inside(x: (Int, Int), y: (Int, Int), p: (Int, Int)) = { (x < p) && (y > p) } } ///////////////////////////////////////Util def rand(o: Int, e: Int) = o + Random.nextInt(e) def randPoint(width: Int, height: Int, p0: (Int, Int)=(0, 0)) = { (rand(p0._1, width), rand(p0._2, height)) } ///////////////////////////////////////Entity trait EntityStats { var curHp = 10 var maxHp = 10 var defense = 1 var offense = 2 def hp = curHp def hpRatio = curHp / maxHp def reduceHp(amt: Int) = { val hpleft = (-amt + defense) + curHp curHp = max(min(hpleft, maxHp), 0) } } class Positional(xc: Int, yc: Int) { var x = xc var y = yc def location = (x, y) def move(dx: Int, dy: Int): Unit = { x += dx y += dy } } class Entity( x: Int, y: Int, reprc: Char) extends Positional(x, y) with EntityStats { def repr = reprc def attack(other: Entity): Unit = other.reduceHp(offense) override def toString = s"$reprc => ($x, $y)" } /////////////////////////////////////////Controllers abstract class Message case class Attack(me: Entity, enemy: Entity) extends Message trait AI { var messages = List[Message]() def see(entities: Seq[Entity]): AI def act: Seq[Message] } class DumbAI extends Entity(0, 0, 'z') with AI { var target: Entity = null def see(entities: Seq[Entity]) = { val radius = 5 val fn = (e: Entity) => {(e.location - location).length <= radius} val validEnts = entities filter fn if (validEnts.length > 0) target = validEnts(0) this } def act = { var msgs = List[Message]() if (target != null) msgs ::= new Attack(this, target) msgs } } val zombie = new DumbAI val others = List( new Entity(3, 3, '@'), new Entity(10, 3, 'c'), new Entity(1, 3, 'l')) println(zombie.see(others).act) /////////////////////////////////////////Action Processor /////////////////////////////////////////Map gen def genEntities(maxx: Int, maxy: Int) = { def make(c: Char) = new Entity(rand(0, maxx), rand(0, maxy), c) make('@') :: (1 to 12 map {_ => make('z')} toList) } /////////////////////////////////////////Display object Display { def width = 25 def height = 80 def dimensions = (width, height) def draw(es: Seq[Entity]) = { for (x <- 0 to width) { for (y <- 0 to height) { val pt = (x, y) val c = es dropWhile { _.location != pt } if (c == Nil) print(' ') else print(c(0).repr) } println(' ') } } } /////////////////////////////////////////Main val entities = genEntities(20, 20) val pc = (entities takeWhile {_.repr == '@'})(0) Display.draw(entities) /////////////////////////////////////////Tests def testAttack = { val p1 = new Entity(0, 0, '@') val p2 = new Entity(0, 0, '@') (1 to 12) foreach {_ => p1.attack(p2)} assert( p1.hp == 0 ) p2.offense = -2 (1 to 12) foreach {_ => p2.attack(p1)} assert( p1.hp == p1.maxHp ) } def testMath = { val a = (0, 0) val b = (10, 10) val p = (5, 5) assert( Math inside (a, b, p) ) } def testPoint = { val a = (0, 0) val b = (1, 1) assert( b - a == (-1, -1) ) assert( b.length - 1.414 <= 1e-3 ) assert( ((10, 10) scale 0.3) == (3, 3) ) assert( ((10, 10) scale 3) == (30, 30) ) assert( (5, 5) > (3, 3) ) }