Permalink
Browse files

Refactoring to allow multiple groups of strategies that can work toge…

…ther to build a final list of outcomes
  • Loading branch information...
1 parent a4e28e9 commit 58e3235e3ced8e62c7dcbcc52dca571214fde767 @skipoleschris committed Apr 11, 2012
View
12 src/main/scala/scalatron/botwar/botPlugin/configuration/BotConfig.scala
@@ -1,9 +1,17 @@
package scalatron.botwar.botPlugin.configuration
-import com.typesafe.config.{ConfigValue, Config}
+import scala.collection.JavaConverters._
+import com.typesafe.config.{ConfigList, ConfigValue, Config}
+import java.util.Map.Entry
case class BotConfig(apocalypse: Int, round: Int, config: Config) {
- def strategyNames = (strategyConfigValues map (_.unwrapped().toString)).toList
+ def strategyGroups: Map[String, List[String]] = {
+ def strategies = config.getConfig("bot.strategies").entrySet().asScala
+ def values(entry: Entry[String, ConfigValue]) = entry.getValue.asInstanceOf[ConfigList].toArray(Array[ConfigValue]())
+ def stringValues(entry: Entry[String, ConfigValue]) = (values(entry) map (_.unwrapped().toString)).toList
+
+ (strategies map (entry => (entry.getKey, stringValues(entry)))).toMap
+ }
private def strategyConfigValues = config.getList("bot.strategies").toArray(Array[ConfigValue]())
}
View
5 src/main/scala/scalatron/botwar/botPlugin/domain/Outcome.scala
@@ -54,11 +54,12 @@ case class OutcomeResult(name: String,
}
object Outcome {
- def asResult(name: String, sequenceGenerator: Stream[Int], outcomes: Set[Outcome]): OutcomeResult = {
+ def asResult(name: String, sequenceGenerator: Stream[Int], outcomes: Set[Outcome]): Option[OutcomeResult] = {
def encodeOutcome(result: OutcomeResult, outcome: Outcome) = outcome.encode(result)
def compatibility(forMaster: Boolean)(outcome: Outcome) =
if ( forMaster ) outcome.compatibleWithMaster else outcome.compatibleWithMiniBot
- (outcomes filter compatibility(name == "Master")).foldLeft(OutcomeResult(name, sequenceGenerator))(encodeOutcome)
+ if ( outcomes.isEmpty ) None
+ else Some((outcomes filter compatibility(name == "Master")).foldLeft(OutcomeResult(name, sequenceGenerator))(encodeOutcome))
}
}
View
21 src/main/scala/scalatron/botwar/botPlugin/responders/BotControlResponder.scala
@@ -1,8 +1,8 @@
package scalatron.botwar.botPlugin.responders
import scalatron.botwar.botPlugin.protocol._
-import scalatron.botwar.botPlugin.domain.{Outcome, Request, DeltaOffset}
import scalatron.botwar.botPlugin.strategies.StrategyChain
+import scalatron.botwar.botPlugin.domain.{OutcomeResult, Outcome, Request, DeltaOffset}
case class BotControlResponder(environment: BotEnvironment,
@@ -25,19 +25,24 @@ case class BotControlResponder(environment: BotEnvironment,
offset: Option[DeltaOffset] = None): BotResponder = {
def lift[T](f: => T): Option[T] = Some(f)
- val result = for (
- req <- lift(Request(name, time, energy, view, offset, environment.trackedState));
- strategy <- forRequest(environment.strategies, req);
- outcomes <- lift(strategy.apply(req));
- result <- lift(Outcome.asResult(req.context.name, environment.sequenceGenerator, outcomes))
- ) yield result
+ val req = Request(name, time, energy, view, offset, environment.trackedState)
+ val allOutcomes = (for (
+ strategyGroup <- environment.strategies;
+ strategy <- forRequest(strategyGroup, req);
+ outcomes <- lift(strategy.apply(req))
+ ) yield outcomes).flatten
- result map { r =>
+ Outcome.asResult(req.context.name, environment.sequenceGenerator, allOutcomes) map { r =>
val nextEnv = (r.newMiniBots.foldLeft(environment) { (env, bot) =>
env.updateTrackedState(bot._1, bot._2)
}) updateTrackedState (r.name, r.trackedState) replace r.sequenceGenerator
BotControlResponder(nextEnv, r.actions.toIndexedSeq)
} getOrElse this
}
+
+ case class StrategyOutcome(name: String = "", outcomes: Set[Outcome] = Set()) {
+ def append(outcome: StrategyOutcome) = StrategyOutcome(outcome.name, outcome.outcomes ++ outcomes)
+ def lift: Option[StrategyOutcome] = if ( name == "") None else Some(this)
+ }
}
View
2 src/main/scala/scalatron/botwar/botPlugin/responders/BotEnvironment.scala
@@ -4,7 +4,7 @@ import scalatron.botwar.botPlugin.configuration.BotConfig
import scalatron.botwar.botPlugin.strategies.Strategy
case class BotEnvironment(botConfig: BotConfig,
- strategies: List[Strategy#StrategyFunction],
+ strategies: Set[List[Strategy#StrategyFunction]],
trackedState: Map[String, Map[String, String]] = Map.empty,
sequenceGenerator: Stream[Int] = Stream.from(1)) {
def updateTrackedState(name: String, entries: Map[String, String]) =
View
2 src/main/scala/scalatron/botwar/botPlugin/responders/InitialisingResponder.scala
@@ -10,7 +10,7 @@ case object InitialisingResponder extends BotResponder with Configuration with S
protected def forCommand(command: Command): Option[BotResponder] = command match {
case Welcome(_, path, apocalypse, round) => {
val botConfig = configure(path, apocalypse, round)
- val strategies = createStrategies(botConfig)
+ val strategies = createStrategyGroups(botConfig)
Some(BotControlResponder(BotEnvironment(botConfig, strategies)))
}
case _ => None
View
5 src/main/scala/scalatron/botwar/botPlugin/strategies/StrategyChain.scala
@@ -4,11 +4,12 @@ import scalatron.botwar.botPlugin.domain.Request
import scalatron.botwar.botPlugin.configuration.BotConfig
trait StrategyChain {
+
def forRequest(strategies: List[Strategy#StrategyFunction], request: Request): Option[Strategy#StrategyFunction] =
strategies find (_.isDefinedAt(request))
- def createStrategies(botConfig: BotConfig): List[Strategy#StrategyFunction] =
- botConfig.strategyNames map instantiate(botConfig)
+ def createStrategyGroups(botConfig: BotConfig): Set[List[Strategy#StrategyFunction]] =
+ (botConfig.strategyGroups map (_._2 map instantiate(botConfig))).toSet
private def instantiate(botConfig: BotConfig)(strategyName: String) = try {
val className = "scalatron.botwar.botPlugin.strategies." + strategyName
View
4 src/test/resources/bot.conf
@@ -1,3 +1,5 @@
bot {
- strategies = [ RandomMovementStrategy ]
+ strategies = {
+ movement = [ RandomMovementStrategy ]
+ }
}
View
6 src/test/resources/configtest/bot.conf
@@ -0,0 +1,6 @@
+bot {
+ strategies = {
+ movement = [ RandomMovementStrategy ]
+ others = [ NoOpStrategy ]
+ }
+}
View
12 src/test/scala/scalatron/botwar/botPlugin/configuration/ConfigurationSpec.scala
@@ -8,15 +8,23 @@ class ConfigurationSpec extends Specification with Configuration { def is =
endp^
"A Configuration should" ^
"load the bot configuration file" ! loadConfig^
+ "define the different strategy groups" ! strategyGroups^
end
def loadConfig = {
- val botConfig = configure("src/test/resources", 5000, 1)
+ val botConfig = configure("src/test/resources/configtest", 5000, 1)
(botConfig.apocalypse must_== 5000) and
(botConfig.round must_== 1) and
- (botConfig.strategyNames must_== ("RandomMovementStrategy" :: Nil)) and
(botConfig.config must not beNull)
}
+
+ def strategyGroups = {
+ val botConfig = configure("src/test/resources/configtest", 5000, 1)
+
+ (botConfig.strategyGroups.keys must containAllOf(Seq("movement", "others"))) and
+ (botConfig.strategyGroups.apply("movement") must_== ("RandomMovementStrategy" :: Nil)) and
+ (botConfig.strategyGroups.apply("others") must_== ("NoOpStrategy" :: Nil))
+ }
}
View
11 src/test/scala/scalatron/botwar/botPlugin/domain/OutcomeSpec.scala
@@ -21,6 +21,7 @@ class OutcomeSpec extends Specification { def is =
"be convertable into a result" ! asResult^
"exclude outcomes not compatible with a master" ! masterCompatibility^
"exclude outcomes not compatible with a mini-bot" ! miniBotCompatibility^
+ "not convert to a result if empty" ! emptyOutcomes^
end
def encodeMove = {
@@ -79,7 +80,7 @@ class OutcomeSpec extends Specification { def is =
}
def asResult = {
- val result = Outcome.asResult("Master", Stream.from(1), Set(MoveOutcome(DeltaOffset(1, -1)), SayOutcome("Test")))
+ val result = Outcome.asResult("Master", Stream.from(1), Set(MoveOutcome(DeltaOffset(1, -1)), SayOutcome("Test"))).get
(result.name must_== "Master") and
(result.sequenceGenerator.head must_== 1) and
@@ -94,7 +95,7 @@ class OutcomeSpec extends Specification { def is =
SayOutcome("say"),
UpdateRunningState("1", Map.empty),
UpdateTrackedState(Map("baz" -> "BAZ")))
- val result = Outcome.asResult("Master", Stream.from(1), allOutcomes)
+ val result = Outcome.asResult("Master", Stream.from(1), allOutcomes).get
(result.actions must haveSize(4)) and
(result.actions must containAllOf(Seq(Move(1, -1),
Spawn(1, -1, "1:foo/FOO", 100),
@@ -112,7 +113,7 @@ class OutcomeSpec extends Specification { def is =
SayOutcome("say"),
UpdateRunningState("1", Map("bam" -> "BAM")),
UpdateTrackedState(Map("baz" -> "BAZ")))
- val result = Outcome.asResult("1", Stream.from(1), allOutcomes)
+ val result = Outcome.asResult("1", Stream.from(1), allOutcomes).get
(result.actions must haveSize(5)) and
(result.actions must containAllOf(Seq(Move(1, -1),
Explode(5),
@@ -122,5 +123,9 @@ class OutcomeSpec extends Specification { def is =
(result.trackedState must contain(("baz" -> "BAZ"))) and
(result.newMiniBots must beEmpty)
}
+
+ def emptyOutcomes = {
+ Outcome.asResult("1", Stream.from(1), Set.empty) must_== None
+ }
}
View
8 src/test/scala/scalatron/botwar/botPlugin/responders/BotControlResponderSpec.scala
@@ -35,7 +35,7 @@ class BotControlResponderSpec extends Specification {def is =
val configEntries = Map(("bot.strategies" -> (Nil).asJava)).asJava
val config = ConfigFactory.parseMap(configEntries)
- val environment = BotEnvironment(BotConfig(5000, 1, config), Nil)
+ val environment = BotEnvironment(BotConfig(5000, 1, config), Set.empty)
val responder = BotControlResponder(environment)
responder.response must_== ""
@@ -45,7 +45,7 @@ class BotControlResponderSpec extends Specification {def is =
val configEntries = Map(("bot.strategies" -> (Nil).asJava)).asJava
val config = ConfigFactory.parseMap(configEntries)
- val environment = BotEnvironment(BotConfig(5000, 1, config), Nil)
+ val environment = BotEnvironment(BotConfig(5000, 1, config), Set.empty)
val responder = BotControlResponder(environment, Vector(Move(1, -1), Say("Test")))
responder.response must_== "Move(dx=1,dy=-1)|Say(text=Test)"
@@ -55,7 +55,7 @@ class BotControlResponderSpec extends Specification {def is =
val configEntries = Map(("bot.strategies" -> (Nil).asJava)).asJava
val config = ConfigFactory.parseMap(configEntries)
- val environment = BotEnvironment(BotConfig(5000, 1, config), Nil)
+ val environment = BotEnvironment(BotConfig(5000, 1, config), Set.empty)
val responder = BotControlResponder(environment, Vector(Move(1, -1), Say("Test")))
responder.respond("Welcome(name=Test,path=src/test/resources,apocalypse=5000,round=1)") must_== responder
@@ -65,7 +65,7 @@ class BotControlResponderSpec extends Specification {def is =
val configEntries = Map(("bot.strategies" -> (Nil).asJava)).asJava
val config = ConfigFactory.parseMap(configEntries)
- val environment = BotEnvironment(BotConfig(5000, 1, config), Nil)
+ val environment = BotEnvironment(BotConfig(5000, 1, config), Set.empty)
val responder = BotControlResponder(environment, Vector(Move(1, -1), Say("Test")))
responder.respond("Goodbye(energy=1000)") must_== responder
View
3 src/test/scala/scalatron/botwar/botPlugin/responders/InitialisingResponderSpec.scala
@@ -24,8 +24,9 @@ class InitialisingResponderSpec extends Specification { def is =
val responder = InitialisingResponder.respond("Welcome(name=Test,path=src/test/resources,apocalypse=5000,round=1)").asInstanceOf[BotControlResponder]
(responder.lastActions must beEmpty) and
- (responder.environment.botConfig.strategyNames must_== "RandomMovementStrategy" :: Nil) and
+ (responder.environment.botConfig.strategyGroups must_== Map("movement" -> ("RandomMovementStrategy" :: Nil))) and
(responder.environment.strategies must haveSize(1)) and
+ (responder.environment.strategies.head must haveSize(1)) and
(responder.environment.trackedState must_== Map.empty[String, Map[String, String]]) and
(responder.environment.sequenceGenerator.head must_== 1)
}
View
26 src/test/scala/scalatron/botwar/botPlugin/strategies/StrategyChainSpec.scala
@@ -18,37 +18,39 @@ class StrategyChainSpec extends Specification with StrategyChain { def is =
end
def strategyCreation = {
- val configEntries = Map(("bot.strategies" -> ("TestStrategy1" :: "TestStrategy2" :: Nil).asJava)).asJava
+ val configEntries = Map("bot.strategies" -> Map("test" -> ("TestStrategy1" :: "TestStrategy2" :: Nil).asJava).asJava).asJava
val config = ConfigFactory.parseMap(configEntries)
- val strategies = createStrategies(new BotConfig(5000, 1, config))
+ val strategies = createStrategyGroups(new BotConfig(5000, 1, config))
- strategies must haveSize(2)
+ (strategies must haveSize(1)) and
+ (strategies.head must haveSize(2))
}
def installNoOpStrategy = {
- val configEntries = Map(("bot.strategies" -> ("FooBar" :: Nil).asJava)).asJava
+ val configEntries = Map("bot.strategies" -> Map("test" -> ("FooBar" :: Nil).asJava).asJava).asJava
val config = ConfigFactory.parseMap(configEntries)
- val strategies = createStrategies(new BotConfig(5000, 1, config))
+ val strategies = createStrategyGroups(new BotConfig(5000, 1, config))
- strategies must haveSize(1)
+ (strategies must haveSize(1)) and
+ (strategies.head must haveSize(1))
}
def findStrategy = {
- val configEntries = Map(("bot.strategies" -> ("TestStrategy1" :: "TestStrategy2" :: Nil).asJava)).asJava
+ val configEntries = Map("bot.strategies" -> Map("test" -> ("TestStrategy1" :: "TestStrategy2" :: Nil).asJava).asJava).asJava
val config = ConfigFactory.parseMap(configEntries)
- val strategies = createStrategies(new BotConfig(5000, 1, config))
+ val strategies = createStrategyGroups(new BotConfig(5000, 1, config))
val request = Request("Master", 1, 100, "____M____", None, Map.empty)
- forRequest(strategies, request) must beSome[Strategy#StrategyFunction]
+ forRequest(strategies.head, request) must beSome[Strategy#StrategyFunction]
}
def noSuitableStrategy = {
- val configEntries = Map(("bot.strategies" -> ("TestStrategy1" :: "TestStrategy2" :: Nil).asJava)).asJava
+ val configEntries = Map("bot.strategies" -> Map("test" -> ("TestStrategy1" :: "TestStrategy2" :: Nil).asJava).asJava).asJava
val config = ConfigFactory.parseMap(configEntries)
- val strategies = createStrategies(new BotConfig(5000, 1, config))
+ val strategies = createStrategyGroups(new BotConfig(5000, 1, config))
val request = Request("1:", 1, 100, "____M____", None, Map.empty)
- forRequest(strategies, request) must_== None
+ forRequest(strategies.head, request) must_== None
}
}

0 comments on commit 58e3235

Please sign in to comment.