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 {
|
||||
var _round: Int = 0
|
||||
var _timebank: Int = Settings.timebank
|
||||
var lastBoard: 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 oppo: Player = new Player(Settings.oppoId, Settings.oppoName)
|
||||
|
@ -37,7 +38,7 @@ class Game {
|
|||
|
||||
update match {
|
||||
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 bombs (name, rest) => playerBy(name).bombs = rest.toInt
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package bot
|
||||
|
||||
import bot.environment.topology.Direction
|
||||
import bot.environment.topology.Stay
|
||||
|
||||
class Player(val id: Int, val name: String) {
|
||||
var bombs: Int = 0
|
||||
var snippets: Int = 0
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
package bot.cortex
|
||||
|
||||
import bot.environment.topology.Point
|
||||
import bot.environment.Board
|
||||
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.Point
|
||||
import bot.util.Log.dbg
|
||||
import bot.environment.Wall
|
||||
import bot.environment.Spawner
|
||||
import bot.environment.Gate
|
||||
|
||||
|
||||
class BugAI extends Tactical {
|
||||
def evaluate(game: Game): Tactic = {
|
||||
|
@ -13,19 +25,69 @@ class BugAI extends Tactical {
|
|||
|
||||
val weightGrid = new Grid(board.width, board.height, 0: Int)
|
||||
|
||||
board.bugs foreach { weightGrid(_) put -1000 }
|
||||
|
||||
for ( bug <- board.bugs; point <- board.walkablePoints(bug.point) ) {
|
||||
val field = weightGrid(point)
|
||||
field put (field.content - 1000)
|
||||
for ( bugField <- board.bugs ) {
|
||||
weightGrid.put(bugField.point, -55)
|
||||
|
||||
bugField.content
|
||||
.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 =>
|
||||
tactic = tactic + {dir -> weightGrid(board.walk(game.bofaPoint)(dir)).content}
|
||||
}
|
||||
|
||||
board.walls foreach { w => weightGrid.put(w.point, -88) }
|
||||
dbg(s"$weightGrid")
|
||||
|
||||
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) }
|
||||
preventFallBack(point, weightGrid, board)
|
||||
|
||||
weightGrid(game.bofaPoint) put -999
|
||||
markWalls(weightGrid, board)
|
||||
weightGrid.put(game.bofaPoint, 0) // from snippetai view-point staying is disadvised
|
||||
markWalls(weightGrid, board) // just for visualization, not walkable anyway
|
||||
dbg(weightGrid.toString())
|
||||
|
||||
board.walkableDirs(point) // get all possible directions starting in point
|
||||
|
@ -42,14 +42,12 @@ class SnippetAI extends Tactical {
|
|||
@tailrec
|
||||
def runner(frontier: Set[Point], distance: Int): Unit = {
|
||||
if (frontier.isEmpty) return
|
||||
|
||||
dbg(s"""Frontier[dist= $distance]: ${frontier.mkString(",")}""")
|
||||
|
||||
|
||||
// process the current frontier and build the new one
|
||||
val nextFrontier =
|
||||
frontier filterNot { visited(_).get } flatMap { p =>
|
||||
visited(p) put true
|
||||
weightGrid(p).content += (1000 / math.pow(1.3, distance)).intValue
|
||||
frontier filterNot { f => visited(f).content } flatMap { p =>
|
||||
visited.put(p, true)
|
||||
weightGrid.put(p, weightGrid(p).content + (1000 / math.pow(1.3, distance)).intValue)
|
||||
board.walkablePoints(p)
|
||||
}
|
||||
|
||||
|
@ -74,6 +72,6 @@ class SnippetAI extends Tactical {
|
|||
}
|
||||
|
||||
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 bot.OptionInt
|
||||
import bot.environment.Board.Tokens
|
||||
import bot.environment.topology._
|
||||
import scala.util.control.Exception.allCatch
|
||||
|
||||
object Board {
|
||||
type Tokens = Set[Token]
|
||||
|
@ -23,17 +23,17 @@ class Board(val width: Int, val height: Int) {
|
|||
def snippets = _snippets.to[Set]
|
||||
def bugs = _bugs.to[Set]
|
||||
def bots(id: Int) = _bots.get(id)
|
||||
def bots = _bots.values.to[Set]
|
||||
def walls = _walls.to[Set]
|
||||
|
||||
def put(point: Point, tokens: Tokens) = {
|
||||
val field = _grid(point)
|
||||
field.content = tokens
|
||||
_grid put (point, tokens)
|
||||
|
||||
tokens foreach {
|
||||
case Snippet() => _snippets += field
|
||||
case Bug(_) => _bugs += field
|
||||
case Bot(id) => _bots += {id -> field}
|
||||
case Wall() => _walls += field
|
||||
case Snippet() => _snippets += _grid(point)
|
||||
case Bug(_) => _bugs += _grid(point)
|
||||
case Bot(id) => _bots += {id -> _grid(point)}
|
||||
case Wall() => _walls += _grid(point)
|
||||
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 = {
|
||||
_snippets.clear
|
||||
_bugs.clear
|
||||
|
@ -78,6 +91,14 @@ class Board(val width: Int, val height: Int) {
|
|||
|
||||
private def unpack(things: String): Tokens = {
|
||||
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
|
||||
.split (';') // get single tokens
|
||||
|
@ -87,12 +108,12 @@ class Board(val width: Int, val height: Int) {
|
|||
case ("P", id) => Bot(id.toInt)
|
||||
case ("G", "l") => Gate(Left)
|
||||
case ("G", "r") => Gate(Right)
|
||||
case ("E", ai) => Bug(ai.toInt)
|
||||
case ("E", ai) => Bug(AIType(ai.toInt))
|
||||
case ("C", _) => Snippet()
|
||||
case ("S", time) => Spawner(time.toOptInt)
|
||||
case ("B", time) => Bomb(time.toOptInt)
|
||||
case ("S", time) => Spawner(time.toOptionInt)
|
||||
case ("B", time) => Bomb(time.toOptionInt)
|
||||
case _ => throw new MatchError } // map to token type
|
||||
.map { tkn => tkn.asInstanceOf[Token] } // explicitely cast Array[Any] to Array[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 Gate (direction: Direction) 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 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 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 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
|
||||
|
||||
class Field[T] (val point: Point, var content: T) {
|
||||
class Field[T] (val point: Point, val content: T) {
|
||||
def x: Int = point.x
|
||||
def y: Int = point.y
|
||||
|
||||
def put(update: T) = content = update
|
||||
def put(update: T) = new Field(point, update)
|
||||
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 {
|
||||
def apply[T] (point: Point, content: T) = new Field(point, content)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package bot.environment.topology
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
import bot.util.Log.dbg
|
||||
|
||||
/** 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) {
|
||||
private val grid: Array[Array[Field[T]]] = Array.ofDim[Field[T]](width, height)
|
||||
|
||||
for (x <- 0 until width; y <- 0 until height)
|
||||
grid(x)(y) = Field( Point(x,y), default )
|
||||
for (x <- 0 until width; y <- 0 until height) put(Point(x,y), default)
|
||||
|
||||
def apply(x: Int, y: Int): Field[T] = grid(x)(y)
|
||||
def apply(point: Point): Field[T] = apply(point.x, point.y)
|
||||
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 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 +(delta: (Int, Int)): Point = this + (delta _1, delta _2)
|
||||
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}"
|
||||
|
||||
def canEqual(a: Any) = a.isInstanceOf[Point]
|
||||
override def equals(that: Any): Boolean =
|
||||
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