Skip to content

Commit

Permalink
Merge pull request #2 from Ekenstein/classic_theme
Browse files Browse the repository at this point in the history
Added classic theme
  • Loading branch information
Ekenstein authored May 1, 2023
2 parents da9d564 + 6c5dd97 commit a51f55f
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 45 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ The animated GIF is highly inspired by the classic game Hayauchi Super Igo for N

```shell
Usage: sgf2gif options_list
Options:
--file, -f -> The SGF-file to convert to a GIF (always required)
--output, -o -> The destination file to write the GIF to. (always required)
--theme [NES] -> The theme to render the board with { Value should be one of [nes] }
--loop, -l [false] -> Whether the animation should be looped or not
Options:
--file, -f -> The SGF-file to convert to a GIF (always required)
--output, -o -> The destination file to write the GIF to. (Optional)
--theme [NES] -> The theme to render the board with { Value should be one of [nes, classic] }
--loop, -l [false] -> Whether the animation should be looped or not
--width, -w [1000] -> The width of the image. { Int }
--height, -h [1000] -> The height of the image. { Int }
--move-number, -mn [2147483647] -> The move number up to which the animation will run to. { Int }
Expand All @@ -22,3 +22,9 @@ Options:
java -jar sgf2gif.jar -f ~/game.sgf -o ~/game.gif --theme nes
```
![](https://github.com/Ekenstein/sgf2gif/blob/main/nes.gif?raw=true)
### Classic theme
```shell
java -jar sgf2gif.jar -f ~/game.sgf -o ~/game.gif --theme classic
```
![](https://github.com/Ekenstein/sgf2gif/blob/main/classic.gif?raw=true)
40 changes: 28 additions & 12 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ application {

plugins {
application
kotlin("jvm") version "1.7.10"
id("org.jlleitschuh.gradle.ktlint") version "10.3.0"
id("com.github.ben-manes.versions") version "0.42.0"
id("com.github.johnrengelman.shadow") version "7.1.2"
kotlin("jvm") version "1.8.21"
id("org.jlleitschuh.gradle.ktlint") version "11.3.2"
id("com.github.ben-manes.versions") version "0.46.0"
id("com.github.johnrengelman.shadow") version "8.1.1"
}

group = "com.github.ekenstein"
version = "0.3.2"
version = "0.4.0"

repositories {
mavenCentral()
Expand All @@ -29,8 +29,8 @@ repositories {
}

dependencies {
implementation("com.github.Ekenstein", "haengma", "2.2.4")
implementation("org.jetbrains.kotlinx", "kotlinx-cli", "0.3.4")
implementation("com.github.Ekenstein", "haengma", "2.2.6")
implementation("org.jetbrains.kotlinx", "kotlinx-cli", "0.3.5")
testImplementation(kotlin("test"))
}

Expand Down Expand Up @@ -79,6 +79,10 @@ tasks {
dependsOn(dependencyUpdateSentinel)
}

withType<JavaCompile> {
targetCompatibility = "1.8"
}

withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
Expand All @@ -89,26 +93,38 @@ ktlint {
}

class UpgradeToUnstableFilter : ComponentFilter {
override fun reject(cs: ComponentSelectionWithCurrent) = reject(cs.currentVersion, cs.candidate.version)
override fun reject(candidate: ComponentSelectionWithCurrent) = reject(
candidate.currentVersion,
candidate.candidate.version
)

private fun reject(old: String, new: String): Boolean {
return !isStable(new) && isStable(old) // no unstable proposals for stable dependencies
}

private fun isStable(version: String): Boolean {
val stableKeyword = setOf("RELEASE", "FINAL", "GA").any { version.toUpperCase().contains(it) }
val stableKeyword = setOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) }
val stablePattern = version.matches(Regex("""^[0-9,.v-]+(-r)?$"""))
return stableKeyword || stablePattern
}
}

class IgnoredDependencyFilter : ComponentFilter {
private val ignoredDependencies = mapOf(
"ktlint" to listOf("0.46.0", "0.46.1") // doesn't currently work.
"ktlint" to listOf(
"0.46.0",
"0.46.1",
"0.47.0",
"0.47.1",
"0.48.0",
"0.48.1",
"0.48.2",
"0.49.0"
) // doesn't currently work.
)

override fun reject(p0: ComponentSelectionWithCurrent): Boolean {
return ignoredDependencies[p0.candidate.module].orEmpty().contains(p0.candidate.version)
override fun reject(candidate: ComponentSelectionWithCurrent): Boolean {
return ignoredDependencies[candidate.candidate.module].orEmpty().contains(candidate.candidate.version)
}
}

Expand Down
Binary file added classic.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified dist/lib/sgf2gif.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-rc-3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import kotlin.time.Duration

data class Stone(val point: SgfPoint, val color: SgfColor)

interface BoardRenderer {
interface BoardTheme {
fun drawEmptyBoard(g: Graphics2D)
fun drawStone(g: Graphics2D, stone: Stone)
fun clearPoint(g: Graphics2D, x: Int, y: Int)
}

fun BoardRenderer.render(
fun BoardTheme.render(
outputStream: ImageOutputStream,
editor: SgfEditor,
width: Int,
Expand Down
28 changes: 20 additions & 8 deletions src/main/kotlin/com/github/ekenstein/sgf2gif/Main.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.github.ekenstein.sgf2gif

import com.github.ekenstein.sgf.editor.SgfEditor
import com.github.ekenstein.sgf.editor.goToLastNode
import com.github.ekenstein.sgf.editor.goToNextMove
import com.github.ekenstein.sgf.editor.stay
import com.github.ekenstein.sgf.editor.tryRepeat
import com.github.ekenstein.sgf.editor.*
import com.github.ekenstein.sgf.utils.get
import com.github.ekenstein.sgf.utils.orElse
import com.github.ekenstein.sgf2gif.themes.Classic
import com.github.ekenstein.sgf2gif.themes.Nes
import kotlinx.cli.ArgParser
import java.io.File
import java.nio.file.Paths
import java.text.NumberFormat
import javax.imageio.stream.FileImageOutputStream
import kotlin.time.Duration.Companion.seconds
Expand All @@ -21,22 +20,35 @@ fun main(args: Array<String>) {
val options = Options(parser)
parser.parse(args)

val editor = SgfEditor(options.sgf)
val (inputFile, sgf) = options.sgf

val editor = SgfEditor(sgf)
.tryRepeat(options.moveNumber) { it.goToNextMove() }
.orElse { it.goToLastNode().stay() }
.get()

val (boardWidth, boardHeight) = editor.boardSize()
val outputFile = options.output.toFile()
val outputFile = options.output?.toFile()
?: createOutputFile(inputFile.nameWithoutExtension)

FileImageOutputStream(outputFile).use { outputStream ->
val renderer = when (options.theme) {
Theme.NES -> Nes(options.width, options.height, boardWidth, boardHeight)
Theme.Classic -> Classic(options.width, options.height, boardWidth, boardHeight)
}

renderer.render(outputStream, editor, options.width, options.height, options.delay.seconds, options.loop) {
print("\r${percentageFormat.format(it)}")
}
}

println("\nExported the SGF to ${options.output}")
println("\nExported the SGF to ${outputFile.absolutePath}")
}

private fun createOutputFile(fileName: String): File {
val currentWorkingDirectory = System.getProperty("user.dir")
val fileNameWithGifExtension = "$fileName.gif"
val filePath = Paths.get(currentWorkingDirectory, fileNameWithGifExtension)

return filePath.toFile()
}
30 changes: 16 additions & 14 deletions src/main/kotlin/com/github/ekenstein/sgf2gif/Options.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import kotlinx.cli.ArgType
import kotlinx.cli.ParsingException
import kotlinx.cli.default
import kotlinx.cli.required
import java.io.File
import java.nio.file.InvalidPathException
import java.nio.file.Path
import kotlin.io.path.exists
Expand All @@ -23,10 +24,10 @@ class Options(parser: ArgParser) {

val output by parser.option(
type = PathArgType(),
description = "The destination file to write the GIF to.",
description = "The destination file to write the GIF to. (Optional)",
shortName = "o",
fullName = "output"
).required()
)

val theme by parser.option(
type = ArgType.Choice<Theme>(),
Expand Down Expand Up @@ -83,25 +84,26 @@ private class PathArgType : ArgType<Path>(true) {
}
}

private class SgfArgType : ArgType<SgfGameTree>(true) {
private class SgfArgType : ArgType<Pair<File, SgfGameTree>>(true) {
override val description: kotlin.String
get() = ""

override fun convert(value: kotlin.String, name: kotlin.String): SgfGameTree {
val path = try {
Path.of(value)
} catch (ex: InvalidPathException) {
throw ParsingException("Option $name is expected to be a path. $value is provided.")
}
override fun convert(value: kotlin.String, name: kotlin.String): Pair<File, SgfGameTree> {
val file = File(value)

if (!path.exists()) {
throw ParsingException("Option $name is expected to exist. The path was $path")
if (!file.exists()) {
throw ParsingException("Option $name is expected to exist. The path was $value")
}

return try {
SgfCollection.from(path) {
ignoreMalformedProperties = true
}.trees.head
val collection = file.inputStream().use { inputStream ->
SgfCollection.from(inputStream) {
ignoreMalformedProperties = true
}
}

val tree = collection.trees.head
file to tree
} catch (ex: SgfException.ParseError) {
throw ParsingException("Option $name is expected to be a valid SGF file.")
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/com/github/ekenstein/sgf2gif/Theme.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.ekenstein.sgf2gif

enum class Theme {
NES
NES,
Classic,
}
Loading

0 comments on commit a51f55f

Please sign in to comment.