huiwang / codingame-scala-kit Goto Github PK
View Code? Open in Web Editor NEWCreate Better CG Bot in Scala
Create Better CG Bot in Scala
class GameLoop[Context, State, Action](
gameIO: GameIO[Context, State, Action],
myPlayer: GameBot[State, Action],
accumulator: GameAccumulator[Context, State, Action],
turns: Int = 200
) {
def run(): Unit = {
val time = System.nanoTime()
val initContext = gameIO.readContext
CGLogger.info("GameInit elt: " + (System.nanoTime() - time) / 1000000 + "ms")
(1 to turns).foldLeft(initContext) {
case (c, turn) =>
val state = gameIO.readState(turn, c)
CGLogger.info(state)
val time = System.nanoTime()
val actions = myPlayer.react(state)
CGLogger.info("GameReact elt: " + (System.nanoTime() - time) / 1000000 + "ms")
gameIO.writeAction(state, actions)
accumulator.accumulate(c, state, actions)
}
}
}
GameLoop was originally designed as a rule-tme-all control strcture for all kinds of games. Thanks to the strong contract, we can always model a game with IO, State/Action, and Bot layer. This allows us to have well-defined traits.
However, the strong contract becomes a limitation in cases where we have to adapt the game modeling to meet the contract. The adaptation is often ugly. For example, in the wondev contest, in addtion to the static context, we must also include historical information in the state to clear the fog of war. Consequently, the state object aggregates many information of different nature.
Instead, we should drop such kind of control strucutres and let the develop choose one best for the specific game. Take the wondev example again, I have a control strucutre as follows
object Player {
def main(args: Array[String]): Unit = {
CGLogger.current = CGLogger.info
var turn = 0
val initContext = WondevIO.readContext
var previousState: WondevState = null
var previousAction: WondevAction = null
var previousOppoScope: Set[Set[Pos]] = null
while (true) {
val state = WondevIO.readState(turn, initContext)
val oppoScope = WarFogAnalysis.restrictOppoScope(
state, previousState,
previousAction, previousOppoScope)
val clearedState = WarFogAnalysis.removeFog(state, oppoScope)
val action = MinimaxPlayer.react(clearedState)
previousState = state
previousAction = action
previousOppoScope = oppoScope
WondevIO.writeAction(state, action)
turn += 1
}
}
}
This way, I have a state object which is quite consistent(no mixing of different kind of infomration). It is still debuggable and benchmarkable. The complexity on the accumulator is reduced dramatically thanks to some mutable vars. What might please @tyrcho is that we don't have to implement anymore the IO, State, Bot in the retricted way (extending predefined traits).
Both Caribbean and Code4life winner strategy are based on minimax algo.
https://github.com/Agade09/Agade-Code-4-Life-Postmortem/blob/master/Agade_C4L_Postmortem.md
https://recursive.cc/blog/coders-of-the-carribean-post-mortem.html
TODO :
> jmh:run -i 10 -wi 10 -f1 -t1 .*Caribbean.*
[info] Updating {file:/Users/hwang/Developer/ai/CodinGameScalaKit/}codingamescalakit...
[info] Resolving jline#jline;2.14.1 ...
[info] Done updating.
[info] Compiling 69 Scala sources to /Users/hwang/Developer/ai/CodinGameScalaKit/target/scala-2.12/classes...
Processing 254 classes from /Users/hwang/Developer/ai/CodinGameScalaKit/target/scala-2.12/classes with "reflection" generator
Writing out Java source to /Users/hwang/Developer/ai/CodinGameScalaKit/target/scala-2.12/src_managed/jmh and resources to /Users/hwang/Developer/ai/CodinGameScalaKit/target/scala-2.12/resource_managed/jmh
Annotation generator had thrown the exception.
java.lang.IncompatibleClassChangeError: com.tyrcho.Player and com.tyrcho.Player$delayedInit$body disagree on InnerClasses attribute
at java.lang.Class.getDeclaringClass0(Native Method)
at java.lang.Class.getDeclaringClass(Class.java:1235)
at java.lang.Class.getEnclosingClass(Class.java:1277)
at java.lang.Class.getCanonicalName(Class.java:1392)
at org.openjdk.jmh.generators.reflection.RFClassInfo.getQualifiedName(RFClassInfo.java:67)
at org.openjdk.jmh.generators.core.BenchmarkGenerator.buildAnnotatedSet(BenchmarkGenerator.java:206)
at org.openjdk.jmh.generators.core.BenchmarkGenerator.generate(BenchmarkGenerator.java:75)
at org.openjdk.jmh.generators.bytecode.JmhBytecodeGenerator.main(JmhBytecodeGenerator.java:100)
at pl.project13.scala.sbt.JmhPlugin$.pl$project13$scala$sbt$JmhPlugin$$internalGenerateBenchmarkSourcesAndResources(JmhPlugin.scala:109)
at pl.project13.scala.sbt.JmhPlugin$$anonfun$2.apply(JmhPlugin.scala:92)
at pl.project13.scala.sbt.JmhPlugin$$anonfun$2.apply(JmhPlugin.scala:90)
at sbt.FileFunction$$anonfun$cached$1.apply(Tracked.scala:235)
at sbt.FileFunction$$anonfun$cached$1.apply(Tracked.scala:235)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3$$anonfun$apply$4.apply(Tracked.scala:249)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3$$anonfun$apply$4.apply(Tracked.scala:245)
at sbt.Difference.apply(Tracked.scala:224)
at sbt.Difference.apply(Tracked.scala:206)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3.apply(Tracked.scala:245)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3.apply(Tracked.scala:244)
at sbt.Difference.apply(Tracked.scala:224)
at sbt.Difference.apply(Tracked.scala:200)
at sbt.FileFunction$$anonfun$cached$2.apply(Tracked.scala:244)
at sbt.FileFunction$$anonfun$cached$2.apply(Tracked.scala:242)
at pl.project13.scala.sbt.JmhPlugin$.pl$project13$scala$sbt$JmhPlugin$$generateBenchmarkSourcesAndResources(JmhPlugin.scala:94)
at pl.project13.scala.sbt.JmhPlugin$$anonfun$projectSettings$13.apply(JmhPlugin.scala:50)
at pl.project13.scala.sbt.JmhPlugin$$anonfun$projectSettings$13.apply(JmhPlugin.scala:50)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
at sbt.std.Transform$$anon$4.work(System.scala:63)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.Execute.work(Execute.scala:235)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
is https://scalameter.github.io/ an alternative to jmh which works better in scala ?
http://mvnrepository.com/artifact/com.storm-enroute/scalameter_2.12/0.8.2
https://en.wikipedia.org/wiki/Nine_Men%27s_Morris
Implement a game with intermediate complexity to showcase the usage of our algorithms.
9-men is interesting because the rules change during the 3 game phases (placement, movement, finals with 3 stones), it is not deeply studied like chess and it's not trivial to play optimally like in tic-tac-toe
Just tried the Bundler for the previous challenge.
I have a fix for this issue, but I'd need your code formatter configuration to avoid formatting differences in the patch.
Apart from that, great tool :)
@huiwang Can we decide here the package organisation ?
I think we need to define :
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.