Implement Bot prediction
Calculations of next step of every bot.
This commit is contained in:
parent
c66e87791e
commit
a1796c4198
58 changed files with 3693 additions and 45 deletions
|
@ -7,6 +7,7 @@ import bot.util.Log.dbg
|
||||||
class Game {
|
class Game {
|
||||||
var _round: Int = 0
|
var _round: Int = 0
|
||||||
var _timebank: Int = Settings.timebank
|
var _timebank: Int = Settings.timebank
|
||||||
|
var lastBoard: Board = new Board(Settings.width, Settings.height)
|
||||||
var board: Board = new Board(Settings.width, Settings.height)
|
var board: Board = new Board(Settings.width, Settings.height)
|
||||||
var bofa: Player = new Player(Settings.bofaId, Settings.bofaName)
|
var bofa: Player = new Player(Settings.bofaId, Settings.bofaName)
|
||||||
var oppo: Player = new Player(Settings.oppoId, Settings.oppoName)
|
var oppo: Player = new Player(Settings.oppoId, Settings.oppoName)
|
||||||
|
@ -37,7 +38,7 @@ class Game {
|
||||||
|
|
||||||
update match {
|
update match {
|
||||||
case round (rest) => this.round = rest.toInt
|
case round (rest) => this.round = rest.toInt
|
||||||
case board (rest) => this.board.parse(rest)
|
case board (rest) => this.lastBoard = this.board.clone(); this.board.parse(rest)
|
||||||
case snippets (name, rest) => playerBy(name).snippets = rest.toInt
|
case snippets (name, rest) => playerBy(name).snippets = rest.toInt
|
||||||
case bombs (name, rest) => playerBy(name).bombs = rest.toInt
|
case bombs (name, rest) => playerBy(name).bombs = rest.toInt
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package bot
|
package bot
|
||||||
|
|
||||||
|
import bot.environment.topology.Direction
|
||||||
|
import bot.environment.topology.Stay
|
||||||
|
|
||||||
class Player(val id: Int, val name: String) {
|
class Player(val id: Int, val name: String) {
|
||||||
var bombs: Int = 0
|
var bombs: Int = 0
|
||||||
var snippets: Int = 0
|
var snippets: Int = 0
|
||||||
|
|
|
@ -1,10 +1,22 @@
|
||||||
package bot.cortex
|
package bot.cortex
|
||||||
|
|
||||||
import bot.environment.topology.Point
|
|
||||||
import bot.environment.Board
|
|
||||||
import bot.Game
|
import bot.Game
|
||||||
|
import bot.environment.Board
|
||||||
|
import bot.environment.Board.Tokens
|
||||||
|
import bot.environment.Bot
|
||||||
|
import bot.environment.Bug
|
||||||
|
import bot.environment.Chase
|
||||||
|
import bot.environment.FarChase
|
||||||
|
import bot.environment.Lever
|
||||||
|
import bot.environment.Predict
|
||||||
|
import bot.environment.topology.Field
|
||||||
import bot.environment.topology.Grid
|
import bot.environment.topology.Grid
|
||||||
|
import bot.environment.topology.Point
|
||||||
import bot.util.Log.dbg
|
import bot.util.Log.dbg
|
||||||
|
import bot.environment.Wall
|
||||||
|
import bot.environment.Spawner
|
||||||
|
import bot.environment.Gate
|
||||||
|
|
||||||
|
|
||||||
class BugAI extends Tactical {
|
class BugAI extends Tactical {
|
||||||
def evaluate(game: Game): Tactic = {
|
def evaluate(game: Game): Tactic = {
|
||||||
|
@ -13,19 +25,69 @@ class BugAI extends Tactical {
|
||||||
|
|
||||||
val weightGrid = new Grid(board.width, board.height, 0: Int)
|
val weightGrid = new Grid(board.width, board.height, 0: Int)
|
||||||
|
|
||||||
board.bugs foreach { weightGrid(_) put -1000 }
|
for ( bugField <- board.bugs ) {
|
||||||
|
weightGrid.put(bugField.point, -55)
|
||||||
for ( bug <- board.bugs; point <- board.walkablePoints(bug.point) ) {
|
|
||||||
val field = weightGrid(point)
|
bugField.content
|
||||||
field put (field.content - 1000)
|
.collect { case b@Bug(_) => b }
|
||||||
|
.foreach { bug =>
|
||||||
|
val goal = goalPoint(bug, bugField, game)
|
||||||
|
dbg(s"Predict Point [${bug.getClass.getSimpleName}]: ${goal.toString()}")
|
||||||
|
val walkPoint = bugWalkablePoint(bug, bugField.point, game) minBy { _ l2 goal }
|
||||||
|
dbg(s"Walk Point [${bug.getClass.getSimpleName}]: ${walkPoint.toString()}")
|
||||||
|
|
||||||
|
weightGrid.put(walkPoint, -1000) // don't collide
|
||||||
|
if (walkPoint == game.bofaPoint) weightGrid.put(bugField.point, -1000) // don't swap positions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
board.walkableDirs(game.bofaPoint) foreach { dir =>
|
board.walkableDirs(game.bofaPoint) foreach { dir =>
|
||||||
tactic = tactic + {dir -> weightGrid(board.walk(game.bofaPoint)(dir)).content}
|
tactic = tactic + {dir -> weightGrid(board.walk(game.bofaPoint)(dir)).content}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
board.walls foreach { w => weightGrid.put(w.point, -88) }
|
||||||
dbg(s"$weightGrid")
|
dbg(s"$weightGrid")
|
||||||
|
|
||||||
tactic
|
tactic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def goalPoint(bug: Bug, field: Field[Tokens], game: Game): Point = {
|
||||||
|
implicit def fieldToPoint (field: Field[_]): Point = field.point
|
||||||
|
implicit def gameToBoard (game: Game): Board = game.board
|
||||||
|
implicit def fieldToTokens (field: Field[Tokens]): Tokens = field.content
|
||||||
|
|
||||||
|
def predictPoint(newField: Field[Tokens]): Point = {
|
||||||
|
val botId = newField.content.collectFirst { case Bot(id) => id } get
|
||||||
|
val oldField = game.lastBoard.bots(botId) get
|
||||||
|
|
||||||
|
val point = newField.point - oldField.point
|
||||||
|
point + Point(point.x*3, point.y*3)
|
||||||
|
}
|
||||||
|
|
||||||
|
def nextBot(point: Point) = game.bots minBy { _ l2 point }
|
||||||
|
def bugPoint(goalPoint: Point): Point = game.walkablePoints(field) minBy {_ l2 goalPoint }
|
||||||
|
|
||||||
|
bug.ai match {
|
||||||
|
case Chase => nextBot(field)
|
||||||
|
case FarChase => game.bots maxBy { _ l2 field }
|
||||||
|
case Lever => val wantBugs = game.bugs filterNot { f => (f == field) && (f contains bug) }
|
||||||
|
val wantBug = if (wantBugs.isEmpty) field else wantBugs minBy { _ l2 field }
|
||||||
|
(wantBug.point - nextBot(field)) + (wantBug.point - nextBot(field))
|
||||||
|
case Predict => predictPoint(nextBot(field))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def bugWalkablePoint(bug: Bug, point: Point, game: Game): Set[Point] = {
|
||||||
|
val grid = game.board.asGrid
|
||||||
|
|
||||||
|
grid(point).content foreach { case Gate(d) => return Set(point-d); case _ => }
|
||||||
|
|
||||||
|
def oldField = game.lastBoard.bugs find { _.content.contains(bug) } getOrElse Field(Point(-1,-1), false)
|
||||||
|
|
||||||
|
grid.directions(point)
|
||||||
|
.filterNot { x => grid(point+x).content.contains(Wall()) }
|
||||||
|
.map { x => game.board.walk(point)(x) }
|
||||||
|
.filterNot { x => x == oldField.point }
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -25,8 +25,8 @@ class SnippetAI extends Tactical {
|
||||||
board.snippets foreach { snippet => distribute(snippet, weightGrid, board) }
|
board.snippets foreach { snippet => distribute(snippet, weightGrid, board) }
|
||||||
preventFallBack(point, weightGrid, board)
|
preventFallBack(point, weightGrid, board)
|
||||||
|
|
||||||
weightGrid(game.bofaPoint) put -999
|
weightGrid.put(game.bofaPoint, 0) // from snippetai view-point staying is disadvised
|
||||||
markWalls(weightGrid, board)
|
markWalls(weightGrid, board) // just for visualization, not walkable anyway
|
||||||
dbg(weightGrid.toString())
|
dbg(weightGrid.toString())
|
||||||
|
|
||||||
board.walkableDirs(point) // get all possible directions starting in point
|
board.walkableDirs(point) // get all possible directions starting in point
|
||||||
|
@ -42,14 +42,12 @@ class SnippetAI extends Tactical {
|
||||||
@tailrec
|
@tailrec
|
||||||
def runner(frontier: Set[Point], distance: Int): Unit = {
|
def runner(frontier: Set[Point], distance: Int): Unit = {
|
||||||
if (frontier.isEmpty) return
|
if (frontier.isEmpty) return
|
||||||
|
|
||||||
dbg(s"""Frontier[dist= $distance]: ${frontier.mkString(",")}""")
|
|
||||||
|
|
||||||
// process the current frontier and build the new one
|
// process the current frontier and build the new one
|
||||||
val nextFrontier =
|
val nextFrontier =
|
||||||
frontier filterNot { visited(_).get } flatMap { p =>
|
frontier filterNot { f => visited(f).content } flatMap { p =>
|
||||||
visited(p) put true
|
visited.put(p, true)
|
||||||
weightGrid(p).content += (1000 / math.pow(1.3, distance)).intValue
|
weightGrid.put(p, weightGrid(p).content + (1000 / math.pow(1.3, distance)).intValue)
|
||||||
board.walkablePoints(p)
|
board.walkablePoints(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +72,6 @@ class SnippetAI extends Tactical {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def markWalls(weightGrid: Grid[Int], board: Board) = {
|
private def markWalls(weightGrid: Grid[Int], board: Board) = {
|
||||||
board.walls foreach { wall => weightGrid(wall) put -88 }
|
board.walls foreach { wall => weightGrid.put(wall.point, -88) }
|
||||||
}
|
}
|
||||||
}
|
}
|
17
bofa/src/main/scala/bot/environment/AIType.scala
Normal file
17
bofa/src/main/scala/bot/environment/AIType.scala
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package bot.environment
|
||||||
|
|
||||||
|
sealed trait AIType
|
||||||
|
|
||||||
|
final case object Chase extends AIType
|
||||||
|
final case object Predict extends AIType
|
||||||
|
final case object Lever extends AIType
|
||||||
|
final case object FarChase extends AIType
|
||||||
|
|
||||||
|
object AIType {
|
||||||
|
def apply(ai: Int) = ai match {
|
||||||
|
case 0 => Chase
|
||||||
|
case 1 => Predict
|
||||||
|
case 2 => Lever
|
||||||
|
case 3 => FarChase
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,9 @@ package bot.environment
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
import bot.OptionInt
|
|
||||||
import bot.environment.Board.Tokens
|
import bot.environment.Board.Tokens
|
||||||
import bot.environment.topology._
|
import bot.environment.topology._
|
||||||
|
import scala.util.control.Exception.allCatch
|
||||||
|
|
||||||
object Board {
|
object Board {
|
||||||
type Tokens = Set[Token]
|
type Tokens = Set[Token]
|
||||||
|
@ -23,17 +23,17 @@ class Board(val width: Int, val height: Int) {
|
||||||
def snippets = _snippets.to[Set]
|
def snippets = _snippets.to[Set]
|
||||||
def bugs = _bugs.to[Set]
|
def bugs = _bugs.to[Set]
|
||||||
def bots(id: Int) = _bots.get(id)
|
def bots(id: Int) = _bots.get(id)
|
||||||
|
def bots = _bots.values.to[Set]
|
||||||
def walls = _walls.to[Set]
|
def walls = _walls.to[Set]
|
||||||
|
|
||||||
def put(point: Point, tokens: Tokens) = {
|
def put(point: Point, tokens: Tokens) = {
|
||||||
val field = _grid(point)
|
_grid put (point, tokens)
|
||||||
field.content = tokens
|
|
||||||
|
|
||||||
tokens foreach {
|
tokens foreach {
|
||||||
case Snippet() => _snippets += field
|
case Snippet() => _snippets += _grid(point)
|
||||||
case Bug(_) => _bugs += field
|
case Bug(_) => _bugs += _grid(point)
|
||||||
case Bot(id) => _bots += {id -> field}
|
case Bot(id) => _bots += {id -> _grid(point)}
|
||||||
case Wall() => _walls += field
|
case Wall() => _walls += _grid(point)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,19 @@ class Board(val width: Int, val height: Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def clone: Board = {
|
||||||
|
val that = new Board(width, height)
|
||||||
|
that._snippets.clear
|
||||||
|
that._bugs.clear
|
||||||
|
that._bots.clear
|
||||||
|
that._walls.clear
|
||||||
|
|
||||||
|
for(x <- 0 until width; y <- 0 until height)
|
||||||
|
that.put(Point(x,y), this.asGrid(x,y).content)
|
||||||
|
|
||||||
|
that
|
||||||
|
}
|
||||||
|
|
||||||
def parse(update: String): Unit = {
|
def parse(update: String): Unit = {
|
||||||
_snippets.clear
|
_snippets.clear
|
||||||
_bugs.clear
|
_bugs.clear
|
||||||
|
@ -78,6 +91,14 @@ class Board(val width: Int, val height: Int) {
|
||||||
|
|
||||||
private def unpack(things: String): Tokens = {
|
private def unpack(things: String): Tokens = {
|
||||||
val tokens: mutable.Set[Token] = mutable.Set.empty
|
val tokens: mutable.Set[Token] = mutable.Set.empty
|
||||||
|
|
||||||
|
implicit class OptionInt(s: String) {
|
||||||
|
//TODO: change this to simple def returning Option[Int], just tested because its fancy
|
||||||
|
def toOptionInt: Option[Int] = s match {
|
||||||
|
case "" => None
|
||||||
|
case _ => allCatch.opt(s.toInt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
things
|
things
|
||||||
.split (';') // get single tokens
|
.split (';') // get single tokens
|
||||||
|
@ -87,12 +108,12 @@ class Board(val width: Int, val height: Int) {
|
||||||
case ("P", id) => Bot(id.toInt)
|
case ("P", id) => Bot(id.toInt)
|
||||||
case ("G", "l") => Gate(Left)
|
case ("G", "l") => Gate(Left)
|
||||||
case ("G", "r") => Gate(Right)
|
case ("G", "r") => Gate(Right)
|
||||||
case ("E", ai) => Bug(ai.toInt)
|
case ("E", ai) => Bug(AIType(ai.toInt))
|
||||||
case ("C", _) => Snippet()
|
case ("C", _) => Snippet()
|
||||||
case ("S", time) => Spawner(time.toOptInt)
|
case ("S", time) => Spawner(time.toOptionInt)
|
||||||
case ("B", time) => Bomb(time.toOptInt)
|
case ("B", time) => Bomb(time.toOptionInt)
|
||||||
case _ => throw new MatchError } // map to token type
|
case _ => throw new MatchError } // map to token type
|
||||||
.map { tkn => tkn.asInstanceOf[Token] } // explicitely cast Array[Any] to Array[Token]
|
.map { tkn => tkn.asInstanceOf[Token] } // explicitely cast Array[Any] to Array[Token]
|
||||||
.toSet // return Array as Set[Token]
|
.toSet // return Array as Set[Token]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,6 +12,6 @@ final case class Wall () extends Token
|
||||||
final case class Snippet () extends Token
|
final case class Snippet () extends Token
|
||||||
final case class Gate (direction: Direction) extends Token
|
final case class Gate (direction: Direction) extends Token
|
||||||
final case class Spawner (rounds: Option[Int]) extends Token
|
final case class Spawner (rounds: Option[Int]) extends Token
|
||||||
final case class Bug (ai: Int) extends Token
|
final case class Bug (ai: AIType) extends Token
|
||||||
final case class Bomb (rounds: Option[Int]) extends Token
|
final case class Bomb (rounds: Option[Int]) extends Token
|
||||||
final case class Bot (id: Int) extends Token
|
final case class Bot (id: Int) extends Token
|
|
@ -12,4 +12,5 @@ sealed trait Direction {
|
||||||
final case object Left extends { val label = "left"; val delta = (-1, 0) } with Direction
|
final case object Left extends { val label = "left"; val delta = (-1, 0) } with Direction
|
||||||
final case object Right extends { val label = "right"; val delta = (1, 0) } with Direction
|
final case object Right extends { val label = "right"; val delta = (1, 0) } with Direction
|
||||||
final case object Up extends { val label = "up"; val delta = (0, -1) } with Direction
|
final case object Up extends { val label = "up"; val delta = (0, -1) } with Direction
|
||||||
final case object Down extends { val label = "down"; val delta = (0, 1) } with Direction
|
final case object Down extends { val label = "down"; val delta = (0, 1) } with Direction
|
||||||
|
final case object Stay extends { val label = "pass"; val delta = (0, 0) } with Direction
|
|
@ -1,13 +1,13 @@
|
||||||
package bot.environment.topology
|
package bot.environment.topology
|
||||||
|
|
||||||
class Field[T] (val point: Point, var content: T) {
|
class Field[T] (val point: Point, val content: T) {
|
||||||
def x: Int = point.x
|
def x: Int = point.x
|
||||||
def y: Int = point.y
|
def y: Int = point.y
|
||||||
|
|
||||||
def put(update: T) = content = update
|
def put(update: T) = new Field(point, update)
|
||||||
def get = content
|
def get = content
|
||||||
|
|
||||||
def apply(f: T => T): Unit = content = f(content)
|
def apply(f: T => T): Unit = new Field(point, f(content))
|
||||||
}
|
}
|
||||||
object Field {
|
object Field {
|
||||||
def apply[T] (point: Point, content: T) = new Field(point, content)
|
def apply[T] (point: Point, content: T) = new Field(point, content)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package bot.environment.topology
|
package bot.environment.topology
|
||||||
|
|
||||||
import scala.reflect.ClassTag
|
import scala.reflect.ClassTag
|
||||||
|
import bot.util.Log.dbg
|
||||||
|
|
||||||
/** The game world viewed as a grid
|
/** The game world viewed as a grid
|
||||||
*
|
*
|
||||||
|
@ -9,13 +10,14 @@ import scala.reflect.ClassTag
|
||||||
class Grid[T: ClassTag] (width: Int, height: Int, default: => T) {
|
class Grid[T: ClassTag] (width: Int, height: Int, default: => T) {
|
||||||
private val grid: Array[Array[Field[T]]] = Array.ofDim[Field[T]](width, height)
|
private val grid: Array[Array[Field[T]]] = Array.ofDim[Field[T]](width, height)
|
||||||
|
|
||||||
for (x <- 0 until width; y <- 0 until height)
|
for (x <- 0 until width; y <- 0 until height) put(Point(x,y), default)
|
||||||
grid(x)(y) = Field( Point(x,y), default )
|
|
||||||
|
|
||||||
def apply(x: Int, y: Int): Field[T] = grid(x)(y)
|
def apply(x: Int, y: Int): Field[T] = grid(x)(y)
|
||||||
def apply(point: Point): Field[T] = apply(point.x, point.y)
|
def apply(point: Point): Field[T] = apply(point.x, point.y)
|
||||||
def apply(f: Field[_]): Field[T] = apply(f.point)
|
def apply(f: Field[_]): Field[T] = apply(f.point)
|
||||||
|
|
||||||
|
def put(point: Point, update: T): Unit = grid(point.x)(point.y) = new Field(point, update)
|
||||||
|
|
||||||
def neighbors (point: Point): Set[Field[T]] = directions(point) map { dir => apply(point+dir) }
|
def neighbors (point: Point): Set[Field[T]] = directions(point) map { dir => apply(point+dir) }
|
||||||
|
|
||||||
def directions (point: Point): Set[Direction] = {
|
def directions (point: Point): Set[Direction] = {
|
||||||
|
|
|
@ -6,8 +6,18 @@ class Point(val x: Int, val y: Int) {
|
||||||
def +(deltaX: Int, deltaY: Int): Point = new Point(x + deltaX, y + deltaY)
|
def +(deltaX: Int, deltaY: Int): Point = new Point(x + deltaX, y + deltaY)
|
||||||
def +(delta: (Int, Int)): Point = this + (delta _1, delta _2)
|
def +(delta: (Int, Int)): Point = this + (delta _1, delta _2)
|
||||||
def +(direction: Direction): Point = this + direction.delta
|
def +(direction: Direction): Point = this + direction.delta
|
||||||
|
def +(point: Point): Point = this + point.asTuple
|
||||||
|
def -(deltaX: Int, deltaY: Int): Point = new Point(x - deltaX, y - deltaY)
|
||||||
|
def -(delta: (Int, Int)): Point = this - (delta _1, delta _2)
|
||||||
|
def -(direction: Direction): Point = this - direction.delta
|
||||||
|
def -(point: Point): Point = this - point.asTuple
|
||||||
|
|
||||||
|
// norms (l1 = manhattan, l2 = euclidian)
|
||||||
|
def l1 (to: Point): Double = (this.x - to.x).abs + (this.y - to.y).abs
|
||||||
|
def l2 (to: Point): Double = Math.sqrt( Math.pow(this.x-to.x, 2) + Math.pow(this.y-to.y, 2) )
|
||||||
|
|
||||||
override def toString: String = s"Point{.x=$x, .y=$y}"
|
override def toString: String = s"Point{.x=$x, .y=$y}"
|
||||||
|
|
||||||
def canEqual(a: Any) = a.isInstanceOf[Point]
|
def canEqual(a: Any) = a.isInstanceOf[Point]
|
||||||
override def equals(that: Any): Boolean =
|
override def equals(that: Any): Boolean =
|
||||||
that match {
|
that match {
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import scala.util.control.Exception.allCatch
|
|
||||||
|
|
||||||
package object bot {
|
|
||||||
implicit class OptionInt(s: String) {
|
|
||||||
def toOptInt: Option[Int] = s match {
|
|
||||||
case "" => None
|
|
||||||
case _ => allCatch.opt(s.toInt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
36
hack-man-2-engine-development/.gitignore
vendored
Normal file
36
hack-man-2-engine-development/.gitignore
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Gradle template
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
gradle/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||||
|
# gradle/wrapper/gradle-wrapper.properties
|
||||||
|
### Java template
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
!match-wrapper*
|
||||||
|
*resultfile.json
|
201
hack-man-2-engine-development/LICENSE
Normal file
201
hack-man-2-engine-development/LICENSE
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2016 TheAIGames.com
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
47
hack-man-2-engine-development/README.md
Normal file
47
hack-man-2-engine-development/README.md
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Ms. Hack-man game engine
|
||||||
|
This repository contains the engine for the Booking.com Ms. Hack-man game for the Riddles.io platform.
|
||||||
|
|
||||||
|
## Setting up
|
||||||
|
|
||||||
|
This guide assumes the following software to be installed and globally
|
||||||
|
accessible:
|
||||||
|
|
||||||
|
- Gradle 2.14
|
||||||
|
- JVM 1.8.0_91
|
||||||
|
|
||||||
|
## Opening this project in IntelliJ IDEA
|
||||||
|
|
||||||
|
- Select 'Import Project'
|
||||||
|
- Browse to project directory root
|
||||||
|
- Select build.gradle
|
||||||
|
- Check settings:
|
||||||
|
- * Use local gradle distribution
|
||||||
|
- * Gradle home: /usr/share/gradle-2.14
|
||||||
|
- * Gradle JVM: 1.8
|
||||||
|
- * Project format: .idea (directory based)
|
||||||
|
|
||||||
|
*Note: for other IDEs, look at online documentation*
|
||||||
|
|
||||||
|
## Building the engine
|
||||||
|
|
||||||
|
Use Gradle to build a .jar of the engine. Go to Tasks -> build -> jar.
|
||||||
|
The .jar file can be found at `build/libs/`.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
Running is handled by the MatchWrapper. This application handles all communication between
|
||||||
|
the engine and bots and stores the results of the match. To run, firstly edit the
|
||||||
|
`wrapper-commands.json` file. This should be pretty self-explanatory. Just change the command
|
||||||
|
fields to the right values to run the engine and the bots. In the example, the starterbot
|
||||||
|
is run twice, plus the command for the engine built in the previous step.
|
||||||
|
|
||||||
|
To run the MatchWrapper, use the following command (Linux):
|
||||||
|
```
|
||||||
|
java -jar match-wrapper.jar "$(cat wrapper-commands.json)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Have a look at the MatchWrapper repo for more details about it:
|
||||||
|
[https://github.com/riddlesio/match-wrapper](https://github.com/riddlesio/match-wrapper)
|
||||||
|
|
||||||
|
*Note: if running on other systems, find how to put the content of wrapper-commands.json as
|
||||||
|
argument when running the match-wrapper.jar*
|
65
hack-man-2-engine-development/build.gradle
Normal file
65
hack-man-2-engine-development/build.gradle
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
group 'io.riddles'
|
||||||
|
|
||||||
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'groovy'
|
||||||
|
apply plugin: 'application'
|
||||||
|
apply plugin: 'com.jfrog.artifactory'
|
||||||
|
|
||||||
|
version = '1.0.5'
|
||||||
|
|
||||||
|
mainClassName = 'io.riddles.hackman2.HackMan2'
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.4.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifactory {
|
||||||
|
resolve {
|
||||||
|
contextUrl = 'http://artifactory.dev.riddles.io/artifactory'
|
||||||
|
repoKey = 'libs-release-local'
|
||||||
|
username = 'anonymous'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
srcDir 'src/java'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
groovy {
|
||||||
|
srcDir 'test/groovy'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': 'Hack-man 2 Game Engine',
|
||||||
|
'Implementation-Version': version,
|
||||||
|
'Main-Class': mainClassName
|
||||||
|
}
|
||||||
|
|
||||||
|
from {
|
||||||
|
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile group: 'io.riddles', name: 'javainterface', version: '1.0.7'
|
||||||
|
compile group: 'org.json', name: 'json', version: '20160212'
|
||||||
|
testCompile 'org.codehaus.groovy:groovy-all:2.4.1'
|
||||||
|
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
|
||||||
|
}
|
172
hack-man-2-engine-development/gradlew
vendored
Executable file
172
hack-man-2-engine-development/gradlew
vendored
Executable file
|
@ -0,0 +1,172 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save ( ) {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
84
hack-man-2-engine-development/gradlew.bat
vendored
Normal file
84
hack-man-2-engine-development/gradlew.bat
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
BIN
hack-man-2-engine-development/match-wrapper-1.3.5.jar
Normal file
BIN
hack-man-2-engine-development/match-wrapper-1.3.5.jar
Normal file
Binary file not shown.
5
hack-man-2-engine-development/run_wrapper.sh
Executable file
5
hack-man-2-engine-development/run_wrapper.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
BASEDIR=`pwd`
|
||||||
|
java -jar $BASEDIR/match-wrapper-*.jar "$(cat wrapper-commands.json)"
|
||||||
|
echo "${?}"
|
2
hack-man-2-engine-development/settings.gradle
Normal file
2
hack-man-2-engine-development/settings.gradle
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
rootProject.name = 'hackman2-engine-java'
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
import io.riddles.javainterface.game.player.PlayerProvider;
|
||||||
|
import io.riddles.javainterface.io.IOHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.HackMan2 - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2 {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
HackMan2Engine engine = new HackMan2Engine(new PlayerProvider<>(), new IOHandler());
|
||||||
|
|
||||||
|
HackMan2State firstState = engine.willRun();
|
||||||
|
HackMan2State finalState = engine.run(firstState);
|
||||||
|
|
||||||
|
engine.didRun(firstState, finalState);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.engine;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2Serializer;
|
||||||
|
import io.riddles.hackman2.game.board.Gate;
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.enemy.EnemySpawnPoint;
|
||||||
|
import io.riddles.hackman2.game.move.ActionType;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.player.HackMan2Player;
|
||||||
|
import io.riddles.hackman2.game.player.CharacterType;
|
||||||
|
import io.riddles.hackman2.game.processor.HackMan2Processor;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
import io.riddles.javainterface.configuration.Configuration;
|
||||||
|
import io.riddles.javainterface.engine.AbstractEngine;
|
||||||
|
import io.riddles.javainterface.engine.GameLoopInterface;
|
||||||
|
import io.riddles.javainterface.engine.SimpleGameLoop;
|
||||||
|
import io.riddles.javainterface.exception.TerminalException;
|
||||||
|
import io.riddles.javainterface.game.player.PlayerProvider;
|
||||||
|
import io.riddles.javainterface.io.IOInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.engine.HackMan2Engine - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2Engine extends AbstractEngine<HackMan2Processor, HackMan2Player, HackMan2State> {
|
||||||
|
|
||||||
|
public static SecureRandom RANDOM;
|
||||||
|
|
||||||
|
public HackMan2Engine(PlayerProvider<HackMan2Player> playerProvider, IOInterface ioHandler) throws TerminalException {
|
||||||
|
super(playerProvider, ioHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Configuration getDefaultConfiguration() {
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
|
||||||
|
configuration.put("maxRounds", 250); // 250
|
||||||
|
configuration.put("playerSnippetCount", 0);
|
||||||
|
configuration.put("mapSnippetCount", 2);
|
||||||
|
configuration.put("snippetSpawnRate", 8);
|
||||||
|
configuration.put("snippetSpawnCount", 1);
|
||||||
|
configuration.put("initialEnemyCount", 0);
|
||||||
|
configuration.put("enemySpawnDelay", 0);
|
||||||
|
configuration.put("enemySpawnRate", 4); // 4
|
||||||
|
configuration.put("enemySnippetLoss", 4);
|
||||||
|
configuration.put("enemySpawnTime", 3);
|
||||||
|
configuration.put("mapBombCount", 0); // 0
|
||||||
|
configuration.put("bombSpawnDelay", 2); // 2
|
||||||
|
configuration.put("bombSpawnRate", 5); // 5
|
||||||
|
configuration.put("bombSnippetLoss", 4);
|
||||||
|
configuration.put("bombMinTicks", 2);
|
||||||
|
configuration.put("bombMaxTicks", 5);
|
||||||
|
configuration.put("fieldWidth", 19);
|
||||||
|
configuration.put("fieldHeight", 15);
|
||||||
|
configuration.put("fieldLayout", getDefaultFieldLayout());
|
||||||
|
configuration.put("seed", UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HackMan2Processor createProcessor() {
|
||||||
|
return new HackMan2Processor(this.playerProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GameLoopInterface createGameLoop() {
|
||||||
|
return new SimpleGameLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HackMan2Player createPlayer(int id) {
|
||||||
|
return new HackMan2Player(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void sendSettingsToPlayer(HackMan2Player player) {
|
||||||
|
player.sendSetting("your_botid", player.getId());
|
||||||
|
player.sendSetting("field_width", configuration.getInt("fieldWidth"));
|
||||||
|
player.sendSetting("field_height", configuration.getInt("fieldHeight"));
|
||||||
|
player.sendSetting("max_rounds", configuration.getInt("maxRounds"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HackMan2State getInitialState() {
|
||||||
|
setRandomSeed();
|
||||||
|
|
||||||
|
// Ask which character the bot wants to play as
|
||||||
|
requestPlayerCharacters();
|
||||||
|
|
||||||
|
int width = configuration.getInt("fieldWidth");
|
||||||
|
int height = configuration.getInt("fieldHeight");
|
||||||
|
String layout = getDefaultFieldLayout();
|
||||||
|
ArrayList<EnemySpawnPoint> enemySpawnPoints = getEnemySpawnPoints();
|
||||||
|
ArrayList<Gate> gates = getGates();
|
||||||
|
|
||||||
|
// Create board
|
||||||
|
HackMan2Board board = new HackMan2Board(width, height, layout, enemySpawnPoints, gates);
|
||||||
|
|
||||||
|
// Create player states
|
||||||
|
ArrayList<HackMan2PlayerState> playerStates = getInitialPlayerStates();
|
||||||
|
|
||||||
|
HackMan2State initialState = new HackMan2State(playerStates, board);
|
||||||
|
|
||||||
|
// Spawn initial items
|
||||||
|
board.spawnInitialObjects(initialState);
|
||||||
|
|
||||||
|
return initialState;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ArrayList<HackMan2PlayerState> getInitialPlayerStates() {
|
||||||
|
ArrayList<HackMan2PlayerState> playerStates = new ArrayList<>();
|
||||||
|
|
||||||
|
for (HackMan2Player player : this.playerProvider.getPlayers()) {
|
||||||
|
int id = player.getId();
|
||||||
|
Point startingCoordinate = getStartingCoordinates(id);
|
||||||
|
HackMan2PlayerState playerState = new HackMan2PlayerState(id, startingCoordinate);
|
||||||
|
|
||||||
|
playerStates.add(playerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPlayedGame(HackMan2State initialState) {
|
||||||
|
HackMan2Serializer serializer = new HackMan2Serializer();
|
||||||
|
return serializer.traverseToString(this.processor, initialState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getStartingCoordinates(int id) {
|
||||||
|
switch (id) {
|
||||||
|
case 0:
|
||||||
|
return new Point(4, 7);
|
||||||
|
case 1:
|
||||||
|
return new Point(14, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getDefaultFieldLayout() {
|
||||||
|
return ".,.,.,x,.,.,.,.,.,.,.,.,.,.,.,x,.,.,.," +
|
||||||
|
".,x,.,x,.,x,x,x,x,.,x,x,x,x,.,x,.,x,.," +
|
||||||
|
".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.," +
|
||||||
|
".,x,x,x,.,x,.,x,x,x,x,x,.,x,.,x,x,x,.," +
|
||||||
|
".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.," +
|
||||||
|
".,.,.,x,.,x,.,x,x,.,x,x,.,x,.,x,.,.,.," +
|
||||||
|
"x,.,x,x,.,.,.,x,x,.,x,x,.,.,.,x,x,.,x," +
|
||||||
|
".,.,x,x,.,x,x,x,x,.,x,x,x,x,.,x,x,.,.," +
|
||||||
|
"x,.,x,x,.,.,.,.,.,.,.,.,.,.,.,x,x,.,x," +
|
||||||
|
".,.,.,x,.,x,x,x,x,x,x,x,x,x,.,x,.,.,.," +
|
||||||
|
".,x,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,x,.," +
|
||||||
|
".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.," +
|
||||||
|
".,x,.,x,x,.,x,x,x,x,x,x,x,.,x,x,.,x,.," +
|
||||||
|
".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.," +
|
||||||
|
".,.,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,.,.";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ArrayList<EnemySpawnPoint> getEnemySpawnPoints() {
|
||||||
|
ArrayList<EnemySpawnPoint> spawnPoints = new ArrayList<>();
|
||||||
|
|
||||||
|
spawnPoints.add(new EnemySpawnPoint(new Point(0, 0), 0));
|
||||||
|
spawnPoints.add(new EnemySpawnPoint(new Point(18, 0), 1));
|
||||||
|
spawnPoints.add(new EnemySpawnPoint(new Point(18, 14), 2));
|
||||||
|
spawnPoints.add(new EnemySpawnPoint(new Point(0, 14), 3));
|
||||||
|
|
||||||
|
return spawnPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ArrayList<Gate> getGates() {
|
||||||
|
ArrayList<Gate> gates = new ArrayList<>();
|
||||||
|
|
||||||
|
Gate gate1 = new Gate(new Point(0, 7), MoveType.LEFT);
|
||||||
|
Gate gate2 = new Gate(new Point(18, 7), MoveType.RIGHT);
|
||||||
|
|
||||||
|
gate1.setLinkedGate(gate2);
|
||||||
|
gate2.setLinkedGate(gate1);
|
||||||
|
|
||||||
|
gates.add(gate1);
|
||||||
|
gates.add(gate2);
|
||||||
|
|
||||||
|
return gates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestPlayerCharacters() {
|
||||||
|
for (HackMan2Player player : this.playerProvider.getPlayers()) {
|
||||||
|
String response = player.requestMove(ActionType.CHARACTER);
|
||||||
|
CharacterType character = CharacterType.fromString(response);
|
||||||
|
|
||||||
|
if (character == null) {
|
||||||
|
character = CharacterType.getRandomCharacter();
|
||||||
|
}
|
||||||
|
|
||||||
|
player.setCharacterType(character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setRandomSeed() {
|
||||||
|
try {
|
||||||
|
RANDOM = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
LOGGER.severe("Not able to use SHA1PRNG, using default algorithm");
|
||||||
|
RANDOM = new SecureRandom();
|
||||||
|
}
|
||||||
|
String seed = configuration.getString("seed");
|
||||||
|
LOGGER.info("RANDOM SEED IS: " + seed);
|
||||||
|
RANDOM.setSeed(seed.getBytes());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.board.Item - Created on 12-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public abstract class HackMan2Object {
|
||||||
|
|
||||||
|
protected Point coordinate;
|
||||||
|
|
||||||
|
public HackMan2Object(Point coordinate) {
|
||||||
|
this.coordinate = coordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2Object(HackMan2Object object) {
|
||||||
|
this.coordinate = new Point(object.coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String toString();
|
||||||
|
|
||||||
|
public Point getCoordinate() {
|
||||||
|
return this.coordinate;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import io.riddles.javainterface.serialize.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.HackMan2ObjectSerializer - Created on 15-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2ObjectSerializer implements Serializer<HackMan2Object> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String traverseToString(HackMan2Object object) {
|
||||||
|
return visitObject(object).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject traverseToJson(HackMan2Object object) {
|
||||||
|
return visitObject(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject visitObject(HackMan2Object object) {
|
||||||
|
JSONObject objectObj = new JSONObject();
|
||||||
|
|
||||||
|
objectObj.put("x", object.getCoordinate().x);
|
||||||
|
objectObj.put("y", object.getCoordinate().y);
|
||||||
|
|
||||||
|
return objectObj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.player.HackMan2Player;
|
||||||
|
import io.riddles.hackman2.game.processor.HackMan2Processor;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2StateSerializer;
|
||||||
|
import io.riddles.javainterface.game.AbstractGameSerializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.HackMan2Serializer - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2Serializer extends AbstractGameSerializer<HackMan2Processor, HackMan2State> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String traverseToString(HackMan2Processor processor, HackMan2State initialState) {
|
||||||
|
HackMan2StateSerializer stateSerializer = new HackMan2StateSerializer();
|
||||||
|
JSONObject game = new JSONObject();
|
||||||
|
|
||||||
|
game = addDefaultJSON(initialState, game, processor);
|
||||||
|
|
||||||
|
JSONArray characters = new JSONArray();
|
||||||
|
for (HackMan2Player player : processor.getPlayerProvider().getPlayers()) {
|
||||||
|
JSONObject characterObj = new JSONObject();
|
||||||
|
characterObj.put("id", player.getId());
|
||||||
|
characterObj.put("type", player.getCharacterType());
|
||||||
|
|
||||||
|
characters.put(characterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray states = new JSONArray();
|
||||||
|
states.put(stateSerializer.traverseToJson(initialState));
|
||||||
|
|
||||||
|
HackMan2State state = initialState;
|
||||||
|
while (state.hasNextState()) {
|
||||||
|
state = (HackMan2State) state.getNextState();
|
||||||
|
states.put(stateSerializer.traverseToJson(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
game.put("characters", characters);
|
||||||
|
game.put("states", states);
|
||||||
|
|
||||||
|
return game.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package io.riddles.hackman2.game.board;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.board.Board - Created on 9-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public abstract class Board {
|
||||||
|
|
||||||
|
protected final String EMTPY_FIELD = ".";
|
||||||
|
protected final String BLOCKED_FIELD = "x";
|
||||||
|
|
||||||
|
protected int width;
|
||||||
|
protected int height;
|
||||||
|
protected String layout;
|
||||||
|
protected String[][] fields;
|
||||||
|
|
||||||
|
Board(int width, int height, String layout) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.layout = layout;
|
||||||
|
this.fields = new String[width][height];
|
||||||
|
|
||||||
|
setFieldsFromString(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDirectionValid(Point coordinate, MoveType direction) {
|
||||||
|
if (direction == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point newCoordinate = direction.getCoordinateAfterMove(coordinate);
|
||||||
|
return isCoordinateValid(newCoordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCoordinateValid(Point coordinate) {
|
||||||
|
int x = coordinate.x;
|
||||||
|
int y = coordinate.y;
|
||||||
|
|
||||||
|
return x >= 0 && y >= 0 && x < this.width && y < this.height &&
|
||||||
|
!this.fields[x][y].equals(BLOCKED_FIELD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLayout() {
|
||||||
|
return this.layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFieldsFromString(String input) {
|
||||||
|
String[] split = input.split(",");
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
for (String fieldString : split) {
|
||||||
|
this.fields[x][y] = fieldString;
|
||||||
|
|
||||||
|
if (++x == this.width) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package io.riddles.hackman2.game.board;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.board.Gate - Created on 18-7-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class Gate extends HackMan2Object {
|
||||||
|
|
||||||
|
private MoveType entry;
|
||||||
|
private Gate linkedGate;
|
||||||
|
|
||||||
|
public Gate(Point coordinate, MoveType entry) {
|
||||||
|
super(coordinate);
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("G%s", this.entry.toString().charAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoveType getEntry() {
|
||||||
|
return this.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gate getLinkedGate() {
|
||||||
|
return this.linkedGate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkedGate(Gate linkedGate) {
|
||||||
|
this.linkedGate = linkedGate;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,508 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.board;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
import io.riddles.hackman2.game.enemy.Enemy;
|
||||||
|
import io.riddles.hackman2.game.enemy.EnemyDeath;
|
||||||
|
import io.riddles.hackman2.game.enemy.EnemySpawnPoint;
|
||||||
|
import io.riddles.hackman2.game.item.Bomb;
|
||||||
|
import io.riddles.hackman2.game.item.Snippet;
|
||||||
|
import io.riddles.hackman2.game.move.HackMan2Move;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
import io.riddles.javainterface.configuration.Configuration;
|
||||||
|
import io.riddles.javainterface.exception.InvalidMoveException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.board.HackMan2Board - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2Board extends Board {
|
||||||
|
|
||||||
|
private ArrayList<Enemy> enemies;
|
||||||
|
private HashMap<String, Bomb> bombs;
|
||||||
|
private HashMap<String, Snippet> snippets;
|
||||||
|
private HashMap<String, Gate> gates;
|
||||||
|
private ArrayList<EnemySpawnPoint> enemySpawnPoints;
|
||||||
|
|
||||||
|
private int spawnedEnemies;
|
||||||
|
private int spawnedBombs;
|
||||||
|
|
||||||
|
public HackMan2Board(int width, int height, String layout,
|
||||||
|
ArrayList<EnemySpawnPoint> enemySpawnPoints, ArrayList<Gate> gates) {
|
||||||
|
super(width, height, layout);
|
||||||
|
|
||||||
|
this.enemySpawnPoints = enemySpawnPoints;
|
||||||
|
|
||||||
|
this.enemies = new ArrayList<>();
|
||||||
|
this.bombs = new HashMap<>();
|
||||||
|
this.snippets = new HashMap<>();
|
||||||
|
this.gates = new HashMap<>();
|
||||||
|
this.spawnedEnemies = 0;
|
||||||
|
this.spawnedBombs = 0;
|
||||||
|
|
||||||
|
gates.forEach(gate -> this.gates.put(gate.getCoordinate().toString(), gate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2Board(HackMan2Board board) {
|
||||||
|
super(board.getWidth(), board.getHeight(), board.getLayout());
|
||||||
|
this.enemySpawnPoints = board.enemySpawnPoints;
|
||||||
|
this.gates = board.gates;
|
||||||
|
this.spawnedEnemies = board.spawnedEnemies;
|
||||||
|
this.spawnedBombs = board.spawnedBombs;
|
||||||
|
|
||||||
|
this.enemies = board.enemies.stream()
|
||||||
|
.map(Enemy::new)
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
this.bombs = board.bombs.entrySet().stream()
|
||||||
|
.collect(
|
||||||
|
HashMap::new,
|
||||||
|
(m, e) -> m.put(e.getKey(), new Bomb(e.getValue())),
|
||||||
|
Map::putAll
|
||||||
|
);
|
||||||
|
this.snippets = board.snippets.entrySet().stream()
|
||||||
|
.collect(
|
||||||
|
HashMap::new,
|
||||||
|
(m, e) -> m.put(e.getKey(), new Snippet(e.getValue())),
|
||||||
|
Map::putAll
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(HackMan2State state) {
|
||||||
|
String[][] outFields = new String[this.width][this.height];
|
||||||
|
|
||||||
|
// Create a new 2d array to store the actual contents of each field
|
||||||
|
for (int y = 0; y < this.height; y++) {
|
||||||
|
for (int x = 0; x < this.width; x++) {
|
||||||
|
if (this.fields[x][y].equals(BLOCKED_FIELD)) {
|
||||||
|
outFields[x][y] = BLOCKED_FIELD;
|
||||||
|
} else {
|
||||||
|
outFields[x][y] = EMTPY_FIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the string representations of each object on the board
|
||||||
|
for (HackMan2PlayerState playerState : state.getPlayerStates()) {
|
||||||
|
Point coordinate = playerState.getCoordinate();
|
||||||
|
outFields[coordinate.x][coordinate.y] += playerState.toString() + ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.enemySpawnPoints.forEach(spawnPoint -> addObjectToOutFields(outFields, spawnPoint));
|
||||||
|
this.gates.forEach((key, gate) -> addObjectToOutFields(outFields, gate));
|
||||||
|
getAliveEnemies().forEach(enemy -> addObjectToOutFields(outFields, enemy));
|
||||||
|
this.bombs.forEach((key, bomb) -> addObjectToOutFields(outFields, bomb));
|
||||||
|
this.snippets.forEach((key, snippet) -> addObjectToOutFields(outFields, snippet));
|
||||||
|
|
||||||
|
// Create the string from the 2d array
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
for (int y = 0; y < this.height; y++) {
|
||||||
|
for (int x = 0; x < this.width; x++) {
|
||||||
|
String value = outFields[x][y];
|
||||||
|
|
||||||
|
if (value.length() > 1) {
|
||||||
|
value = value.substring(1, value.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.append(value).append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.setLength(output.length() - 1);
|
||||||
|
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnInitialObjects(HackMan2State state) {
|
||||||
|
for (int i = 0; i < HackMan2Engine.configuration.getInt("mapSnippetCount"); i++) {
|
||||||
|
spawnSnippet(state);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < HackMan2Engine.configuration.getInt("mapBombCount"); i++) {
|
||||||
|
spawnBomb(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateMove(HackMan2PlayerState playerState, HackMan2Move move) {
|
||||||
|
if (move.isInvalid()) return;
|
||||||
|
|
||||||
|
MoveType moveType = move.getMoveType();
|
||||||
|
Point oldCoordinate = playerState.getCoordinate();
|
||||||
|
Point newCoordinate = getCoordinateAfterMove(moveType, oldCoordinate);
|
||||||
|
|
||||||
|
if (!isCoordinateValid(newCoordinate)) {
|
||||||
|
move.setException(new InvalidMoveException("Can't move this direction"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getCoordinateAfterMove(MoveType moveType, Point coordinate) {
|
||||||
|
Gate gate = this.gates.get(coordinate.toString());
|
||||||
|
|
||||||
|
// Move through gate
|
||||||
|
if (gate != null && gate.getEntry() == moveType) {
|
||||||
|
return gate.getLinkedGate().getCoordinate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal move
|
||||||
|
return moveType.getCoordinateAfterMove(coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanUpEnemies() {
|
||||||
|
this.enemies = getAliveEnemies();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveEnemies(HackMan2State state) {
|
||||||
|
this.enemies.forEach(enemy -> enemy.getNewCoordinate(state));
|
||||||
|
this.enemies.forEach(Enemy::performMovement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void performPickups(HackMan2State state) {
|
||||||
|
pickupSnippets(state);
|
||||||
|
pickupBombs(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void performCollisions(HackMan2State previousState, HackMan2State state) {
|
||||||
|
swapCollideWithEnemies(previousState, state);
|
||||||
|
detonateBombs(state);
|
||||||
|
positionCollideWithEnemies(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnEnemies() {
|
||||||
|
for (EnemySpawnPoint spawnPoint : this.enemySpawnPoints) {
|
||||||
|
spawnPoint.reduceSpawnTime();
|
||||||
|
|
||||||
|
Enemy newEnemy = spawnPoint.spawnEnemy(this.spawnedEnemies);
|
||||||
|
|
||||||
|
if (newEnemy == null) continue;
|
||||||
|
|
||||||
|
this.enemies.add(newEnemy);
|
||||||
|
this.spawnedEnemies++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnObjects(HackMan2State state) {
|
||||||
|
startEnemySpawn(state);
|
||||||
|
spawnSnippets(state);
|
||||||
|
spawnBombs(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dropBomb(Point coordinate, int ticks) {
|
||||||
|
this.bombs.put(coordinate.toString(), new Bomb(coordinate, ticks));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Enemy> getEnemies() {
|
||||||
|
return this.enemies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Bomb> getBombs() {
|
||||||
|
return this.bombs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Snippet> getSnippets() {
|
||||||
|
return this.snippets;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addObjectToOutFields(String[][] outFields, HackMan2Object object) {
|
||||||
|
Point coordinate = object.getCoordinate();
|
||||||
|
outFields[coordinate.x][coordinate.y] += object.toString() + ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pickupSnippets(HackMan2State state) {
|
||||||
|
ArrayList<HackMan2PlayerState> playersOnSnippet = getPlayersOnItem(state, this.snippets);
|
||||||
|
|
||||||
|
for (HackMan2PlayerState playerState : playersOnSnippet) {
|
||||||
|
playerState.updateSnippets(1);
|
||||||
|
state.addSnippetCollected();
|
||||||
|
this.snippets.remove(playerState.getCoordinate().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pickupBombs(HackMan2State state) {
|
||||||
|
HashMap<String, Bomb> collectableBombs = this.bombs.entrySet().stream()
|
||||||
|
.filter(e -> e.getValue().getTicks() == null)
|
||||||
|
.collect(HashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll);
|
||||||
|
|
||||||
|
ArrayList<HackMan2PlayerState> playersOnBomb = getPlayersOnItem(state, collectableBombs);
|
||||||
|
|
||||||
|
for (HackMan2PlayerState playerState : playersOnBomb) {
|
||||||
|
playerState.updateBombs(1);
|
||||||
|
this.bombs.remove(playerState.getCoordinate().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void detonateBombs(HackMan2State state) {
|
||||||
|
this.bombs.forEach((key, bomb) -> bomb.tick());
|
||||||
|
ArrayList<String> explodingCoordinates = explodeBombs();
|
||||||
|
|
||||||
|
blastEnemies(explodingCoordinates);
|
||||||
|
blastPlayers(state, explodingCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<HackMan2PlayerState> getPlayersOnItem(HackMan2State state, Map itemMap) {
|
||||||
|
ArrayList<HackMan2PlayerState> playersNotOnSameCoord = getPlayersNotOnSameCoordinate(state);
|
||||||
|
|
||||||
|
// Return list of playerStates that have same coord as some item map
|
||||||
|
return playersNotOnSameCoord.stream()
|
||||||
|
.filter(ps -> itemMap.containsKey(ps.getCoordinate().toString()))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<HackMan2PlayerState> getPlayersNotOnSameCoordinate(HackMan2State state) {
|
||||||
|
ArrayList<HackMan2PlayerState> playerStates = new ArrayList<>(state.getPlayerStates());
|
||||||
|
|
||||||
|
// Shuffle to get random player on same coordinate
|
||||||
|
Collections.shuffle(playerStates, HackMan2Engine.RANDOM);
|
||||||
|
|
||||||
|
// Remove players on same coordinate
|
||||||
|
return new ArrayList<>(playerStates.stream()
|
||||||
|
.<Map<String, HackMan2PlayerState>> collect(
|
||||||
|
HashMap::new,
|
||||||
|
(m, ps) -> m.put(ps.getCoordinate().toString(), ps),
|
||||||
|
Map::putAll
|
||||||
|
)
|
||||||
|
.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swapCollideWithEnemies(HackMan2State previousState, HackMan2State state) {
|
||||||
|
ArrayList<Enemy> aliveEnemies = getAliveEnemies();
|
||||||
|
|
||||||
|
for (HackMan2PlayerState playerState : state.getPlayerStates()) {
|
||||||
|
Point coord = playerState.getCoordinate();
|
||||||
|
Point previousCoord = previousState.getPlayerStateById(
|
||||||
|
playerState.getPlayerId()).getCoordinate();
|
||||||
|
|
||||||
|
for (Enemy enemy : aliveEnemies) {
|
||||||
|
Enemy previousEnemy = previousState.getBoard().getEnemyById(enemy.getId());
|
||||||
|
|
||||||
|
if (previousEnemy == null) continue;
|
||||||
|
|
||||||
|
Point enemyCoord = enemy.getCoordinate();
|
||||||
|
Point previousEnemyCoord = previousEnemy.getCoordinate();
|
||||||
|
|
||||||
|
if (coord.equals(previousEnemyCoord) && enemyCoord.equals(previousCoord)) {
|
||||||
|
hitPlayerWithEnemy(playerState);
|
||||||
|
enemy.kill(EnemyDeath.ATTACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void positionCollideWithEnemies(HackMan2State state) {
|
||||||
|
ArrayList<Enemy> aliveEnemies = state.getBoard().getAliveEnemies();
|
||||||
|
|
||||||
|
state.getPlayerStates().forEach(playerState ->
|
||||||
|
aliveEnemies.stream()
|
||||||
|
.filter(enemy -> enemy.getCoordinate().equals(playerState.getCoordinate()))
|
||||||
|
.forEach(enemy -> {
|
||||||
|
hitPlayerWithEnemy(playerState);
|
||||||
|
enemy.kill(EnemyDeath.ATTACK);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Enemy> getAliveEnemies() {
|
||||||
|
return this.enemies.stream()
|
||||||
|
.filter(Enemy::isAlive)
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ArrayList<String> explodeBombs() {
|
||||||
|
ArrayList<String> explodingCoordinates = new ArrayList<>();
|
||||||
|
ArrayList<Bomb> explodedBombs = new ArrayList<>();
|
||||||
|
|
||||||
|
this.bombs.entrySet().stream()
|
||||||
|
.filter(e -> e.getValue().getTicks() != null && e.getValue().getTicks() == 0)
|
||||||
|
.forEach(e -> explodeBomb(e.getValue(), explodingCoordinates, explodedBombs));
|
||||||
|
|
||||||
|
// Remove all exploded bombs at the end
|
||||||
|
for (Bomb exploded : explodedBombs) {
|
||||||
|
this.bombs.remove(exploded.getCoordinate().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return explodingCoordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void explodeBomb(Bomb bomb, ArrayList<String> explodingCoordinates, ArrayList<Bomb> explodingBombs) {
|
||||||
|
Point coordinate = bomb.getCoordinate();
|
||||||
|
|
||||||
|
explodingBombs.add(bomb);
|
||||||
|
addExplodingCoordinate(coordinate, explodingCoordinates);
|
||||||
|
|
||||||
|
explodeInDirection(coordinate, new Point(0, -1), explodingCoordinates, explodingBombs);
|
||||||
|
explodeInDirection(coordinate, new Point(1, 0), explodingCoordinates, explodingBombs);
|
||||||
|
explodeInDirection(coordinate, new Point(0, 1), explodingCoordinates, explodingBombs);
|
||||||
|
explodeInDirection(coordinate, new Point(-1, 0), explodingCoordinates, explodingBombs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void explodeInDirection(Point coordinate, Point direction,
|
||||||
|
ArrayList<String> explodingCoordinates, ArrayList<Bomb> explodingBombs) {
|
||||||
|
Point newCoordinate = new Point(coordinate.x + direction.x, coordinate.y + direction.y);
|
||||||
|
|
||||||
|
if (!isCoordinateValid(newCoordinate)) return;
|
||||||
|
|
||||||
|
addExplodingCoordinate(newCoordinate, explodingCoordinates);
|
||||||
|
explodeInDirection(newCoordinate, direction, explodingCoordinates, explodingBombs); // recursive call
|
||||||
|
|
||||||
|
Bomb nextBomb = this.bombs.get(newCoordinate.toString());
|
||||||
|
|
||||||
|
if (nextBomb == null || explodingBombs.contains(nextBomb) || nextBomb.getTicks() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// explode bombs that are hit in the blast
|
||||||
|
explodeBomb(nextBomb, explodingCoordinates, explodingBombs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void blastEnemies(ArrayList<String> explodingCoordinates) {
|
||||||
|
this.enemies.stream()
|
||||||
|
.filter(enemy -> explodingCoordinates.contains(enemy.getCoordinate().toString()))
|
||||||
|
.forEach(enemy -> enemy.kill(EnemyDeath.BOMBED));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void blastPlayers(HackMan2State state, ArrayList<String> explodingCoordinates) {
|
||||||
|
state.getPlayerStates().stream()
|
||||||
|
.filter(ps -> explodingCoordinates.contains(ps.getCoordinate().toString()))
|
||||||
|
.forEach(ps -> hitPlayerWithBomb(state, ps));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hitPlayerWithEnemy(HackMan2PlayerState playerState) {
|
||||||
|
int snippetLoss = HackMan2Engine.configuration.getInt("enemySnippetLoss");
|
||||||
|
playerState.updateSnippets(-snippetLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hitPlayerWithBomb(HackMan2State state, HackMan2PlayerState playerState) {
|
||||||
|
int snippetLoss = HackMan2Engine.configuration.getInt("bombSnippetLoss");
|
||||||
|
int playerSnippets = playerState.getSnippets();
|
||||||
|
int spawnCount = playerSnippets < snippetLoss ? playerSnippets : snippetLoss;
|
||||||
|
|
||||||
|
playerState.updateSnippets(-snippetLoss);
|
||||||
|
|
||||||
|
for (int n = 0; n < spawnCount; n++) {
|
||||||
|
spawnSnippet(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addExplodingCoordinate(Point coordinate, ArrayList<String> explodingCoordinates) {
|
||||||
|
String key = coordinate.toString();
|
||||||
|
|
||||||
|
if (explodingCoordinates.contains(key)) return;
|
||||||
|
|
||||||
|
explodingCoordinates.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point getRandomSpawnPoint(HackMan2State state) {
|
||||||
|
ArrayList<Point> spawnPoints = getItemSpawnPoints(state);
|
||||||
|
int randomIndex = HackMan2Engine.RANDOM.nextInt(spawnPoints.size());
|
||||||
|
|
||||||
|
return spawnPoints.get(randomIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Point> getItemSpawnPoints(HackMan2State state) {
|
||||||
|
ArrayList<Point> spawnPoints = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int y = 0; y < this.height; y++) {
|
||||||
|
for (int x = 0; x < this.width; x++) {
|
||||||
|
Point coordinate = new Point(x, y);
|
||||||
|
|
||||||
|
if (!isCoordinateValid(coordinate)) continue;
|
||||||
|
|
||||||
|
// Items can't spawn closer than 5 to each player
|
||||||
|
boolean distant = state.getPlayerStates().stream()
|
||||||
|
.allMatch(p -> p.getCoordinate().distance(coordinate) > 5);
|
||||||
|
boolean onOtherItem = this.snippets.containsKey(coordinate.toString()) ||
|
||||||
|
this.bombs.containsKey(coordinate.toString());
|
||||||
|
|
||||||
|
if (distant && !onOtherItem) {
|
||||||
|
spawnPoints.add(coordinate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return spawnPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Enemy getEnemyById(int id) {
|
||||||
|
return this.enemies.stream()
|
||||||
|
.filter(enemy -> enemy.getId() == id)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on the amount of snippets
|
||||||
|
private void startEnemySpawn(HackMan2State state) {
|
||||||
|
Configuration config = HackMan2Engine.configuration;
|
||||||
|
int snippetsCollected = state.getSnippetsCollected();
|
||||||
|
int spawningSpawnPoints = (int) this.enemySpawnPoints.stream()
|
||||||
|
.filter(sp -> sp.spawnTime != null)
|
||||||
|
.count();
|
||||||
|
int totalEnemies = spawningSpawnPoints + this.spawnedEnemies;
|
||||||
|
int enemiesToSpawn = ((snippetsCollected - config.getInt("enemySpawnDelay")) /
|
||||||
|
config.getInt("enemySpawnRate")) - totalEnemies;
|
||||||
|
|
||||||
|
for (int id = this.spawnedEnemies; id < this.spawnedEnemies + enemiesToSpawn; id++) {
|
||||||
|
int spawnType = totalEnemies % 4;
|
||||||
|
this.enemySpawnPoints.get(spawnType).setSpawnTime(config.getInt("enemySpawnTime"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on rounds
|
||||||
|
private void spawnSnippets(HackMan2State state) {
|
||||||
|
Configuration config = HackMan2Engine.configuration;
|
||||||
|
|
||||||
|
if (state.getRoundNumber() % config.getInt("snippetSpawnRate") == 0) {
|
||||||
|
for (int n = 0; n < config.getInt("snippetSpawnCount"); n++) {
|
||||||
|
spawnSnippet(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on amount of snippets
|
||||||
|
private void spawnBombs(HackMan2State state) {
|
||||||
|
Configuration config = HackMan2Engine.configuration;
|
||||||
|
int snippetsCollected = state.getSnippetsCollected();
|
||||||
|
int bombsToSpawn = ((snippetsCollected - config.getInt("bombSpawnDelay")) /
|
||||||
|
config.getInt("bombSpawnRate")) - this.spawnedBombs;
|
||||||
|
|
||||||
|
for (int n = 0; n < bombsToSpawn; n++) {
|
||||||
|
spawnBomb(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnSnippet(HackMan2State state) {
|
||||||
|
Point coordinate = getRandomSpawnPoint(state);
|
||||||
|
this.snippets.put(coordinate.toString(), new Snippet(coordinate));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnBomb(HackMan2State state) {
|
||||||
|
Point coordinate = getRandomSpawnPoint(state);
|
||||||
|
this.bombs.put(coordinate.toString(), new Bomb(coordinate, null));
|
||||||
|
this.spawnedBombs++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.AbstractEnemyAI - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public abstract class AbstractEnemyAI {
|
||||||
|
|
||||||
|
public abstract Point transform(Enemy enemy, HackMan2State state);
|
||||||
|
|
||||||
|
ArrayList<MoveType> getAvailableDirections(Enemy enemy, HackMan2Board board) {
|
||||||
|
MoveType direction = enemy.getDirection() != null ? enemy.getDirection() : MoveType.PASS;
|
||||||
|
|
||||||
|
return MoveType.getMovingMoveTypes().stream()
|
||||||
|
.filter(moveType -> !moveType.equals(direction.getOppositeMoveType()) &&
|
||||||
|
board.isDirectionValid(enemy.getCoordinate(), moveType))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there are any transformations the enemy MUST make, that value is returned.
|
||||||
|
*/
|
||||||
|
Point mandatoryTransform(Enemy enemy, ArrayList<MoveType> availableDirections) {
|
||||||
|
Point coordinate = enemy.getCoordinate();
|
||||||
|
|
||||||
|
switch (availableDirections.size()) {
|
||||||
|
// No directions available, turn around
|
||||||
|
case 0:
|
||||||
|
MoveType oppositeDirection = enemy.getDirection().getOppositeMoveType();
|
||||||
|
return oppositeDirection.getCoordinateAfterMove(coordinate);
|
||||||
|
// Only one direction available, go that way
|
||||||
|
case 1:
|
||||||
|
return availableDirections.get(0).getCoordinateAfterMove(coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns next point (1 step) the enemy must move to if it wants to get closer
|
||||||
|
* to given goal.
|
||||||
|
*/
|
||||||
|
Point transformToGoal(Point coordinate, Point goal, ArrayList<MoveType> availableDirections) {
|
||||||
|
// Map to the coordinates after moving in each available direction
|
||||||
|
ArrayList<Point> movedCoordinates = availableDirections.stream()
|
||||||
|
.map(direction -> direction.getCoordinateAfterMove(coordinate))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
// Shuffle so min returns a random value on same distances
|
||||||
|
Collections.shuffle(movedCoordinates, HackMan2Engine.RANDOM);
|
||||||
|
|
||||||
|
// Return coordinate with smallest euclidean distance
|
||||||
|
return movedCoordinates.stream()
|
||||||
|
.min(Comparator.comparingDouble(goal::distance))
|
||||||
|
.orElseThrow(() -> new RuntimeException("Failed to find shortest distance"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the player states sorted from closest to farthest to enemy
|
||||||
|
*/
|
||||||
|
ArrayList<HackMan2PlayerState> getSortedPlayers(Point coordinate, HackMan2State state) {
|
||||||
|
ArrayList<HackMan2PlayerState> playerStates = new ArrayList<>(state.getPlayerStates());
|
||||||
|
|
||||||
|
// Shuffle to get random player state on same distance values
|
||||||
|
Collections.shuffle(playerStates, HackMan2Engine.RANDOM);
|
||||||
|
|
||||||
|
// Sort from closest to farthest away from enemy coordinate
|
||||||
|
playerStates.sort(
|
||||||
|
Comparator.comparingDouble(ps -> coordinate.distance(ps.getCoordinate())));
|
||||||
|
|
||||||
|
return playerStates;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.ChaseAI - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* This enemy AI will always move to the current location
|
||||||
|
* of the closest player.
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class ChaseAI extends AbstractEnemyAI {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point transform(Enemy enemy, HackMan2State state) {
|
||||||
|
HackMan2Board board = state.getBoard();
|
||||||
|
Point coordinate = enemy.getCoordinate();
|
||||||
|
ArrayList<MoveType> availableDirections = getAvailableDirections(enemy, board);
|
||||||
|
|
||||||
|
Point mandatoryTransform = mandatoryTransform(enemy, availableDirections);
|
||||||
|
if (mandatoryTransform != null) { // Mandatory directions are always taken
|
||||||
|
return mandatoryTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
HackMan2PlayerState closestPlayer = getSortedPlayers(coordinate, state).get(0);
|
||||||
|
|
||||||
|
return transformToGoal(coordinate, closestPlayer.getCoordinate(), availableDirections);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.Enemy - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class Enemy extends HackMan2Object {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
private int type;
|
||||||
|
private boolean isAlive;
|
||||||
|
private EnemyDeath deathType;
|
||||||
|
private MoveType direction;
|
||||||
|
private AbstractEnemyAI enemyAI;
|
||||||
|
private Point newCoordinate; // Stores new coordinate after moving
|
||||||
|
|
||||||
|
public Enemy(int id, Point coordinate, int type) {
|
||||||
|
super(coordinate);
|
||||||
|
this.id = id;
|
||||||
|
this.type = type;
|
||||||
|
this.isAlive = true;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
this.enemyAI = new ChaseAI();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.enemyAI = new PredictAI();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.enemyAI = new LeverAI();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this.enemyAI = new FarChaseAI();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Enemy(Enemy enemy) {
|
||||||
|
super(enemy);
|
||||||
|
this.id = enemy.id;
|
||||||
|
this.type = enemy.type;
|
||||||
|
this.direction = enemy.direction;
|
||||||
|
this.enemyAI = enemy.enemyAI;
|
||||||
|
this.isAlive = enemy.isAlive;
|
||||||
|
this.deathType = enemy.deathType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.format("E%d", this.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getNewCoordinate(HackMan2State state) {
|
||||||
|
this.newCoordinate = this.enemyAI.transform(this, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void performMovement() {
|
||||||
|
this.direction = getNewDirection(this.coordinate, this.newCoordinate);
|
||||||
|
this.coordinate = this.newCoordinate;
|
||||||
|
this.newCoordinate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kill(EnemyDeath deathType) {
|
||||||
|
this.isAlive = false;
|
||||||
|
this.deathType = deathType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoveType getDirection() {
|
||||||
|
return this.direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAlive() {
|
||||||
|
return this.isAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnemyDeath getDeathType() {
|
||||||
|
return this.deathType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MoveType getNewDirection(Point oldCoordinate, Point newCoordinate) {
|
||||||
|
if (newCoordinate.x > oldCoordinate.x) return MoveType.RIGHT;
|
||||||
|
if (newCoordinate.x < oldCoordinate.x) return MoveType.LEFT;
|
||||||
|
if (newCoordinate.y > oldCoordinate.y) return MoveType.DOWN;
|
||||||
|
if (newCoordinate.y < oldCoordinate.y) return MoveType.UP;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.EnemyDeath - Created on 10-7-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public enum EnemyDeath {
|
||||||
|
ATTACK,
|
||||||
|
BOMBED;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2ObjectSerializer;
|
||||||
|
import io.riddles.javainterface.serialize.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.EnemySerializer - Created on 11-7-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class EnemySerializer implements Serializer<Enemy> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String traverseToString(Enemy enemy) {
|
||||||
|
return visitEnemy(enemy).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject traverseToJson(Enemy enemy) {
|
||||||
|
return visitEnemy(enemy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject visitEnemy(Enemy enemy) {
|
||||||
|
HackMan2ObjectSerializer objectSerializer = new HackMan2ObjectSerializer();
|
||||||
|
|
||||||
|
JSONObject enemyObj = objectSerializer.traverseToJson(enemy);
|
||||||
|
|
||||||
|
enemyObj.put("id", enemy.getId());
|
||||||
|
enemyObj.put("type", enemy.getType());
|
||||||
|
enemyObj.put("move", enemy.getDirection());
|
||||||
|
|
||||||
|
if (!enemy.isAlive()) {
|
||||||
|
enemyObj.put("death", enemy.getDeathType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return enemyObj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.SpawnPoint - Created on 14-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class EnemySpawnPoint extends HackMan2Object {
|
||||||
|
|
||||||
|
private int type;
|
||||||
|
public Integer spawnTime;
|
||||||
|
|
||||||
|
public EnemySpawnPoint(Point coordinate, int type) {
|
||||||
|
super(coordinate);
|
||||||
|
this.type = type;
|
||||||
|
this.spawnTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (this.spawnTime == null || this.spawnTime == 0) {
|
||||||
|
return "S";
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format("S%d", this.spawnTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpawnTime(Integer spawnTime) {
|
||||||
|
this.spawnTime = spawnTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reduceSpawnTime() {
|
||||||
|
if (this.spawnTime == null) return;
|
||||||
|
|
||||||
|
this.spawnTime--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Enemy spawnEnemy(int id) {
|
||||||
|
if (this.spawnTime == null || this.spawnTime != 0) return null;
|
||||||
|
|
||||||
|
this.spawnTime = null;
|
||||||
|
|
||||||
|
return new Enemy(id, new Point(getCoordinate()), this.type);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.FarChaseAI - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* This enemy AI will always move to the current location
|
||||||
|
* of the farthest player.
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class FarChaseAI extends AbstractEnemyAI {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point transform(Enemy enemy, HackMan2State state) {
|
||||||
|
HackMan2Board board = state.getBoard();
|
||||||
|
Point coordinate = enemy.getCoordinate();
|
||||||
|
ArrayList<MoveType> availableDirections = getAvailableDirections(enemy, board);
|
||||||
|
|
||||||
|
Point mandatoryTransform = mandatoryTransform(enemy, availableDirections);
|
||||||
|
if (mandatoryTransform != null) { // Mandatory directions are always taken
|
||||||
|
return mandatoryTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get farthest player
|
||||||
|
ArrayList<HackMan2PlayerState> players = getSortedPlayers(coordinate, state);
|
||||||
|
HackMan2PlayerState farthestPlayer = players.get(players.size() - 1);
|
||||||
|
|
||||||
|
return transformToGoal(coordinate, farthestPlayer.getCoordinate(), availableDirections);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.LeverAI - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* This enemy AI will always move to a point that is the vector
|
||||||
|
* from the enemy closest to the closest player, to that closest player
|
||||||
|
* times two.
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class LeverAI extends AbstractEnemyAI {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point transform(Enemy enemy, HackMan2State state) {
|
||||||
|
HackMan2Board board = state.getBoard();
|
||||||
|
Point coordinate = enemy.getCoordinate();
|
||||||
|
ArrayList<MoveType> availableDirections = getAvailableDirections(enemy, board);
|
||||||
|
|
||||||
|
Point mandatoryTransform = mandatoryTransform(enemy, availableDirections);
|
||||||
|
if (mandatoryTransform != null) { // Mandatory directions are always taken
|
||||||
|
return mandatoryTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
HackMan2PlayerState closestPlayer = getSortedPlayers(coordinate, state).get(0);
|
||||||
|
ArrayList<Enemy> enemies = state.getBoard().getEnemies();
|
||||||
|
Enemy closestEnemy = enemies.stream()
|
||||||
|
.filter(e -> e.getId() != enemy.getId())
|
||||||
|
.min(Comparator.comparingDouble(
|
||||||
|
e -> e.getCoordinate().distance(closestPlayer.getCoordinate())))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (closestEnemy == null) { // if no other enemy, take self
|
||||||
|
closestEnemy = enemy;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point playerCoord = closestPlayer.getCoordinate();
|
||||||
|
Point enemyCoord = closestEnemy.getCoordinate();
|
||||||
|
Point leverVector = new Point(
|
||||||
|
playerCoord.x - enemyCoord.x,
|
||||||
|
playerCoord.y - enemyCoord.y
|
||||||
|
);
|
||||||
|
Point goalPosition = new Point(
|
||||||
|
playerCoord.x + leverVector.x,
|
||||||
|
playerCoord.y + leverVector.y
|
||||||
|
);
|
||||||
|
|
||||||
|
return transformToGoal(coordinate, goalPosition, availableDirections);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.enemy.PredictAI - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* This enemy AI will always move to the point 4 steps ahead
|
||||||
|
* of the closest player. Doesn't take walls, etc into account,
|
||||||
|
* so very crude.
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class PredictAI extends AbstractEnemyAI {
|
||||||
|
|
||||||
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
|
private final int PREDICT_STEPS = 4;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point transform(Enemy enemy, HackMan2State state) {
|
||||||
|
HackMan2Board board = state.getBoard();
|
||||||
|
Point coordinate = enemy.getCoordinate();
|
||||||
|
ArrayList<MoveType> availableDirections = getAvailableDirections(enemy, board);
|
||||||
|
|
||||||
|
Point mandatoryTransform = mandatoryTransform(enemy, availableDirections);
|
||||||
|
if (mandatoryTransform != null) { // Mandatory directions are always taken
|
||||||
|
return mandatoryTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get predicted position of closest player
|
||||||
|
HackMan2PlayerState closestPlayer = getSortedPlayers(coordinate, state).get(0);
|
||||||
|
Point playerCoordinate = closestPlayer.getCoordinate();
|
||||||
|
Point direction = closestPlayer.getDirection().getDirectionVector();
|
||||||
|
Point predictedPosition = new Point(
|
||||||
|
playerCoordinate.x + (direction.x * PREDICT_STEPS),
|
||||||
|
playerCoordinate.y + (direction.y * PREDICT_STEPS)
|
||||||
|
);
|
||||||
|
|
||||||
|
return transformToGoal(coordinate, predictedPosition, availableDirections);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.item;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.item.Bomb - Created on 9-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class Bomb extends HackMan2Object {
|
||||||
|
|
||||||
|
private Integer ticks;
|
||||||
|
|
||||||
|
public Bomb(Point coordinate, Integer ticks) {
|
||||||
|
super(coordinate);
|
||||||
|
this.ticks = ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bomb(Bomb bomb) {
|
||||||
|
super(bomb);
|
||||||
|
this.ticks = bomb.ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (this.ticks == null) {
|
||||||
|
return "B";
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.format("B%d", this.ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
if (this.ticks == null) return;
|
||||||
|
|
||||||
|
this.ticks--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getTicks() {
|
||||||
|
return this.ticks;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.item;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.item.Snippet - Created on 12-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class Snippet extends HackMan2Object {
|
||||||
|
|
||||||
|
public Snippet(Point coordinate) {
|
||||||
|
super(coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Snippet(Snippet snippet) {
|
||||||
|
super(snippet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "C";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.move;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.move.ActionType - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public enum ActionType {
|
||||||
|
CHARACTER,
|
||||||
|
MOVE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.move;
|
||||||
|
|
||||||
|
import io.riddles.javainterface.exception.InvalidInputException;
|
||||||
|
import io.riddles.javainterface.game.move.AbstractMove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.move.HackMan2Move - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2Move extends AbstractMove {
|
||||||
|
|
||||||
|
private MoveType type;
|
||||||
|
private Integer bombTicks;
|
||||||
|
|
||||||
|
public HackMan2Move(MoveType type) {
|
||||||
|
this.type = type;
|
||||||
|
this.bombTicks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2Move(MoveType type, int bombTicks) {
|
||||||
|
this.type = type;
|
||||||
|
this.bombTicks = bombTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2Move(InvalidInputException exception) {
|
||||||
|
super(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoveType getMoveType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBombTicks() {
|
||||||
|
return this.bombTicks;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.move;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
import io.riddles.javainterface.exception.InvalidInputException;
|
||||||
|
import io.riddles.javainterface.serialize.Deserializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.move.HackMan2MoveDeserializer - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2MoveDeserializer implements Deserializer<HackMan2Move> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HackMan2Move traverse(String string) {
|
||||||
|
try {
|
||||||
|
return visitMove(string);
|
||||||
|
} catch (InvalidInputException ex) {
|
||||||
|
return new HackMan2Move(ex);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return new HackMan2Move(new InvalidInputException("Failed to parse action"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HackMan2Move visitMove(String input) throws InvalidInputException {
|
||||||
|
String[] split = input.split(";");
|
||||||
|
|
||||||
|
MoveType moveType = visitMoveType(split[0]);
|
||||||
|
|
||||||
|
if (split.length < 2) {
|
||||||
|
return new HackMan2Move(moveType);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bombTicks = visitDropBomb(split[1]);
|
||||||
|
return new HackMan2Move(moveType, bombTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MoveType visitMoveType(String input) throws InvalidInputException {
|
||||||
|
MoveType moveType = MoveType.fromString(input);
|
||||||
|
|
||||||
|
if (moveType == null) {
|
||||||
|
throw new InvalidInputException("Move action isn't valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return moveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int visitDropBomb(String input) throws InvalidInputException {
|
||||||
|
String[] split = input.split(" ");
|
||||||
|
|
||||||
|
if (!split[0].equals("drop_bomb")) {
|
||||||
|
throw new InvalidInputException("Secondary move can only be 'drop_bomb'");
|
||||||
|
}
|
||||||
|
|
||||||
|
int bombTicks;
|
||||||
|
|
||||||
|
try {
|
||||||
|
bombTicks = Integer.parseInt(split[1]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidInputException("Can't parse amount of bomb ticks");
|
||||||
|
}
|
||||||
|
|
||||||
|
int minTicks = HackMan2Engine.configuration.getInt("bombMinTicks");
|
||||||
|
int maxTicks = HackMan2Engine.configuration.getInt("bombMaxTicks");
|
||||||
|
if (bombTicks < minTicks || bombTicks > maxTicks) {
|
||||||
|
throw new InvalidInputException(String.format(
|
||||||
|
"Bomb ticks must be between %d and %d (inclusive)", minTicks, maxTicks));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bombTicks;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.move;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.move.MoveType - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public enum MoveType {
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
PASS;
|
||||||
|
|
||||||
|
private static final Map<String, MoveType> TYPE_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (MoveType moveType : values()) {
|
||||||
|
TYPE_MAP.put(moveType.toString(), moveType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<MoveType> getMovingMoveTypes() {
|
||||||
|
ArrayList<MoveType> movingMoveTypes = new ArrayList<>();
|
||||||
|
|
||||||
|
movingMoveTypes.add(UP);
|
||||||
|
movingMoveTypes.add(DOWN);
|
||||||
|
movingMoveTypes.add(LEFT);
|
||||||
|
movingMoveTypes.add(RIGHT);
|
||||||
|
|
||||||
|
return movingMoveTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoveType getOppositeMoveType() {
|
||||||
|
switch (this) {
|
||||||
|
case LEFT:
|
||||||
|
return MoveType.RIGHT;
|
||||||
|
case RIGHT:
|
||||||
|
return MoveType.LEFT;
|
||||||
|
case UP:
|
||||||
|
return MoveType.DOWN;
|
||||||
|
case DOWN:
|
||||||
|
return MoveType.UP;
|
||||||
|
default:
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getDirectionVector() {
|
||||||
|
switch (this) {
|
||||||
|
case LEFT:
|
||||||
|
return new Point(-1, 0);
|
||||||
|
case RIGHT:
|
||||||
|
return new Point(1, 0);
|
||||||
|
case UP:
|
||||||
|
return new Point(0, -1);
|
||||||
|
case DOWN:
|
||||||
|
return new Point(0, 1);
|
||||||
|
default:
|
||||||
|
return new Point(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getCoordinateAfterMove(Point coordinate) {
|
||||||
|
Point direction = getDirectionVector();
|
||||||
|
|
||||||
|
return new Point(coordinate.x + direction.x, coordinate.y + direction.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MoveType fromString(String string) {
|
||||||
|
return TYPE_MAP.get(string.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package io.riddles.hackman2.game.player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.player.PlayerType - Created on 10-7-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public enum CharacterType {
|
||||||
|
BIXIE,
|
||||||
|
BIXIETTE;
|
||||||
|
|
||||||
|
private static final Map<String, CharacterType> TYPE_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (CharacterType moveType : values()) {
|
||||||
|
TYPE_MAP.put(moveType.toString(), moveType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CharacterType getRandomCharacter() {
|
||||||
|
ArrayList<CharacterType> values = new ArrayList<>(TYPE_MAP.values());
|
||||||
|
return values.get(HackMan2Engine.RANDOM.nextInt(values.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CharacterType fromString(String string) {
|
||||||
|
return TYPE_MAP.get(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.player;
|
||||||
|
|
||||||
|
import io.riddles.javainterface.game.player.AbstractPlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.player.HackMan2Player - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2Player extends AbstractPlayer {
|
||||||
|
|
||||||
|
private CharacterType characterType;
|
||||||
|
|
||||||
|
public HackMan2Player(int id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharacterType(CharacterType characterType) {
|
||||||
|
this.characterType = characterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterType getCharacterType() {
|
||||||
|
return this.characterType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.processor;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.engine.HackMan2Engine;
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.hackman2.game.move.ActionType;
|
||||||
|
import io.riddles.hackman2.game.move.HackMan2Move;
|
||||||
|
import io.riddles.hackman2.game.move.HackMan2MoveDeserializer;
|
||||||
|
import io.riddles.hackman2.game.player.HackMan2Player;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState;
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State;
|
||||||
|
import io.riddles.javainterface.exception.InvalidMoveException;
|
||||||
|
import io.riddles.javainterface.game.player.PlayerProvider;
|
||||||
|
import io.riddles.javainterface.game.processor.SimpleProcessor;
|
||||||
|
import io.riddles.javainterface.game.state.AbstractPlayerState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.processor.HackMan2Processor - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2Processor extends SimpleProcessor<HackMan2State, HackMan2Player> {
|
||||||
|
|
||||||
|
private HackMan2MoveDeserializer moveDeserializer;
|
||||||
|
|
||||||
|
public HackMan2Processor(PlayerProvider<HackMan2Player> playerProvider) {
|
||||||
|
super(playerProvider);
|
||||||
|
this.moveDeserializer = new HackMan2MoveDeserializer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasGameEnded(HackMan2State state) {
|
||||||
|
int maxRounds = HackMan2Engine.configuration.getInt("maxRounds");
|
||||||
|
ArrayList<HackMan2PlayerState> alivePlayers = state.getAlivePlayers();
|
||||||
|
|
||||||
|
return state.getRoundNumber() >= maxRounds || alivePlayers.size() <= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getWinnerId(HackMan2State state) {
|
||||||
|
ArrayList<HackMan2PlayerState> alivePlayers = state.getAlivePlayers();
|
||||||
|
|
||||||
|
if (alivePlayers.size() == 0) {
|
||||||
|
return null;
|
||||||
|
} else if (alivePlayers.size() == 1) {
|
||||||
|
return alivePlayers.get(0).getPlayerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<HackMan2PlayerState> winners = new ArrayList<>();
|
||||||
|
int maxSnippets = -1;
|
||||||
|
for (HackMan2PlayerState playerState : alivePlayers) {
|
||||||
|
if (playerState.getSnippets() > maxSnippets) {
|
||||||
|
maxSnippets = playerState.getSnippets();
|
||||||
|
winners.clear();
|
||||||
|
winners.add(playerState);
|
||||||
|
} else if (playerState.getSnippets() == maxSnippets) {
|
||||||
|
winners.add(playerState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (winners.size() == 1) {
|
||||||
|
return winners.get(0).getPlayerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getScore(HackMan2State state) {
|
||||||
|
return state.getRoundNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HackMan2State createNextState(HackMan2State inputState, int roundNumber) {
|
||||||
|
HackMan2State nextState = inputState.createNextState(roundNumber);
|
||||||
|
HackMan2Board board = nextState.getBoard();
|
||||||
|
|
||||||
|
// Clean up enemies from previous round (i.e. remove dead ones)
|
||||||
|
board.cleanUpEnemies();
|
||||||
|
|
||||||
|
// Send updates and get all moves
|
||||||
|
for (HackMan2PlayerState playerState : nextState.getPlayerStates()) {
|
||||||
|
HackMan2Player player = getPlayer(playerState.getPlayerId());
|
||||||
|
|
||||||
|
sendUpdatesToPlayer(inputState, player);
|
||||||
|
HackMan2Move move = getPlayerMove(player);
|
||||||
|
playerState.setMove(move);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move enemies (before they know where the players are going)
|
||||||
|
board.moveEnemies(nextState);
|
||||||
|
|
||||||
|
// Move the players
|
||||||
|
executePlayerMoves(nextState);
|
||||||
|
|
||||||
|
// Perform object pickups
|
||||||
|
board.performPickups(nextState);
|
||||||
|
|
||||||
|
// Spawn enemies from spawnpoints (before collisions)
|
||||||
|
board.spawnEnemies();
|
||||||
|
|
||||||
|
// Calculate changes due to collisions
|
||||||
|
board.performCollisions(inputState, nextState);
|
||||||
|
|
||||||
|
// Spawn all new objects
|
||||||
|
board.spawnObjects(nextState);
|
||||||
|
|
||||||
|
return nextState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendUpdatesToPlayer(HackMan2State state, HackMan2Player player) {
|
||||||
|
player.sendUpdate("round", state.getRoundNumber());
|
||||||
|
player.sendUpdate("field", state.getBoard().toString(state));
|
||||||
|
|
||||||
|
for (HackMan2PlayerState targetPlayerState : state.getPlayerStates()) {
|
||||||
|
HackMan2Player target = getPlayer(targetPlayerState.getPlayerId());
|
||||||
|
|
||||||
|
player.sendUpdate("snippets", target, targetPlayerState.getSnippets());
|
||||||
|
player.sendUpdate("bombs", target, targetPlayerState.getBombs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executePlayerMoves(HackMan2State state) {
|
||||||
|
HackMan2Board board = state.getBoard();
|
||||||
|
|
||||||
|
for (HackMan2PlayerState playerState : state.getPlayerStates()) {
|
||||||
|
HackMan2Move move = playerState.getMove();
|
||||||
|
board.validateMove(playerState, move);
|
||||||
|
|
||||||
|
if (!move.isInvalid()) {
|
||||||
|
executePlayerMove(board, playerState, move);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move.isInvalid()) {
|
||||||
|
HackMan2Player player = getPlayer(playerState.getPlayerId());
|
||||||
|
player.sendWarning(move.getException().getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executePlayerMove(HackMan2Board board, HackMan2PlayerState playerState, HackMan2Move move) {
|
||||||
|
// Move player
|
||||||
|
Point oldCoordinate = playerState.getCoordinate();
|
||||||
|
Point newCoordinate = board.getCoordinateAfterMove(move.getMoveType(), oldCoordinate);
|
||||||
|
playerState.setCoordinate(newCoordinate);
|
||||||
|
playerState.setDirection(move.getMoveType());
|
||||||
|
|
||||||
|
// Drop bomb
|
||||||
|
if (move.getBombTicks() != null) {
|
||||||
|
if (playerState.getBombs() > 0) {
|
||||||
|
board.dropBomb(newCoordinate, move.getBombTicks() + 1); // +1 for tick this round
|
||||||
|
playerState.updateBombs(-1);
|
||||||
|
} else {
|
||||||
|
move.setException(new InvalidMoveException("No bombs available"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HackMan2Move getPlayerMove(HackMan2Player player) {
|
||||||
|
String response = player.requestMove(ActionType.MOVE);
|
||||||
|
return this.moveDeserializer.traverse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HackMan2Player getPlayer(int id) {
|
||||||
|
return this.playerProvider.getPlayerById(id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.state;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.move.HackMan2Move;
|
||||||
|
import io.riddles.hackman2.game.move.MoveType;
|
||||||
|
import io.riddles.javainterface.game.state.AbstractPlayerState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.state.HackMan2PlayerState - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2PlayerState extends AbstractPlayerState<HackMan2Move> {
|
||||||
|
|
||||||
|
private int snippets;
|
||||||
|
private int bombs;
|
||||||
|
private Point coordinate;
|
||||||
|
private boolean isAlive;
|
||||||
|
private MoveType direction;
|
||||||
|
|
||||||
|
public HackMan2PlayerState(int playerId, Point startCoordinate) {
|
||||||
|
super(playerId);
|
||||||
|
this.snippets = 0;
|
||||||
|
this.bombs = 0;
|
||||||
|
this.coordinate = startCoordinate;
|
||||||
|
this.isAlive = true;
|
||||||
|
this.direction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2PlayerState(HackMan2PlayerState playerState) {
|
||||||
|
super(playerState.getPlayerId());
|
||||||
|
this.snippets = playerState.getSnippets();
|
||||||
|
this.bombs = playerState.getBombs();
|
||||||
|
this.coordinate = new Point(playerState.getCoordinate());
|
||||||
|
this.isAlive = playerState.isAlive();
|
||||||
|
this.direction = playerState.getDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.format("P%d", this.playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSnippets(int delta) {
|
||||||
|
this.snippets += delta;
|
||||||
|
|
||||||
|
if (this.snippets < 0) {
|
||||||
|
this.snippets = 0;
|
||||||
|
this.isAlive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSnippets() {
|
||||||
|
return this.snippets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBombs(int delta) {
|
||||||
|
this.bombs = this.bombs + delta >= 0 ? this.bombs + delta : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBombs() {
|
||||||
|
return this.bombs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoordinate(Point coordinate) {
|
||||||
|
this.coordinate = coordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getCoordinate() {
|
||||||
|
return this.coordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAlive() {
|
||||||
|
return this.isAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirection(MoveType direction) {
|
||||||
|
this.direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoveType getDirection() {
|
||||||
|
return this.direction;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.state;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import io.riddles.javainterface.serialize.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.state.HackMan2PlayerStateSerializer - Created on 15-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2PlayerStateSerializer implements Serializer<HackMan2PlayerState> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String traverseToString(HackMan2PlayerState playerState) {
|
||||||
|
return visitPlayerState(playerState).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject traverseToJson(HackMan2PlayerState playerState) {
|
||||||
|
return visitPlayerState(playerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject visitPlayerState(HackMan2PlayerState playerState) {
|
||||||
|
JSONObject playerStateObj = new JSONObject();
|
||||||
|
|
||||||
|
playerStateObj.put("id", playerState.getPlayerId());
|
||||||
|
playerStateObj.put("x", playerState.getCoordinate().x);
|
||||||
|
playerStateObj.put("y", playerState.getCoordinate().y);
|
||||||
|
playerStateObj.put("bombs", playerState.getBombs());
|
||||||
|
playerStateObj.put("score", playerState.getSnippets());
|
||||||
|
|
||||||
|
if (playerState.getMove() != null && !playerState.getMove().isInvalid()) {
|
||||||
|
playerStateObj.put("move", playerState.getMove().getMoveType());
|
||||||
|
} else {
|
||||||
|
playerStateObj.put("move", JSONObject.NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerStateObj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.state;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
import io.riddles.javainterface.game.state.AbstractPlayerState;
|
||||||
|
import io.riddles.javainterface.game.state.AbstractState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.state.HackMan2State - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2State extends AbstractState<HackMan2PlayerState> {
|
||||||
|
|
||||||
|
private HackMan2Board board;
|
||||||
|
private int snippetsCollected;
|
||||||
|
|
||||||
|
// For initital state only
|
||||||
|
public HackMan2State(ArrayList<HackMan2PlayerState> playerStates, HackMan2Board board) {
|
||||||
|
super(null, playerStates, 0);
|
||||||
|
this.board = board;
|
||||||
|
this.snippetsCollected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2State(HackMan2State previousState, ArrayList<HackMan2PlayerState> playerStates, int roundNumber) {
|
||||||
|
super(previousState, playerStates, roundNumber);
|
||||||
|
this.board = new HackMan2Board(previousState.board);
|
||||||
|
this.snippetsCollected = previousState.snippetsCollected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2State createNextState(int roundNumber) {
|
||||||
|
// Create new player states from current player states
|
||||||
|
ArrayList<HackMan2PlayerState> playerStates = new ArrayList<>();
|
||||||
|
for (HackMan2PlayerState playerState : this.getPlayerStates()) {
|
||||||
|
playerStates.add(new HackMan2PlayerState(playerState));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new state from current state
|
||||||
|
return new HackMan2State(this, playerStates, roundNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<HackMan2PlayerState> getAlivePlayers() {
|
||||||
|
return this.playerStates.stream()
|
||||||
|
.filter(HackMan2PlayerState::isAlive)
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSnippetCollected() {
|
||||||
|
this.snippetsCollected++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSnippetsCollected() {
|
||||||
|
return this.snippetsCollected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HackMan2Board getBoard() {
|
||||||
|
return this.board;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.state;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.HackMan2ObjectSerializer;
|
||||||
|
import io.riddles.hackman2.game.enemy.EnemySerializer;
|
||||||
|
import io.riddles.hackman2.game.item.Bomb;
|
||||||
|
import io.riddles.hackman2.game.item.Snippet;
|
||||||
|
import io.riddles.javainterface.serialize.Serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.state.HackMan2StateSerializer - Created on 8-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
public class HackMan2StateSerializer implements Serializer<HackMan2State> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String traverseToString(HackMan2State state) {
|
||||||
|
return visitState(state).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject traverseToJson(HackMan2State state) {
|
||||||
|
return visitState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject visitState(HackMan2State state) {
|
||||||
|
HackMan2PlayerStateSerializer playerStateSerializer = new HackMan2PlayerStateSerializer();
|
||||||
|
EnemySerializer enemySerializer = new EnemySerializer();
|
||||||
|
HackMan2ObjectSerializer objectSerializer = new HackMan2ObjectSerializer();
|
||||||
|
|
||||||
|
JSONObject stateObj = new JSONObject();
|
||||||
|
|
||||||
|
JSONArray playerArray = new JSONArray();
|
||||||
|
JSONArray collectibleArray = new JSONArray();
|
||||||
|
JSONArray bombArray = new JSONArray();
|
||||||
|
JSONArray enemyArray = new JSONArray();
|
||||||
|
|
||||||
|
state.getPlayerStates().forEach(
|
||||||
|
playerState -> playerArray.put(playerStateSerializer.traverseToJson(playerState))
|
||||||
|
);
|
||||||
|
state.getBoard().getSnippets().forEach(
|
||||||
|
(key, snippet) -> collectibleArray.put(objectSerializer.traverseToJson(snippet))
|
||||||
|
);
|
||||||
|
state.getBoard().getBombs().forEach((key, bomb) -> {
|
||||||
|
JSONObject bombObj = objectSerializer.traverseToJson(bomb);
|
||||||
|
bombObj.put("ticks", bomb.getTicks());
|
||||||
|
bombArray.put(bombObj);
|
||||||
|
});
|
||||||
|
state.getBoard().getEnemies().forEach(
|
||||||
|
enemy -> enemyArray.put(enemySerializer.traverseToJson(enemy))
|
||||||
|
);
|
||||||
|
|
||||||
|
stateObj.put("round", state.getRoundNumber());
|
||||||
|
stateObj.put("players", playerArray);
|
||||||
|
stateObj.put("collectibles", collectibleArray);
|
||||||
|
stateObj.put("bombs", bombArray);
|
||||||
|
stateObj.put("enemies", enemyArray);
|
||||||
|
|
||||||
|
return stateObj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package io.riddles.hackman2.engine
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.player.HackMan2Player
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2PlayerState
|
||||||
|
import io.riddles.hackman2.game.state.HackMan2State
|
||||||
|
import io.riddles.javainterface.game.player.PlayerProvider
|
||||||
|
import io.riddles.javainterface.io.FileIOHandler
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.engine.HackMan2EngineSpec - Created on 3-10-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
class HackMan2EngineSpec extends Specification {
|
||||||
|
|
||||||
|
class TestEngine extends HackMan2Engine {
|
||||||
|
|
||||||
|
TestEngine(String wrapperInput, String[] botFiles) {
|
||||||
|
super(new PlayerProvider<>(), new FileIOHandler(wrapperInput))
|
||||||
|
|
||||||
|
for (int i = 0; i < botFiles.length; i++) {
|
||||||
|
HackMan2Player player = new HackMan2Player(i)
|
||||||
|
player.setIoHandler(new FileIOHandler(botFiles[i]))
|
||||||
|
this.playerProvider.add(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processor = createProcessor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test gates"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
String[] botInputs = new String[2]
|
||||||
|
|
||||||
|
String wrapperInput = "./test/resources/wrapper_input.txt"
|
||||||
|
botInputs[0] = "./test/resources/bot1_test_gates_input.txt"
|
||||||
|
botInputs[1] = "./test/resources/bot2_test_gates_input.txt"
|
||||||
|
|
||||||
|
TestEngine engine = new TestEngine(wrapperInput, botInputs)
|
||||||
|
TestEngine.configuration = engine.getDefaultConfiguration()
|
||||||
|
TestEngine.configuration.put("maxRounds", 13)
|
||||||
|
|
||||||
|
HackMan2State initialState = engine.getInitialState()
|
||||||
|
|
||||||
|
when:
|
||||||
|
HackMan2State finalState = engine.run(initialState)
|
||||||
|
HackMan2PlayerState playerState1 = finalState.getPlayerStateById(0)
|
||||||
|
HackMan2PlayerState playerState2 = finalState.getPlayerStateById(1)
|
||||||
|
|
||||||
|
then:
|
||||||
|
playerState1.getCoordinate().x == 17
|
||||||
|
playerState1.getCoordinate().y == 6
|
||||||
|
playerState2.getCoordinate().x == 1
|
||||||
|
playerState2.getCoordinate().y == 7
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 riddles.io (developers@riddles.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.riddles.hackman2.game.board
|
||||||
|
|
||||||
|
import io.riddles.hackman2.game.item.Bomb
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
import java.awt.Point
|
||||||
|
|
||||||
|
/**
|
||||||
|
* io.riddles.hackman2.game.board.HackMan2BoardSpec - Created on 13-6-17
|
||||||
|
*
|
||||||
|
* [description]
|
||||||
|
*
|
||||||
|
* @author Jim van Eeden - jim@riddles.io
|
||||||
|
*/
|
||||||
|
class HackMan2BoardSpec extends Specification {
|
||||||
|
|
||||||
|
String layout = ".,.,.,x,.,.,.,.,.,.,.,.,.,.,.,x,.,.,.," +
|
||||||
|
".,x,.,x,.,x,x,x,x,.,x,x,x,x,.,x,.,x,.," +
|
||||||
|
".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.," +
|
||||||
|
".,x,x,x,.,x,.,x,x,x,x,x,.,x,.,x,x,x,.," +
|
||||||
|
".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.," +
|
||||||
|
".,.,.,x,.,x,.,x,x,.,x,x,.,x,.,x,.,.,.," +
|
||||||
|
"x,.,x,x,.,.,.,x,x,.,x,x,.,.,.,x,x,.,x," +
|
||||||
|
".,.,x,x,.,x,x,x,x,.,x,x,x,x,.,x,x,.,.," +
|
||||||
|
"x,.,x,x,.,.,.,.,.,.,.,.,.,.,.,x,x,.,x," +
|
||||||
|
".,.,.,x,.,x,x,x,x,x,x,x,x,x,.,x,.,.,.," +
|
||||||
|
".,x,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,x,.," +
|
||||||
|
".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.," +
|
||||||
|
".,x,.,x,x,.,x,x,x,x,x,x,x,.,x,x,.,x,.," +
|
||||||
|
".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.," +
|
||||||
|
".,.,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,.,."
|
||||||
|
|
||||||
|
def "test explode bombs"() {
|
||||||
|
|
||||||
|
setup:
|
||||||
|
HackMan2Board board = new HackMan2Board(19, 15, layout, null, new ArrayList<>())
|
||||||
|
board.dropBomb(new Point(0, 0), 0)
|
||||||
|
board.dropBomb(new Point(2, 0), 5)
|
||||||
|
board.dropBomb(new Point(2, 1), 2)
|
||||||
|
board.dropBomb(new Point(2, 2), 0)
|
||||||
|
board.dropBomb(new Point(18, 0), 0)
|
||||||
|
Point coordinate = new Point(18, 5)
|
||||||
|
board.bombs.put(coordinate.toString(), new Bomb(coordinate, null))
|
||||||
|
|
||||||
|
when:
|
||||||
|
ArrayList<String> explosions = board.explodeBombs()
|
||||||
|
|
||||||
|
then:
|
||||||
|
explosions.toString() == "[java.awt.Point[x=0,y=0], java.awt.Point[x=1,y=0], " +
|
||||||
|
"java.awt.Point[x=2,y=0], java.awt.Point[x=2,y=1], java.awt.Point[x=2,y=2], " +
|
||||||
|
"java.awt.Point[x=3,y=2], java.awt.Point[x=4,y=2], java.awt.Point[x=0,y=1], " +
|
||||||
|
"java.awt.Point[x=0,y=2], java.awt.Point[x=0,y=3], java.awt.Point[x=0,y=4], " +
|
||||||
|
"java.awt.Point[x=0,y=5], java.awt.Point[x=18,y=0], java.awt.Point[x=18,y=1], " +
|
||||||
|
"java.awt.Point[x=18,y=2], java.awt.Point[x=18,y=3], java.awt.Point[x=18,y=4], " +
|
||||||
|
"java.awt.Point[x=18,y=5], java.awt.Point[x=17,y=0], java.awt.Point[x=16,y=0]]"
|
||||||
|
board.getBombs().size() == 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
bixie
|
||||||
|
up
|
||||||
|
up
|
||||||
|
up
|
||||||
|
left
|
||||||
|
left
|
||||||
|
down
|
||||||
|
left
|
||||||
|
down
|
||||||
|
down
|
||||||
|
left
|
||||||
|
left
|
||||||
|
left
|
||||||
|
up
|
||||||
|
up
|
||||||
|
right
|
||||||
|
up
|
||||||
|
up
|
||||||
|
up
|
||||||
|
up
|
|
@ -0,0 +1,20 @@
|
||||||
|
bixie
|
||||||
|
pass
|
||||||
|
down
|
||||||
|
down
|
||||||
|
down
|
||||||
|
right
|
||||||
|
right
|
||||||
|
up
|
||||||
|
right
|
||||||
|
up
|
||||||
|
up
|
||||||
|
right
|
||||||
|
right
|
||||||
|
right
|
||||||
|
down
|
||||||
|
down
|
||||||
|
left
|
||||||
|
down
|
||||||
|
down
|
||||||
|
down
|
|
@ -0,0 +1,2 @@
|
||||||
|
details
|
||||||
|
game
|
16
hack-man-2-engine-development/test_mshackman.txt
Normal file
16
hack-man-2-engine-development/test_mshackman.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
settings player_names player0,player1
|
||||||
|
settings your_bot player0
|
||||||
|
settings timebank 5000
|
||||||
|
settings time_per_move 200
|
||||||
|
settings your_botid 0
|
||||||
|
settings field_width 19
|
||||||
|
settings field_height 15
|
||||||
|
settings max_rounds 250
|
||||||
|
action character 5000
|
||||||
|
update game round 0
|
||||||
|
update game field S,.,.,x,.,.,.,.,.,.,.,.,.,.,.,x,.,.,S,.,x,.,x,.,x,x,x,x,.,x,x,x,x,.,x,.,x,.,C,x,.,.,.,x,.,.,.,C,.,.,.,x,.,.,.,x,.,.,x,x,x,.,x,.,x,x,x,x,x,.,x,.,x,x,x,.,.,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.,.,.,.,x,.,x,.,x,x,.,x,x,.,x,.,x,.,.,.,x,.,x,x,.,.,.,x,x,.,x,x,.,.,.,x,x,.,x,Gl,.,x,x,P0,x,x,x,x,.,x,x,x,x,P1,x,x,.,Gr,x,.,x,x,.,.,.,.,.,.,.,.,.,.,.,x,x,.,x,.,.,.,x,.,x,x,x,x,x,x,x,x,x,.,x,.,.,.,.,x,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,x,.,.,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.,.,x,.,x,x,.,x,x,x,x,x,x,x,.,x,x,.,x,.,.,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.,S,.,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,.,S
|
||||||
|
update player0 snippets 0
|
||||||
|
update player0 bombs 0
|
||||||
|
update player1 snippets 0
|
||||||
|
update player1 bombs 0
|
||||||
|
action move 5000
|
21
hack-man-2-engine-development/wrapper-commands.json
Normal file
21
hack-man-2-engine-development/wrapper-commands.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"wrapper": {
|
||||||
|
"timebankMax": 2000,
|
||||||
|
"timePerMove": 100,
|
||||||
|
"maxTimeouts": 0,
|
||||||
|
"resultFile": "./resultfile.json",
|
||||||
|
"propagateBotExitCode": false,
|
||||||
|
"debug": true
|
||||||
|
},
|
||||||
|
"match": {
|
||||||
|
"bots": [{
|
||||||
|
"command": "java -jar /home/jim/workspace/hackman2-starterbot-java/build/libs/hackman2-starterbot-java-1.0.0.jar"
|
||||||
|
},{
|
||||||
|
"command": "java -jar /home/jim/workspace/hackman2-starterbot-java/build/libs/hackman2-starterbot-java-1.0.0.jar"
|
||||||
|
}],
|
||||||
|
"engine": {
|
||||||
|
"command": "java -jar /home/jim/workspace/hackman2-engine-java/build/libs/hackman2-engine-java-1.0.3.jar",
|
||||||
|
"configuration": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue