Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Map tiles
  • Loading branch information
cswinter committed Mar 8, 2020
1 parent 2ddf210 commit ee786ce
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 7 deletions.
Expand Up @@ -23,6 +23,7 @@ case class ObsConfig(
drones: Int,
minerals: Int,
globalDrones: Int,
tiles: Int,
relativePositions: Boolean,
extraBuildActions: Seq[Int], // Number of modules for custom build actions
obsLastAction: Boolean,
Expand Down Expand Up @@ -82,6 +83,7 @@ class Application @Inject()(
drones: Int,
minerals: Int,
globalDrones: Int,
tiles: Int,
relativePositions: Boolean,
v2: Boolean,
buildActions: Seq[Int],
Expand All @@ -93,6 +95,7 @@ class Application @Inject()(
drones,
minerals,
globalDrones,
tiles,
relativePositions,
buildActions,
obsLastAction,
Expand Down Expand Up @@ -139,11 +142,13 @@ class ObsSerializer(obs: Seq[Observation], obsConfig: ObsConfig) {
(if (obsConfig.lastSeen) { 2 } else { 0 })
private val enemyDroneFeat = 15 + (if (obsConfig.lastSeen) { 2 } else { 0 })
private val mineralFeat = 3
private val tileFeat = 4
private val enemies = obsConfig.drones - obsConfig.allies
private val totalObjectFeat =
allyDroneFeat * obsConfig.allies +
2 * enemyDroneFeat * enemies +
mineralFeat * obsConfig.minerals
mineralFeat * obsConfig.minerals +
tileFeat * obsConfig.tiles
private val naction = 8 + obsConfig.extraBuildActions.size
private val actionMaskFeat = obsConfig.allies * naction
private val size = obs.length * (globalFeat + totalObjectFeat + extraFeat + actionMaskFeat)
Expand Down Expand Up @@ -184,6 +189,14 @@ class ObsSerializer(obs: Seq[Observation], obsConfig: ObsConfig) {
val mpadding = (obsConfig.minerals - ob.minerals.size) * mineralFeat
for (_ <- 0 until mpadding) bb.putFloat(0.0f)

// Tiles
val tiles = ob.tiles
.sortBy(t => (t.lastVisitedTime, t.hashCode))
.take(obsConfig.tiles)
tiles.foreach(serializeTile(ob.timestep, ob.maxGameLength))
val tpadding = (obsConfig.tiles - tiles.size) * tileFeat
for (_ <- 0 until tpadding) bb.putFloat(0.0f)

// All enemies, including drones not visible to player
ob.allEnemyDrones.take(nEnemy).foreach(serializeDrone)
val aepadding = (nEnemy - ob.allEnemyDrones.size) * enemyDroneFeat
Expand Down Expand Up @@ -228,6 +241,13 @@ class ObsSerializer(obs: Seq[Observation], obsConfig: ObsConfig) {
bb.putFloat(m.size)
}

def serializeTile(time: Int, tmax: Int)(t: MapTile): Unit = {
bb.putFloat(t.centerX)
bb.putFloat(t.centerY)
bb.putFloat(if (t.lastVisitedTime == 0) tmax else time - t.lastVisitedTime)
bb.putFloat(if (t.lastVisitedTime == 0) { -1 } else { 1 })
}

def serializeScores(ob: Observation): Unit = {
bb.putFloat(ob.winner.map(_ + 1.0f).getOrElse(0))
bb.putFloat(ob.alliedScore.toFloat)
Expand Down
Expand Up @@ -36,7 +36,11 @@ class MultiplayerServer @Inject()(lifecycle: ApplicationLifecycle) {
synchronized {
val initialDrones = customMap.map(m => (m.player1Drones.size, m.player2Drones.size)).getOrElse((1, 1))
val maxGameLength = maxTicks.getOrElse(3 * 60 * 60)
val player1 = new PlayerController(maxGameLength, BluePlayer, gameID + 1)
val mapWidth = customMap.map(_.mapWidth).getOrElse(6000)
val mapHeight = customMap.map(_.mapHeight).getOrElse(4000)
val tileWidth = 400
val player1 =
new PlayerController(maxGameLength, BluePlayer, gameID + 1, mapWidth, mapHeight, tileWidth)
var controllers: Seq[DroneControllerBase] =
Seq.fill(initialDrones._1)(new PassiveDroneController(player1, Promise.successful(DoNothing)))
var player2: Option[PlayerController] = None
Expand All @@ -47,7 +51,8 @@ class MultiplayerServer @Inject()(lifecycle: ApplicationLifecycle) {
println("level7")
controllers ++= Seq.fill(initialDrones._2)(TheGameMaster.level7AI())
} else {
val p2 = new PlayerController(maxGameLength, OrangePlayer, gameID + 1)
val p2 =
new PlayerController(maxGameLength, OrangePlayer, gameID + 1, mapWidth, mapHeight, tileWidth)
player2 = Some(p2)
controllers ++= Seq.fill(initialDrones._2)(
new PassiveDroneController(p2, Promise.successful(DoNothing)))
Expand Down Expand Up @@ -137,6 +142,8 @@ class PassiveDroneController(
var lastAction: Action = Action(None, false, false, false, 0)

override def onTick(): Unit = {
state.updateTiles(position)

if (missileCooldown == 0 && enemiesInSight.nonEmpty) {
val closest = enemiesInSight.minBy(enemy => (enemy.position - position).lengthSquared)
if (isInMissileRange(closest)) fireMissilesAt(closest)
Expand Down Expand Up @@ -220,14 +227,31 @@ class PassiveDroneController(
override def metaController = Some(state)
}

class PlayerController(val maxGameLength: Int, val player: Player, val gameID: Int) extends MetaController {
class PlayerController(
val maxGameLength: Int,
val player: Player,
val gameID: Int,
val mapWidth: Int,
val mapHeight: Int,
val tileWidth: Int
) extends MetaController {
@volatile var alliedDrones = Seq.empty[PassiveDroneController]
@volatile var enemyDrones = Seq.empty[Drone]
@volatile var timeLastSeen = Map.empty[Drone, Int]
@volatile var sim: Option[DroneWorldSimulator] = None
@volatile var observationsReady: Promise[Unit] = Promise()
@volatile var minerals = Seq.empty[MineralCrystal]
@volatile var step0 = true
var time = 0
var timestep = 0
var tiles: Array[Array[MapTile]] = Array.tabulate(
(mapWidth + tileWidth - 1) / tileWidth,
(mapHeight + tileWidth - 1) / tileWidth
)(
(x, y) =>
new MapTile(x * tileWidth + tileWidth / 2 - mapWidth / 2,
y * tileWidth + tileWidth / 2 - mapHeight / 2,
0))
var dronecount = 0

def observe(sim: DroneWorldSimulator, lastSeen: Boolean): Observation = {
Expand All @@ -240,6 +264,7 @@ class PlayerController(val maxGameLength: Int, val player: Player, val gameID: I
def unsafe_observe(sim: DroneWorldSimulator, lastSeen: Boolean): Observation = {
val enemyPlayer = if (player == BluePlayer) OrangePlayer else BluePlayer
enemyDrones = enemyDrones.filterNot(_.isDead)
timestep = sim.timestep
Observation(
sim.timestep,
maxGameLength,
Expand Down Expand Up @@ -267,7 +292,8 @@ class PlayerController(val maxGameLength: Int, val player: Player, val gameID: I
.sum, // TODO: why doesn't dead drone get removed? (maybe one tick too late?)
sim.dronesFor(enemyPlayer).map(score).sum,
sim.config.worldSize.height,
sim.config.worldSize.width
sim.config.worldSize.width,
tiles.flatMap(_.toSeq)
)
}

Expand All @@ -288,6 +314,7 @@ class PlayerController(val maxGameLength: Int, val player: Player, val gameID: I
if (step0) {
step0 = false
} else if (!observationsReady.isCompleted) {
time += 1
Log.debug(f"[$gameID, $player] marking observation ready")
observationsReady.success(())
}
Expand All @@ -300,8 +327,33 @@ class PlayerController(val maxGameLength: Int, val player: Player, val gameID: I
}

def nextID(): Int = { dronecount += 1; dronecount }

def updateTiles(pos: Vector2): Unit = {
var x = ((pos.x + mapWidth / 2) / tileWidth).toInt
var y = ((pos.y + mapHeight / 2) / tileWidth).toInt

if (x < 0) x = 0
if (x >= tiles.length) x = tiles.length - 1
if (y < 0) y = 0
if (y >= tiles(0).length) y = tiles(0).length - 1

val tile = tiles(x)(y)

// assert(tile.centerX - tileWidth / 2 <= pos.x)
// assert(pos.x <= tile.centerX + tileWidth / 2)
// assert(tile.centerY - tileWidth / 2 <= pos.y)
// assert(pos.y <= tile.centerY + tileWidth / 2)

tile.lastVisitedTime = timestep + 10
}
}

case class MapTile(
centerX: Int,
centerY: Int,
var lastVisitedTime: Int
)

case class Observation(
timestep: Int,
maxGameLength: Int,
Expand All @@ -313,7 +365,8 @@ case class Observation(
alliedScore: Double,
enemyScore: Double,
mapHeight: Double,
mapWidth: Double
mapWidth: Double,
tiles: Seq[MapTile]
)

case class DroneObservation(
Expand Down
2 changes: 1 addition & 1 deletion server/conf/routes
Expand Up @@ -8,7 +8,7 @@ GET /observe com.clemenswinter.codecraftse
POST /start-game com.clemenswinter.codecraftserver.controllers.Application.startGame(maxTicks: Option[Int], actionDelay: Int ?= 0, scriptedOpponent: Boolean ?= true, idleOpponent: Boolean ?= true)
GET /observation com.clemenswinter.codecraftserver.controllers.Application.playerState(gameID: Int, playerID: Int)
POST /act com.clemenswinter.codecraftserver.controllers.Application.act(gameID: Int, playerID: Int)
GET /batch-observation com.clemenswinter.codecraftserver.controllers.Application.batchPlayerState(json: Boolean ?= true, allies: Int ?= 1, drones: Int ?= 10, minerals: Int ?= 10, globalDrones: Int ?= 0, relativePositions: Boolean ?= true, v2: Boolean ?= false, actions: Seq[Int] ?= Seq.empty, obsLastAction: Boolean ?= false, lastSeen: Boolean ?= false, mapSize: Boolean ?= false)
GET /batch-observation com.clemenswinter.codecraftserver.controllers.Application.batchPlayerState(json: Boolean ?= true, allies: Int ?= 1, drones: Int ?= 10, minerals: Int ?= 10, globalDrones: Int ?= 0, tiles: Int ?= 0, relativePositions: Boolean ?= true, v2: Boolean ?= false, actions: Seq[Int] ?= Seq.empty, obsLastAction: Boolean ?= false, lastSeen: Boolean ?= false, mapSize: Boolean ?= false)
POST /batch-act com.clemenswinter.codecraftserver.controllers.Application.batchAct()

GET /ajax/multiplayerServerStatus com.clemenswinter.codecraftserver.controllers.Application.mpssJson
Expand Down

0 comments on commit ee786ce

Please sign in to comment.