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) )
}