Added simon

This commit is contained in:
soywiz
2017-10-07 18:41:37 +02:00
parent a4e847e6a1
commit 54066d0514
37 changed files with 204 additions and 329 deletions

View File

@@ -0,0 +1,12 @@
apply plugin: 'kotlin-platform-common'
sourceSets {
main.resources.srcDirs = [ 'src/main/resources', 'src/generated/resources' ]
}
dependencies {
compile "com.soywiz:korge-common:$korVersion"
compile "com.soywiz:korge-ext-swf-common:$korVersion"
compile "com.soywiz:korge-ext-ui-common:$korVersion"
compile "com.soywiz:korau-mp3-common:$korVersion"
}

View File

@@ -0,0 +1 @@
rootProject.name = 'korge-simon-common'

View File

@@ -0,0 +1,135 @@
{
"frames": {
"0.png": {
"frame": {
"x": 2,
"y": 2,
"w": 32,
"h": 40
},
"rotated": false,
"sourceSize": {
"w": 32,
"h": 40
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 32,
"h": 40
},
"trimmed": false
},
"1.png": {
"frame": {
"x": 2,
"y": 42,
"w": 32,
"h": 40
},
"rotated": false,
"sourceSize": {
"w": 32,
"h": 40
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 32,
"h": 40
},
"trimmed": false
},
"2.png": {
"frame": {
"x": 2,
"y": 82,
"w": 32,
"h": 40
},
"rotated": false,
"sourceSize": {
"w": 32,
"h": 40
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 32,
"h": 40
},
"trimmed": false
},
"3.png": {
"frame": {
"x": 2,
"y": 122,
"w": 32,
"h": 40
},
"rotated": false,
"sourceSize": {
"w": 32,
"h": 40
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 32,
"h": 40
},
"trimmed": false
},
"4.png": {
"frame": {
"x": 2,
"y": 162,
"w": 32,
"h": 40
},
"rotated": false,
"sourceSize": {
"w": 32,
"h": 40
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 32,
"h": 40
},
"trimmed": false
},
"5.png": {
"frame": {
"x": 2,
"y": 202,
"w": 32,
"h": 40
},
"rotated": false,
"sourceSize": {
"w": 32,
"h": 40
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 32,
"h": 40
},
"trimmed": false
}
},
"meta": {
"app": "korge",
"format": "RGBA8888",
"image": "kotlin.atlas.png",
"scale": 1.0,
"size": {
"w": 32,
"h": 240
},
"version": "0.10.0"
}
}

View File

@@ -0,0 +1 @@
{"name":"kotlin.atlas","loaderVersion":0,"sha1":"f096d009db1e83bdd171bdd91f830bcb32e2be70","configSha1":""}

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

View File

@@ -5,26 +5,32 @@ import com.soywiz.korge.atlas.Atlas
import com.soywiz.korge.audio.SoundFile
import com.soywiz.korge.audio.SoundSystem
import com.soywiz.korge.audio.readSoundFile
import com.soywiz.korge.html.Html
import com.soywiz.korge.input.mouse
import com.soywiz.korge.plugin.KorgePlugin
import com.soywiz.korge.resources.Path
import com.soywiz.korge.resources.getPath
import com.soywiz.korge.scene.Module
import com.soywiz.korge.scene.ScaledScene
import com.soywiz.korge.scene.Scene
import com.soywiz.korge.scene.sleep
import com.soywiz.korge.time.seconds
import com.soywiz.korge.ui.UIFactory
import com.soywiz.korge.ui.UIPlugin
import com.soywiz.korge.ui.korui.koruiFrame
import com.soywiz.korge.util.AutoClose
import com.soywiz.korge.view.*
import com.soywiz.korge.view.Container
import com.soywiz.korge.view.Image
import com.soywiz.korge.view.image
import com.soywiz.korim.color.Colors
import com.soywiz.korio.async.Signal
import com.soywiz.korio.async.go
import com.soywiz.korio.async.waitOne
import com.soywiz.korio.inject.AsyncInjector
import com.soywiz.korio.inject.Optional
import com.soywiz.korio.util.substr
import com.soywiz.korio.lang.JvmStatic
import com.soywiz.korma.geom.ISize
import com.soywiz.korma.geom.SizeInt
import com.soywiz.korma.random.MtRand
import com.soywiz.korma.random.get
import com.soywiz.korui.geom.len.Padding
import com.soywiz.korui.geom.len.em
@@ -32,29 +38,38 @@ import com.soywiz.korui.style.padding
import com.soywiz.korui.ui.button
import com.soywiz.korui.ui.click
import com.soywiz.korui.ui.horizontal
import java.util.*
object Simon : Module() {
@JvmStatic fun main(args: Array<String>) = Korge(this)
@JvmStatic
fun main(args: Array<String>) = Korge(this, injector = AsyncInjector()
.mapPrototype { SelectLevelScene(getPath("kotlin.atlas"), get()) }
.mapPrototype {
IngameScene(
getPath(Atlas::class, "kotlin.atlas"),
getPath(SoundFile::class, "sounds/success.wav"),
getPath(SoundFile::class, "sounds/fail.mp3"),
getOrNull(),
get()
)
}
)
override val size: SizeInt = SizeInt(1280, 720)
override val windowSize: SizeInt = size * 0.75
override val title: String = "Kotlin Simon"
override val icon: String = "kotlin/0.png"
//override val mainScene: Class<out Scene> = MainScene::class.java
override val mainScene: Class<out Scene> = SelectLevelScene::class.java
override val size = SizeInt(1280, 720)
override val windowSize = size * 0.75
override val title = "Kotlin Simon"
override val icon = "kotlin/0.png"
override val mainScene = SelectLevelScene::class
override val plugins: List<KorgePlugin> = super.plugins + listOf(UIPlugin)
class Sequence(
val max: Int,
val random: Random = Random()
val random: MtRand = MtRand()
) {
val items = arrayListOf<Int>()
val items = ArrayList<Int>()
fun ensure(num: Int): List<Int> {
while (items.size < num) items += random[0, max]
while (items.size < num) items.add(random[0, max])
return items
}
}

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 335 B

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,17 @@
apply plugin: 'kotlin-platform-jvm'
apply plugin: 'application'
mainClassName = 'com.soywiz.korge.samples.simon.Simon'
sourceSets {
main.resources.srcDirs = [ '../common/src/main/resources', '../common/src/generated/resources' ]
}
dependencies {
implement project(":korge-simon:common")
compile "com.soywiz:korge:$korVersion"
compile "com.soywiz:korge-ext-swf:$korVersion"
compile "com.soywiz:korge-ext-ui:$korVersion"
compile "com.soywiz:korau-mp3:$korVersion"
}

View File

@@ -0,0 +1 @@
rootProject.name = 'korge-simon'

View File

@@ -2,6 +2,7 @@ package com.soywiz.korge.tictactoe
import com.soywiz.korge.animate.play
import com.soywiz.korge.input.onClick
import com.soywiz.korge.input.onUp
import com.soywiz.korge.time.milliseconds
import com.soywiz.korge.tween.*
import com.soywiz.korge.view.View
@@ -86,7 +87,7 @@ suspend fun Board.reset() {
fun Board.Cell.init(view: View) {
this.view = view
set(this.value)
view["hit"].onClick {
view["hit"].onUp {
onPress(Unit)
}
}

View File

@@ -1,64 +0,0 @@
package com.soywiz.korge.tictactoe
import com.soywiz.korio.util.Extra
import com.soywiz.korma.ds.Array2
import com.soywiz.korma.geom.PointInt
import kotlin.collections.ArrayList
enum class Chip { EMPTY, CROSS, CIRCLE }
class Board(val width: Int = 3, val height: Int = width, val lineSize: Int = width) {
class Cell(val x: Int, val y: Int) : Extra by Extra.Mixin() {
val pos = PointInt(x, y)
var value = Chip.EMPTY
}
val cells = Array2(width, height) { Cell(it % width, it / width) }
fun inside(x: Int, y: Int) = cells.inside(x, y)
fun select(x: Int, y: Int, dx: Int, dy: Int, size: Int): List<Cell>? {
if (!inside(x, y)) return null
if (!inside(x + dx * (size - 1), y + dy * (size - 1))) return null
return (0 until size).map { cells[x + dx * it, y + dy * it] }
}
val lines = kotlin.collections.ArrayList<List<Cell>>()
init {
fun addLine(line: List<Cell>?) {
if (line != null) lines += line
}
for (y in 0..height) {
for (x in 0..width) {
addLine(select(x, y, 1, 0, lineSize))
addLine(select(x, y, 0, 1, lineSize))
addLine(select(x, y, 1, 1, lineSize))
addLine(select(width - x - 1, y, -1, 1, lineSize))
}
}
}
operator fun get(x: Int, y: Int) = cells[x, y]
operator fun set(x: Int, y: Int, value: Chip) = run { cells[x, y].value = value }
val Iterable<Cell>.chipLine: Chip?
get() {
val expected = this.first().value
return if (expected == Chip.EMPTY) null else if (this.all { it.value == expected }) expected else null
}
val moreMovements: Boolean get() = cells.any { it.value == Chip.EMPTY }
val winnerLine: List<Cell>?
get() {
val out = kotlin.collections.ArrayList<Cell>()
for (line in lines) if (line.chipLine != null) out += line
return if (out.isEmpty()) null else out.toSet().toList()
}
val winner: Chip?
get() {
return winnerLine?.firstOrNull()?.value
}
}

View File

@@ -1,92 +0,0 @@
package com.soywiz.korge.tictactoe
import com.soywiz.korge.animate.play
import com.soywiz.korge.input.onClick
import com.soywiz.korge.time.milliseconds
import com.soywiz.korge.tween.*
import com.soywiz.korge.view.View
import com.soywiz.korge.view.get
import com.soywiz.korio.async.Signal
import com.soywiz.korio.async.async
import com.soywiz.korio.util.Extra
var Board.Cell.view by Extra.Property<View?> { null }
val Board.Cell.vview: View get() = this.view!!
val Board.Cell.onPress by Extra.Property { Signal<Unit>() }
fun Board.Cell.set(type: Chip) {
this.value = type
view["chip"].play(when (type) {
Chip.EMPTY -> "empty"
Chip.CIRCLE -> "circle"
Chip.CROSS -> "cross"
})
}
suspend fun Board.Cell.setAnimate(type: Chip) {
set(type)
async {
view.tween(
(view["chip"]!!::alpha[0.7, 1.0]).linear(),
(view["chip"]!!::scale[0.8, 1.0]).easeOutElastic(),
time = 300.milliseconds
)
}
}
var Board.Cell.highlighting by Extra.Property { false }
suspend fun Board.Cell.highlight(highlight: Boolean) {
view["highlight"].play(if (highlight) "highlight" else "none")
this.highlighting = highlight
if (highlight) {
async {
val hl = view["highlight"]!!
while (highlighting) {
hl.tween((hl::alpha[0.7]).easeInOutQuad(), time = 300.milliseconds)
hl.tween((hl::alpha[1.0]).easeInOutQuad(), time = 200.milliseconds)
}
}
async {
val ch = view["chip"]!!
ch.tween((ch::scale[0.4]).easeOutQuad(), time = 100.milliseconds)
ch.tween((ch::scale[1.2]).easeOutElastic(), time = 300.milliseconds)
while (highlighting) {
ch.tween((ch::scale[1.0]).easeOutQuad(), time = 300.milliseconds)
ch.tween((ch::scale[1.2]).easeOutElastic(), time = 300.milliseconds)
}
}
}
}
suspend fun Board.Cell.lowlight(lowlight: Boolean) {
async {
view.tween(
view!!::scale[1.0, 0.7],
view!!::alpha[0.3],
time = 300.milliseconds, easing = Easings.EASE_OUT_QUAD
)
}
}
suspend fun Board.reset() {
for (cell in cells) {
//cell.view?.removeAllComponents()
cell.set(Chip.EMPTY)
cell.highlight(false)
cell.view?.scale = 1.0
cell.view?.alpha = 1.0
cell.view["chip"]?.scale = 1.0
cell.view["chip"]?.alpha = 1.0
}
}
fun Board.Cell.init(view: View) {
this.view = view
set(this.value)
view["hit"].onClick {
onPress(Unit)
}
}

View File

@@ -1,10 +0,0 @@
package com.soywiz.korge.tictactoe
import com.soywiz.korge.animate.AnLibrary
import com.soywiz.korge.resources.getPath
import com.soywiz.korio.inject.AsyncInjector
// AUTOGENERATED:
fun AsyncInjector.generatedInject() = this
//.mapPrototype { TicTacToeMainScene(getPath("main.ani")) } // @TODO: kotlin.js bug
.mapPrototype { TicTacToeMainScene(getPath(AnLibrary::class, "main.ani")) }

View File

@@ -1,146 +0,0 @@
package com.soywiz.korge.tictactoe
import com.soywiz.korge.Korge
import com.soywiz.korge.animate.AnLibrary
import com.soywiz.korge.animate.AnLibraryPlugin
import com.soywiz.korge.input.mouse
import com.soywiz.korge.plugin.KorgePlugin
import com.soywiz.korge.resources.Path
import com.soywiz.korge.scene.Module
import com.soywiz.korge.scene.Scene
import com.soywiz.korge.view.Container
import com.soywiz.korge.view.descendantsWithPropInt
import com.soywiz.korge.view.get
import com.soywiz.korge.view.setText
import com.soywiz.korio.async.Signal
import com.soywiz.korio.async.go
import com.soywiz.korio.async.waitOne
import com.soywiz.korio.error.invalidOp
import com.soywiz.korio.inject.AsyncInjector
import com.soywiz.korio.lang.JvmStatic
import com.soywiz.korma.geom.PointInt
object TicTacToe {
@JvmStatic
fun main(args: Array<String>) = Korge(TicTacToeModule, injector = AsyncInjector().generatedInject())
}
object TicTacToeModule : Module() {
override val mainScene = TicTacToeMainScene::class
override val title: String = "tic-tac-toe"
override val icon: String = "icon.png"
override val plugins: List<KorgePlugin> = super.plugins + listOf(
AnLibraryPlugin
)
suspend override fun init(injector: AsyncInjector) {
//injector.get<ResourcesRoot>().mapExtensions("swf" to "ani")
//injector.get<ResourcesRoot>().mapExtensionsJustInJTransc("swf" to "ani")
}
}
// Controller
class TicTacToeMainScene(
@Path("main.ani") val mainLibrary: AnLibrary
) : Scene() {
val board = Board(3, 3)
lateinit var game: Game
suspend override fun sceneInit(sceneView: Container) {
sceneView += mainLibrary.createMainTimeLine()
for ((rowView, row) in sceneView.descendantsWithPropInt("row")) {
for ((cellView, cell) in rowView.descendantsWithPropInt("cell")) {
board.cells[row, cell].init(cellView)
}
}
val p1 = InteractivePlayer(board, Chip.CROSS)
val p2 = BotPlayer(board, Chip.CIRCLE)
//val p2 = InteractivePlayer(board, Chip.CIRCLE)
game = Game(board, listOf(p1, p2))
cancellables += go {
while (true) {
game.board.reset()
val result = game.game()
println(result)
val results = mainLibrary.createMovieClip("Results")
//(results["result"] as AnTextField).format?.face = Html.FontFace.Bitmap(font)
when (result) {
is Game.Result.DRAW -> results["result"].setText("DRAW")
is Game.Result.WIN -> {
results["result"].setText("WIN")
for (cell in result.cells) cell.highlight(true)
for (cell in game.board.cells.toList() - result.cells) cell.lowlight(true)
}
}
sceneView += results
results["hit"]?.mouse?.onClick?.waitOne()
//sceneView -= results
results.removeFromParent()
}
}
}
}
interface Player {
val chip: Chip
suspend fun move(): PointInt
}
class Game(val board: Board, val players: List<Player>) {
interface Result {
object DRAW : Result
class WIN(val player: Player?, val cells: List<Board.Cell>) : Result
}
suspend fun game(): Result {
var turn = 0
while (board.moreMovements) {
val currentPlayer = players[turn % players.size]
while (true) {
val pos = currentPlayer.move()
println(pos)
if (board.cells[pos].value == Chip.EMPTY) {
board.cells[pos].setAnimate(currentPlayer.chip)
break
}
}
if (board.winner != null) return Result.WIN(currentPlayer, board.winnerLine ?: listOf())
turn++
}
return Result.DRAW
}
}
class BotPlayer(val board: Board, override val chip: Chip) : Player {
suspend override fun move(): PointInt {
for (cell in board.cells) {
if (cell.value == Chip.EMPTY) {
return cell.pos
}
}
invalidOp("No more movements")
}
}
class InteractivePlayer(val board: Board, override val chip: Chip) : Player {
val clicked = Signal<PointInt>()
init {
for (cell in board.cells) {
cell.onPress {
clicked(cell.pos)
}
}
}
suspend override fun move(): PointInt {
return clicked.waitOne()
}
}

View File

@@ -5,6 +5,10 @@ include(
'korge-tic-tac-toe:js',
'korge-tic-tac-toe:jvm',
'korge-simon:common',
'korge-simon:js',
'korge-simon:jvm',
//'korge-coffee',
//'korge-simon',
)