diff --git a/kotlin-native/samples/README.md b/kotlin-native/samples/README.md index 4fd6a3dfb58..551092059f1 100644 --- a/kotlin-native/samples/README.md +++ b/kotlin-native/samples/README.md @@ -13,8 +13,6 @@ More Kotlin Multiplatform Mobile samples can be found here: https://kotlinlang.o The samples that are in this directory mostly illustrate the other use cases for Kotlin/Native: * `csvparser` - simple CSV file parser and analyzer * `echoServer` - TCP/IP echo server - * `gitchurn` - program interoperating with `libgit2` for GIT repository analysis - * `gtk` - GTK3 interoperability example * `html5Canvas` - WebAssembly example * `libcurl` - using of FTP/HTTP/HTTPS client library `libcurl` * `nonBlockingEchoServer` - multi-client TCP/IP echo server using co-routines @@ -22,7 +20,6 @@ The samples that are in this directory mostly illustrate the other use cases for * `opengl` - OpenGL/GLUT teapot example * `python_extension` - Python extension written in Kotlin/Native * `tensorflow` - simple client for TensorFlow Machine Intelligence library - * `tetris` - Tetris game implementation (using SDL2 for rendering) * `uikit` - UIKit Objective-C interoperability example for iOS * `videoplayer` - SDL and FFMPEG-based video and audio player * `win32` - trivial Win32 GUI application diff --git a/kotlin-native/samples/gitchurn/README.md b/kotlin-native/samples/gitchurn/README.md deleted file mode 100644 index c17c130ecc5..00000000000 --- a/kotlin-native/samples/gitchurn/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# GIT frequency analyzer - -This example shows how one could perform statistics on Git repository. - -Install libgit2 development files. -For Debian-like Linux - use `apt-get install libgit2-dev`. -For Windows - `pacman -S mingw-w64-x86_64-libgit2` in MinGW64 console, if you do -not have MSYS2-MinGW64 installed - install it first as described in http://www.msys2.org - -To build use `../gradlew assemble`. - -To run use `../gradlew runReleaseExecutableGitChurn` or execute the program directly: - - ./build/bin/gitChurn/main/release/executable/gitchurn.kexe ../../ - -It will print most frequently modified (by number of commits) files in repository. diff --git a/kotlin-native/samples/gitchurn/build.gradle.kts b/kotlin-native/samples/gitchurn/build.gradle.kts deleted file mode 100644 index 825991898b3..00000000000 --- a/kotlin-native/samples/gitchurn/build.gradle.kts +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - kotlin("multiplatform") -} - -val mingwPath = File(System.getenv("MINGW64_DIR") ?: "C:/msys64/mingw64") - -kotlin { - // Determine host preset. - val hostOs = System.getProperty("os.name") - val isMingwX64 = hostOs.startsWith("Windows") - - // Create a target for the host platform. - val hostTarget = when { - hostOs == "Mac OS X" -> macosX64("gitChurn") - hostOs == "Linux" -> linuxX64("gitChurn") - isMingwX64 -> mingwX64("gitChurn") - else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.") - } - - hostTarget.apply { - binaries { - executable { - entryPoint = "sample.gitchurn.main" - if (isMingwX64) { - linkerOpts("-L${mingwPath.resolve("lib")}") - runTask?.environment("PATH" to mingwPath.resolve("bin")) - } - runTask?.args(rootProject.rootDir.resolve("..")) - } - } - compilations["main"].cinterops { - val libgit2 by creating { - when (preset) { - presets["macosX64"] -> includeDirs.headerFilterOnly("/opt/local/include", "/usr/local/include") - presets["linuxX64"] -> includeDirs.headerFilterOnly("/usr/include") - presets["mingwX64"] -> includeDirs.headerFilterOnly(mingwPath.resolve("include")) - } - } - } - } -} diff --git a/kotlin-native/samples/gitchurn/gradle.properties b/kotlin-native/samples/gitchurn/gradle.properties deleted file mode 100644 index 790a07d5124..00000000000 --- a/kotlin-native/samples/gitchurn/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt deleted file mode 100644 index 60410ba4148..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.git_time_t -import platform.posix.ctime -import platform.posix.time_tVar - -fun main(args: Array) { - if (args.isEmpty()) - return help() - - val workDir = args[0] - - val limit = if (args.size > 1) { - val limitRaw = args[1].toIntOrNull() - if (limitRaw == null || limitRaw <= 0) { - return help("Not a positive integer: $limitRaw") - } - limitRaw - } else - Int.MAX_VALUE - - try { - calculateChurn(workDir, limit) - } catch (e: GitException) { - help(e.message) - } -} - -private fun calculateChurn(workDir: String, limit: Int) { - println("Opening…") - val repository = git.repository(workDir) - val map = mutableMapOf() - var count = 0 - val commits = repository.commits() - val limited = commits.take(limit) - println("Calculating…") - limited.forEach { commit -> - if (count % 100 == 0) - println("Commit #$count [${commit.time.format()}]: ${commit.summary}") - - commit.parents.forEach { parent -> - val diff = commit.tree.diff(parent.tree) - diff.deltas().forEach { delta -> - val path = delta.newPath - val n = map[path] ?: 0 - map.put(path, n + 1) - } - diff.close() - parent.close() - } - commit.close() - count++ - } - println("Report:") - map.toList().sortedByDescending { it.second }.take(10).forEach { - println("File: ${it.first}") - println(" ${it.second}") - println() - } - - repository.close() - git.close() -} - -private fun git_time_t.format() = memScoped { - val commitTime = alloc() - commitTime.value = this@format - ctime(commitTime.ptr)!!.toKString().trim() -} - - -private fun printTree(commit: GitCommit) { - commit.tree.entries().forEach { entry -> - when (entry) { - is GitTreeEntry.File -> println(" ${entry.name}") - is GitTreeEntry.Folder -> println(" /${entry.name} (${entry.subtree.entries().size})") - } - } -} - -private fun help(errorMessage: String? = null) { - errorMessage?.let { - println("ERROR: $it") - } - println("./gitchurn.kexe []") -} diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt deleted file mode 100644 index 7b12183345f..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitCommit(val repository: GitRepository, val commit: CPointer) { - fun close() = git_commit_free(commit) - - val summary: String get() = git_commit_summary(commit)!!.toKString() - val time: git_time_t get() = git_commit_time(commit) - - val tree: GitTree get() = memScoped { - val treePtr = allocPointerTo() - git_commit_tree(treePtr.ptr, commit).errorCheck() - GitTree(repository, treePtr.value!!) - } - - val parents: List get() = memScoped { - val count = git_commit_parentcount(commit).toInt() - val result = ArrayList(count) - for (index in 0..count - 1) { - val commitPtr = allocPointerTo() - git_commit_parent(commitPtr.ptr, commit, index.toUInt()).errorCheck() - result.add(GitCommit(repository, commitPtr.value!!)) - } - result - } -} \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt deleted file mode 100644 index b5d73643422..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitDiff(val repository: GitRepository, val handle: CPointer) { - fun deltas(): List { - val size = git_diff_num_deltas(handle).toInt() - val results = ArrayList(size) - for (index in 0..size - 1) { - val delta = git_diff_get_delta(handle, index.convert()) - results.add(GifDiffDelta(this, delta!!)) - } - return results - } - - fun close() { - git_diff_free(handle) - } - -} - -class GifDiffDelta(val diff: GitDiff, val handle: CPointer) { - - val status get() = handle.pointed.status - val newPath get() = handle.pointed.new_file.path!!.toKString() - val oldPath get() = handle.pointed.old_file.path!!.toKString() - - fun status(): String { - return when (status) { - GIT_DELTA_ADDED -> "A" - GIT_DELTA_DELETED -> "D" - GIT_DELTA_MODIFIED -> "M" - GIT_DELTA_RENAMED -> "R" - GIT_DELTA_COPIED -> "C" - else -> throw Exception("Unsupported delta status $status") - } - } - -} diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt deleted file mode 100644 index 18a65ee8772..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitRemote(val repository: GitRepository, val handle: CPointer) { - fun close() = git_remote_free(handle) - - val url: String get() = git_remote_url(handle)!!.toKString() - val name: String = git_remote_name(handle)!!.toKString() -} \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt deleted file mode 100644 index b10f23d37f6..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitRepository(val location: String) { - val arena = Arena() - val handle: CPointer = memScoped { - val loc = allocPointerTo() - git_repository_open(loc.ptr, location).errorCheck() - loc.value!! - } - - fun close() { - git_repository_free(handle) - arena.clear() - } - - fun remotes(): List = memScoped { - val remoteList = alloc() - git_remote_list(remoteList.ptr, handle).errorCheck() - val size = remoteList.count.toInt() - val list = ArrayList(size) - for (index in 0..size - 1) { - val array = remoteList.strings!! - val name = array[index]!!.toKString() - val remotePtr = allocPointerTo() - git_remote_lookup(remotePtr.ptr, handle, name).errorCheck() - list.add(GitRemote(this@GitRepository, remotePtr.value!!)) - } - list - } - - fun commits(): Sequence = memScoped { - val walkPtr = allocPointerTo() - git_revwalk_new(walkPtr.ptr, handle).errorCheck() - val walk = walkPtr.value - git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL or GIT_SORT_TIME) - git_revwalk_push_head(walk).errorCheck() - generateSequence { - memScoped { - val oid = alloc() - val result = git_revwalk_next(oid.ptr, walk) - - when (result) { - 0 -> { - val commitPtr = allocPointerTo() - git_commit_lookup(commitPtr.ptr, handle, oid.ptr).errorCheck() - val commit = commitPtr.value!! - GitCommit(this@GitRepository, commit) - } - GIT_ITEROVER -> null - else -> throw Exception("Unexpected result code $result") - } - } - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt deleted file mode 100644 index 03d78325939..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitTree(val repository: GitRepository, val handle: CPointer) { - fun close() = git_tree_free(handle) - - fun entries(): List = memScoped { - val size = git_tree_entrycount(handle).toInt() - val entries = ArrayList(size) - for (index in 0..size - 1) { - val treeEntry = git_tree_entry_byindex(handle, index.convert())!! - val entryType = git_tree_entry_type(treeEntry) - val entry = when (entryType) { - GIT_OBJ_TREE -> memScoped { - val id = git_tree_entry_id(treeEntry) - val treePtr = allocPointerTo() - git_tree_lookup(treePtr.ptr, repository.handle, id) - GitTreeEntry.Folder(this@GitTree, treeEntry, treePtr.value!!) - } - GIT_OBJ_BLOB -> GitTreeEntry.File(this@GitTree, treeEntry) - else -> throw Exception("Unsupported entry type $entryType") - } - entries.add(entry) - } - entries - } - - fun diff(other: GitTree): GitDiff = memScoped { - val diffPtr = allocPointerTo() - git_diff_tree_to_tree(diffPtr.ptr, repository.handle, handle, other.handle, null).errorCheck() - GitDiff(repository, diffPtr.value!!) - } -} - -sealed class GitTreeEntry(val tree: GitTree, val handle: CPointer) { - val name: String get() = git_tree_entry_name(handle)!!.toKString() - - class Folder(tree: GitTree, handle: CPointer, val subtreeHandle: CPointer) : GitTreeEntry(tree, handle) { - val subtree = GitTree(tree.repository, subtreeHandle) - } - - class File(tree: GitTree, handle: CPointer) : GitTreeEntry(tree, handle) -} diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt deleted file mode 100644 index 5ecb1d6413c..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -object git { - init { - git_libgit2_init() - } - - fun close() { - git_libgit2_shutdown() - } - - fun repository(location: String): GitRepository { - return GitRepository(location) - } -} - -fun Int.errorCheck() { - if (this == 0) return - throw GitException() -} - -class GitException : Exception(run { - val err = giterr_last() - err!!.pointed.message!!.toKString() -}) \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def b/kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def deleted file mode 100644 index 377332016f4..00000000000 --- a/kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def +++ /dev/null @@ -1,5 +0,0 @@ -headers = git2.h -headerFilter = git2/** git2.h -linkerOpts.osx = -L/opt/local/lib -L/usr/local/lib -lgit2 -linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -lgit2 -linkerOpts.mingw = -lgit2 diff --git a/kotlin-native/samples/gtk/README.md b/kotlin-native/samples/gtk/README.md deleted file mode 100644 index c8817e84d38..00000000000 --- a/kotlin-native/samples/gtk/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# GTK application - -This example shows how one may use _Kotlin/Native_ to build GUI -applications with the GTK toolkit. - -To build use `../gradlew assemble`. - -Do not forget to install GTK3. See bellow. - -To run on Mac also install XQuartz X server (https://www.xquartz.org/), and then `../gradlew runReleaseExecutableGtk` or execute the program directly: - - ./build/bin/gtk/main/release/executable/gtk.kexe - -Dialog box with the button will be shown, and application will print message -and terminate on button click. - - -#### GTK3 Install - -on Mac use - - brew install gtk+3 - -or - - port install gtk3 - -on Debian flavours of Linux - - sudo apt-get install libgtk-3-dev - -on Fedora - - sudo dnf install gtk3-devel - -on Windows in MinGW64 console, if you do -not have MSYS2-MinGW64 installed - install it first as described in http://www.msys2.org - - pacman -S mingw-w64-x86_64-gtk3 - pacman -S mingw-w64-x86_64-harfbuzz diff --git a/kotlin-native/samples/gtk/build.gradle.kts b/kotlin-native/samples/gtk/build.gradle.kts deleted file mode 100644 index 4b5df719236..00000000000 --- a/kotlin-native/samples/gtk/build.gradle.kts +++ /dev/null @@ -1,70 +0,0 @@ -plugins { - kotlin("multiplatform") -} - -val mingwPath = File(System.getenv("MINGW64_DIR") ?: "C:/msys64/mingw64") - -kotlin { - // Determine host preset. - val hostOs = System.getProperty("os.name") - val isMingwX64 = hostOs.startsWith("Windows") - - // Create a target for the host platform. - val hostTarget = when { - hostOs == "Mac OS X" -> macosX64("gtk") - hostOs == "Linux" -> linuxX64("gtk") - isMingwX64 -> mingwX64("gtk") - else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.") - } - - hostTarget.apply { - binaries { - executable { - entryPoint = "sample.gtk.main" - if (isMingwX64) { - linkerOpts("-L${mingwPath.resolve("lib")}") - runTask?.environment("PATH" to mingwPath.resolve("bin")) - } - } - } - compilations["main"].cinterops { - val gtk3 by creating { - when (preset) { - presets["macosX64"], presets["linuxX64"] -> { - listOf("/opt/local/include", "/usr/include", "/usr/local/include").forEach { - includeDirs( - "$it/atk-1.0", - "$it/gdk-pixbuf-2.0", - "$it/cairo", - "$it/harfbuzz", - "$it/pango-1.0", - "$it/gtk-3.0", - "$it/glib-2.0" - ) - } - - includeDirs( - "/opt/local/lib/glib-2.0/include", - "/usr/lib/x86_64-linux-gnu/glib-2.0/include", - "/usr/local/lib/glib-2.0/include" - ) - } - presets["mingwX64"] -> { - listOf( - "include/atk-1.0", - "include/gdk-pixbuf-2.0", - "include/cairo", - "include/pango-1.0", - "include/gtk-3.0", - "include/glib-2.0", - "include/harfbuzz", - "lib/glib-2.0/include" - ).forEach { - includeDirs(mingwPath.resolve(it)) - } - } - } - } - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/gtk/gradle.properties b/kotlin-native/samples/gtk/gradle.properties deleted file mode 100644 index f833920c5d7..00000000000 --- a/kotlin-native/samples/gtk/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -kotlin.native.jvmArgs=-Xmx8g -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt b/kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt deleted file mode 100644 index c09de4f268a..00000000000 --- a/kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.gtk - -import kotlinx.cinterop.* -import gtk3.* - -// Note that all callback parameters must be primitive types or nullable C pointers. -fun > g_signal_connect(obj: CPointer<*>, actionName: String, - action: CPointer, data: gpointer? = null, connect_flags: GConnectFlags = 0u) { - g_signal_connect_data(obj.reinterpret(), actionName, action.reinterpret(), - data = data, destroy_data = null, connect_flags = connect_flags) - -} - -fun activate(app: CPointer?, user_data: gpointer?) { - val windowWidget = gtk_application_window_new(app)!! - val window = windowWidget.reinterpret() - gtk_window_set_title(window, "Window") - gtk_window_set_default_size(window, 200, 200) - - val button_box = gtk_button_box_new( - GtkOrientation.GTK_ORIENTATION_HORIZONTAL)!! - gtk_container_add(window.reinterpret(), button_box) - - val button = gtk_button_new_with_label("Konan говорит: click me!")!! - g_signal_connect(button, "clicked", - staticCFunction { _: CPointer?, _: gpointer? -> println("Hi Kotlin") - }) - g_signal_connect(button, "clicked", - staticCFunction { widget: CPointer? -> - gtk_widget_destroy(widget) - }, - window, G_CONNECT_SWAPPED) - gtk_container_add (button_box.reinterpret(), button) - - gtk_widget_show_all(windowWidget) -} - -fun gtkMain(args: Array): Int { - val app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE)!! - g_signal_connect(app, "activate", staticCFunction(::activate)) - val status = memScoped { - g_application_run(app.reinterpret(), - args.size, args.map { it.cstr.ptr }.toCValues()) - } - g_object_unref(app) - return status -} - -fun main(args: Array) { - gtkMain(args) -} diff --git a/kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def b/kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def deleted file mode 100644 index 51c5e6f6d23..00000000000 --- a/kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def +++ /dev/null @@ -1,9 +0,0 @@ -headers = gtk/gtk.h -headerFilter = gtk/* gobject/* gio/* -compilerOpts.osx = -I/usr/local/include/gtk-3.0 -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include \ --I/usr/local/include/pango-1.0 -I/usr/local/include/cairo -I/usr/local/include -I/usr/local/include/gdk-pixbuf-2.0 \ --I/usr/local/include/atk-1.0 -compilerOpts.linux = -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/local/lib/glib-2.0/include -I/usr/lib64/glib-2.0/include -linkerOpts.osx = -L/opt/local/lib -L/usr/local/lib -lglib-2.0 -lgdk-3.0 -lgtk-3 -lgio-2.0 -lgobject-2.0 -linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -lglib-2.0 -lgdk-3 -lgtk-3 -lgio-2.0 -lgobject-2.0 -linkerOpts.mingw = -lglib-2.0 -lgdk-3 -lgtk-3 -lgio-2.0 -lgobject-2.0 diff --git a/kotlin-native/samples/python_extension/README.md b/kotlin-native/samples/python_extension/README.md deleted file mode 100644 index 8ae6b7d5dc3..00000000000 --- a/kotlin-native/samples/python_extension/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# C to Kotlin/Native interoperability example - -This example shows how to use Kotlin/Native programs from other execution environments, such as Python. -Python has C native interface, which could be used to organize a bridge with the -Kotlin/Native application. File `kotlin_bridge.c` contains translation code between Kotlin and Python -lands. This demo works on Linux, Windows (64-bit) or macOS hosts. - -To build and run the sample do the following: - -* Install Python with development headers, i.e. on Linux - ``` - sudo apt install python-dev - ``` - -* Run `build.sh`, it will ask for superuser password to install Python extension. - Use build.bat on Windows. -* On macOS copy Kotlin binary to extension's directory and change install name with - `install_name_tool` tool, i.e. - ``` - sudo cp ./build/libserver.dylib /Library/Python/2.7/site-packages/ - sudo install_name_tool /Library/Python/2.7/site-packages/kotlin_bridge.so \ - -change libserver.dylib @loader_path/libserver.dylib - ``` -* On Linux copy Kotlin binary in some place where libraries could be loaded from, i.e. - ``` - cp ./build/libserver.so /usr/local/lib/ - ldconfig - ``` - or modify dynamic loader search path with - ``` - export LD_LIBRARY_PATH=`pwd` - ``` - -* run Python code using Kotlin functionality with - ``` - python src/main/python/main.py - ``` -* it will show you result of using several Kotlin/Native APIs, accepting and returning both objects and - primitive types - - The example works as following. Kotlin/Native API is implemented in `Server.kt`, and we run Kotlin/Native compiler - with `-produce dynamic` option. Compiler produces two artifacts: `server_api.h` which is C language API - to all public functions and classes available in the application. `libserver.dylib` or `libserver.so` or `server.dll` - shared object contains C bridge to all above APIs. - - This C bridge looks like a C struct, reflecting all scopes in program, with operations available. For example, - for class Server -```c_cpp - class Server(val prefix: String) { - fun greet(session: Session) = "$prefix: Hello from Kotlin/Native in ${session}" - fun concat(session: Session, a: String, b: String) = "$prefix: $a $b in ${session}" - fun add(session: Session, a: Int, b: Int) = a + b + session.number - } -``` - following C API is produced -```c_cpp - typedef struct { - server_KNativePtr pinned; - } server_kref_demo_Session; - typedef struct { - server_KNativePtr pinned; - } server_kref_demo_Server; - - typedef struct { - /* Service functions. */ - void (*DisposeStablePointer)(server_KNativePtr ptr); - void (*DisposeString)(const char* string); - server_KBoolean (*IsInstance)(server_KNativePtr ref, const server_KType* type); - - /* User functions. */ - struct { - struct { - struct { - server_KType* (*_type)(void); - server_kref_demo_Session (*Session)(const char* name, server_KInt number); - } Session; - struct { - server_KType* (*_type)(void); - server_kref_demo_Server (*Server)(const char* prefix); - const char* (*greet)(server_kref_demo_Server thiz, server_kref_demo_Session session); - const char* (*concat)(server_kref_demo_Server thiz, server_kref_demo_Session session, const char* a, const char* b); - server_KInt (*add)(server_kref_demo_Server thiz, server_kref_demo_Session session, server_KInt a, server_KInt b); - } Server; - } demo; - } kotlin; - } server_ExportedSymbols; - extern server_ExportedSymbols* server_symbols(void); -``` - - So every class instance is represented with a single element structure, encapsulating stable pointer to an instance. - Once no longer needed, `DisposeStablePointer()` with that stable pointer shall be called, and if value is not stored - somewhere else - it is disposed. For primitive types and `kotlin.String` smart bridges converting to C primitive types - or to C strings (which has to be manually freed with `DisposeString()`) are implemented. - - For example, running constructor of class Server taking a string will look like - - server_kref_demo_Server server = server_symbols()->kotlin.demo.Server.Server("the server"); - - And disposing no longer needed instance will look like - - server_symbols()->DisposeStablePointer(server.pinned); - - To make code easier readable, macro definitions like - - #define T_(name) server_kref_demo_ ## name - #define __ server_symbols()-> - - will transform above, overly verbose lines to more readable - - T_(Server) server = __ kotlin.demo.Server.Server("the server"); - - `_type()` function will return opaque type pointer, which could be checked with `IsInstance()` operation, like - - __ IsInstance(ref.pinned, __ kotlin.demo.Server._type()) diff --git a/kotlin-native/samples/python_extension/build.bat b/kotlin-native/samples/python_extension/build.bat deleted file mode 100644 index 2fcff0aa32c..00000000000 --- a/kotlin-native/samples/python_extension/build.bat +++ /dev/null @@ -1,15 +0,0 @@ -setlocal -set DIR=. - -if defined KONAN_HOME ( - set "PATH=%KONAN_HOME%\bin;%PATH%" -) else ( - set "PATH=..\..\dist\bin;..\..\bin;%PATH%" -) -kotlinc-native -p dynamic src/main/kotlin/Server.kt -o server - -rem Prepare MSVC build environment, and .lib file for linking with our .dll. -SET VS90COMNTOOLS=%VS140COMNTOOLS% -\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\lib.exe" /def:server.def /out:server.lib /machine:X64 - -python src/main/python/setup.py install diff --git a/kotlin-native/samples/python_extension/build.sh b/kotlin-native/samples/python_extension/build.sh deleted file mode 100755 index f091f2cda3d..00000000000 --- a/kotlin-native/samples/python_extension/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -DIR=$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd ) - -if [ -z "$KONAN_HOME" ]; then - PATH="$DIR/../../dist/bin:$DIR/../../bin:$PATH" -else - PATH="$KONAN_HOME/bin:$PATH" -fi - -KONAN_USER_DIR=${KONAN_DATA_DIR:-"$HOME/.konan"} -KONAN_DEPS="$KONAN_USER_DIR/dependencies" - -# python3 shall work as well. -PYTHON=python - -mkdir -p $DIR/build -cd $DIR/build - -kotlinc-native -p dynamic $DIR/src/main/kotlin/Server.kt -o server - -cd $DIR -sudo -S $PYTHON ${DIR}/src/main/python/setup.py install diff --git a/kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c b/kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c deleted file mode 100644 index d010e9ff6fd..00000000000 --- a/kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -#include - -#include "server_api.h" - -#define __ server_symbols()-> -#define T_(name) server_kref_demo_ ## name - -// Note, that as we cache this in the global, and Kotlin/Native object references -// are currently thread local, we make this global a TLS variable. -#ifdef _MSC_VER -#define TLSVAR __declspec(thread) -#else -#define TLSVAR __thread -#endif - -static TLSVAR server_kref_demo_Server server = { 0 }; - -static T_(Server) getServer(void) { - if (!server.pinned) { - server = __ kotlin.root.demo.Server.Server("the server"); - } - return server; -} - -static T_(Session) getSession(PyObject* args) { - T_(Session) result = { 0 }; - long long pinned; - if (PyArg_ParseTuple(args, "L", &pinned)) { - result.pinned = (void*)(uintptr_t)pinned; - } - return result; -} - -static PyObject* open_session(PyObject* self, PyObject* args) { - PyObject *result = NULL; - char* string_arg = NULL; - int int_arg = 0; - if (PyArg_ParseTuple(args, "is", &int_arg, &string_arg)) { - T_(Session) session = __ kotlin.root.demo.Session.Session(string_arg, int_arg); - result = Py_BuildValue("L", session.pinned); - } - return result; -} - -static PyObject* close_session(PyObject* self, PyObject* args) { - T_(Session) session = getSession(args); - __ DisposeStablePointer(session.pinned); - __ DisposeStablePointer(getServer().pinned); - server.pinned = 0; - return Py_BuildValue("L", 0); -} - -static PyObject* greet_server(PyObject* self, PyObject* args) { - T_(Server) server = getServer(); - T_(Session) session = getSession(args); - const char* string = __ kotlin.root.demo.Server.greet(server, session); - PyObject* result = Py_BuildValue("s", string); - __ DisposeString(string); - return result; -} - -static PyObject* concat_server(PyObject* self, PyObject* args) { - long long session_arg; - char* string_arg1 = NULL; - char* string_arg2 = NULL; - PyObject* result = NULL; - - if (PyArg_ParseTuple(args, "Lss", &session_arg, &string_arg1, &string_arg2)) { - T_(Server) server = getServer(); - T_(Session) session = { (void*)(uintptr_t)session_arg }; - const char* string = __ kotlin.root.demo.Server.concat(server, session, string_arg1, string_arg2); - result = Py_BuildValue("s", string); - __ DisposeString(string); - } else { - result = Py_BuildValue("s", NULL); - } - return result; -} - -static PyObject* add_server(PyObject* self, PyObject* args) { - long long session_arg; - int int_arg1 = 0; - int int_arg2 = 0; - PyObject* result = NULL; - - if (PyArg_ParseTuple(args, "Lii", &session_arg, &int_arg1, &int_arg2)) { - T_(Server) server = getServer(); - T_(Session) session = { (void*)(uintptr_t)session_arg }; - int sum = __ kotlin.root.demo.Server.add(server, session, int_arg1, int_arg2); - result = Py_BuildValue("i", sum); - } else { - result = Py_BuildValue("i", 0); - } - return result; -} - -static PyMethodDef kotlin_bridge_funcs[] = { - { "open_session", (PyCFunction)open_session, METH_VARARGS, "Opens a session" }, - { "close_session", (PyCFunction)close_session, METH_VARARGS, "Closes the session" }, - { "greet_server", (PyCFunction)greet_server, METH_VARARGS, "Greeting service" }, - { "concat_server", (PyCFunction)concat_server, METH_VARARGS, "Concatenation service" }, - { "add_server", (PyCFunction)add_server, METH_VARARGS, "Addition service" }, - { NULL } -}; - -#if PY_MAJOR_VERSION >= 3 - -struct module_state { - server_kref_demo_Server server; -}; - -static int kotlin_bridge_traverse(PyObject *m, visitproc visit, void *arg) { - return 0; -} - -static int kotlin_bridge_clear(PyObject *m) { - return 0; -} - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "kotlin_bridge", - NULL, - sizeof(struct module_state), - kotlin_bridge_funcs, - NULL, - kotlin_bridge_traverse, - kotlin_bridge_clear, - NULL -}; - -PyMODINIT_FUNC PyInit_kotlin_bridge(void) { - PyObject *module = PyModule_Create(&moduledef); - return module; -} -#else -void initkotlin_bridge(void) { - Py_InitModule3("kotlin_bridge", kotlin_bridge_funcs, "Kotlin/Native example module"); -} -#endif diff --git a/kotlin-native/samples/python_extension/src/main/kotlin/Server.kt b/kotlin-native/samples/python_extension/src/main/kotlin/Server.kt deleted file mode 100644 index ee137f8f94b..00000000000 --- a/kotlin-native/samples/python_extension/src/main/kotlin/Server.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package demo - -class Session(val name: String, val number: Int) - -class Server(val prefix: String) { - fun greet(session: Session) = "$prefix: Hello from Kotlin/Native in ${session}" - fun concat(session: Session, a: String, b: String) = "$prefix: $a $b in ${session}" - fun add(session: Session, a: Int, b: Int) = a + b + session.number -} diff --git a/kotlin-native/samples/python_extension/src/main/python/main.py b/kotlin-native/samples/python_extension/src/main/python/main.py deleted file mode 100644 index bb7111128e5..00000000000 --- a/kotlin-native/samples/python_extension/src/main/python/main.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/python -# -# Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license -# that can be found in the license/LICENSE.txt file. -# - -import kotlin_bridge - -session = kotlin_bridge.open_session(239, 'konan') - -message = kotlin_bridge.greet_server(session) -print("Greet '{}'".format(message)) - -message = kotlin_bridge.concat_server(session, "Coding", "fun") -print("Concat '{}'".format(message)) - -message = kotlin_bridge.add_server(session, 1, 60) -print("Sum '{}'".format(message)) - - -kotlin_bridge.close_session(session) - diff --git a/kotlin-native/samples/python_extension/src/main/python/setup.py b/kotlin-native/samples/python_extension/src/main/python/setup.py deleted file mode 100644 index e8030fd991b..00000000000 --- a/kotlin-native/samples/python_extension/src/main/python/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -# -# Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license -# that can be found in the license/LICENSE.txt file. -# - -from distutils.core import setup, Extension - -setup(name='kotlin_bridge', - version='1.0', - maintainer = 'JetBrains', - maintainer_email = 'info@jetbrains.com', - author = 'JetBrains', - author_email = 'info@jetbrains.com', - description = 'Kotlin/Native Python bridge', - long_description = 'Using Kotlin/Native from Python example', - - # data_files=[("/Library/Python/2.7/site-packages/", ['libserver.dylib'])], - - ext_modules=[ - Extension('kotlin_bridge', - include_dirs = ['./build'], - libraries = ['server'], - library_dirs = ['./build'], - depends = ['server_api.h'], - sources = ['src/main/c/kotlin_bridge.c'] - ) - ] -) - -# On macOS, after install you may want to copy libserver.dylib to Python's extension directory, -# and do something like -# sudo install_name_tool /Library/Python/2.7/site-packages/kotlin_bridge.so -change libserver.dylib @loader_path/libserver.dylib -# This way libserver.dylib could be loaded from extension's directory. \ No newline at end of file diff --git a/kotlin-native/samples/settings.gradle.kts b/kotlin-native/samples/settings.gradle.kts index ed5559953a3..e88a0ee28d7 100644 --- a/kotlin-native/samples/settings.gradle.kts +++ b/kotlin-native/samples/settings.gradle.kts @@ -19,12 +19,9 @@ if (isMacos || isLinux || isWindows) { include(":csvparser") include(":curl") include(":echoServer") - include(":gitchurn") include(":globalState") - include(":gtk") include(":html5Canvas") include(":libcurl") - include(":tetris") include(":videoplayer") include(":workers") include(":coverage") @@ -33,7 +30,6 @@ if (isMacos || isLinux || isWindows) { if (isMacos || isLinux) { include(":nonBlockingEchoServer") include(":tensorflow") - include(":torch") } if (isMacos) { @@ -41,7 +37,6 @@ if (isMacos) { include(":opengl") include(":uikit") include(":watchos") - include(":simd") } if (isWindows) { diff --git a/kotlin-native/samples/simd/build.gradle.kts b/kotlin-native/samples/simd/build.gradle.kts deleted file mode 100644 index ba008f6b994..00000000000 --- a/kotlin-native/samples/simd/build.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - kotlin("multiplatform") -} - -kotlin { - macosX64 { - binaries { - executable() - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt b/kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt deleted file mode 100644 index 99d63bb55dd..00000000000 --- a/kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt +++ /dev/null @@ -1,54 +0,0 @@ -import platform.Accelerate.* - -// Custom print -fun Vector128.toStringHex(): String { - return "0x" + (0 until 16).map { getUByteAt(it).toString(16) }.joinToString("") -} - -// Custom print -fun Vector128.toStringFloat(): String { - return "(${(0 until 4).map { getFloatAt(it).toString() }.joinToString(", ")})" -} - - -fun main() { - - // Accessors - val vf4 = vectorOf(1f, 3.162f, 10f, 31f) - println(vf4) - println(vf4.toStringFloat()) - println(vf4.toStringHex()) - println(vf4.getFloatAt(1)) - println(vf4.getIntAt(0)) - println(vf4.getByteAt(3)) - // Illegal access (out of bounds) - try { - println(vf4.getIntAt(4)) - println("FAILED") - } catch (e: IndexOutOfBoundsException) { - println("Handling $e") - } - - // Assignment and equality - var x1 = vectorOf(-1f, 0f, 0f, -7f) - val y1 = vectorOf(-1f, 0f, 0f, -7f) - var x2 = vectorOf(1f, 4f, 3f, 7f) - println("(x1 == y1) is ${(x1 == y1)}") - println("(x1.equals(y1)) is ${(x1.equals(y1))}") - println("(x1 == x2) is ${(x1 == x2)}") - x1 = x2 - println("Now (x1 == x1) is ${(x1 == x1)}") - - - // Using library function (MacOS Accelerate framework) - val sum = vS128Add(vectorOf(1,2,3,4), vectorOf(4,3,2,1)) - println(sum) - // More Accelerate framework - val q = vectorOf(1f, 9f, 25f, 49f) - val sq = vsqrtf(q) - println("vsqrtf$q = ${sq.toStringFloat()}") - val f4 = vectorOf(1f, 3.162f, 10f, 31f) - println("vlog10f($f4) = ${vlog10f(vf4).toStringFloat()}") - - -} diff --git a/kotlin-native/samples/tetris/README.md b/kotlin-native/samples/tetris/README.md deleted file mode 100644 index ca961c9f74e..00000000000 --- a/kotlin-native/samples/tetris/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Tetris game - -This example shows implementation of simple Tetris game using SDL -(Simple DirectMedia Layer) library for rendering. SDL allows easy development -of cross-platform game and multimedia applications. - -Install SDL2 development files (see https://www.libsdl.org/download-2.0.php). For Mac - -copy `SDL2.framework` to `$HOME/Library/Frameworks`. For Debian-like Linux - -use `apt-get install libsdl2-dev`. -For Windows - `pacman -S mingw-w64-x86_64-SDL2 mingw-w64-i686-SDL2` in MSYS2 console. If you do not have MSYS2 -installed - install it first as described in http://www.msys2.org - -To build Tetris application for your host platform use `../gradlew assemble`. - -Note that SDL2 must be installed on the host. - -Now you can run the game using `../gradlew runReleaseExecutableTetris` or directly with - - ./build/bin/tetris/main/release/executable/tetris.kexe - -During build process compilation script creates interoperability bindings to SDL2, using SDL C headers, -and then compiles an application with the produced bindings. - -To deploy executable to iPhone device take Info.plist, then use XCode and your own private signing identity. - -To run on Raspberry Pi one need to install SDL package with `apt-get install libsdl2-2.0.0` on the Pi. -Also GLES2 renderer is recommended (use `SDL_RENDER_DRIVER=opengles2 ./Tetris.kexe`). - -For Windows `set SDL_RENDER_DRIVER=software` may be needed on some machines. - -Note: There is a known issue with SDL2 library on Mac OS X 10.14 Mojave. Window may render black until -it is dragged. See https://bugzilla.libsdl.org/show_bug.cgi?id=4272 diff --git a/kotlin-native/samples/tetris/build.gradle.kts b/kotlin-native/samples/tetris/build.gradle.kts deleted file mode 100644 index 6b782129ac4..00000000000 --- a/kotlin-native/samples/tetris/build.gradle.kts +++ /dev/null @@ -1,119 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - -plugins { - kotlin("multiplatform") -} - -val kotlinNativeDataPath = System.getenv("KONAN_DATA_DIR")?.let { File(it) } - ?: File(System.getProperty("user.home")).resolve(".konan") -val mingw64Path = File(System.getenv("MINGW64_DIR") ?: "C:/msys64/mingw64") -val mingw32Path = File(System.getenv("MINGW32_DIR") ?: "C:/msys64/mingw32") - -kotlin { - val hostOs = System.getProperty("os.name") - if (hostOs == "Mac OS X") { - macosX64() - } - if (hostOs == "Linux") { - linuxX64() - } - if (hostOs.startsWith("Windows")) { - mingwX64() - mingwX86() - } - - targets.withType { - sourceSets["${targetName}Main"].apply { - kotlin.srcDir("src/tetrisMain/kotlin") - } - - binaries { - executable { - entryPoint = "sample.tetris.main" - - // Compile Windows Resources - if (preset == presets["mingwX64"] || preset == presets["mingwX86"]) { - val taskName = linkTaskName.replaceFirst("link", "windres") - val inFile = File("src/tetrisMain/resources/Tetris.rc") - val outFile = buildDir.resolve("processedResources/$taskName.res") - val windresTask = tasks.register(taskName) { - val llvmDir = when (preset) { - presets["mingwX86"] -> kotlinNativeDataPath.resolve( - "dependencies/msys2-mingw-w64-i686-2/bin") - presets["mingwX64"] -> kotlinNativeDataPath.resolve( - "dependencies/msys2-mingw-w64-x86_64-2/bin") - else -> throw GradleException("Unsupported presets") - }.toString() - inputs.file(inFile) - outputs.file(outFile) - commandLine("$llvmDir/windres", inFile, "-O", "coff", "-o", outFile) - environment("PATH", "$llvmDir;${System.getenv("PATH")}") - dependsOn(compilation.compileKotlinTask) - } - linkTask.dependsOn(windresTask) - linkerOpts(outFile.toString()) - } - - when (preset) { - presets["macosX64"] -> linkerOpts("-L/opt/local/lib", "-L/usr/local/lib", "-lSDL2") - presets["linuxX64"] -> linkerOpts("-L/usr/lib64", "-L/usr/lib/x86_64-linux-gnu", "-lSDL2") - presets["mingwX64"] -> linkerOpts( - "-L${mingw64Path.resolve("lib")}", - "-Wl,-Bstatic", - "-lstdc++", - "-static", - "-lSDL2", - "-limm32", - "-lole32", - "-loleaut32", - "-lversion", - "-lwinmm", - "-lsetupapi", - "-mwindows" - ) - presets["mingwX86"] -> linkerOpts( - "-L${mingw32Path.resolve("lib")}", - "-Wl,-Bstatic", - "-lstdc++", - "-static", - "-lSDL2", - "-limm32", - "-lole32", - "-loleaut32", - "-lversion", - "-lwinmm", - "-lsetupapi", - "-mwindows" - ) - } - - val distTaskName = linkTaskName.replaceFirst("link", "dist") - val distTask = tasks.register(distTaskName) { - from("src/tetrisMain/resources") - into(linkTask.outputFile.get().parentFile) - exclude("*.rc") - if (!konanTarget.family.isAppleFamily) { - exclude("*.plist") - } - dependsOn(linkTask) - } - tasks["assemble"].dependsOn(distTask) - - runTask?.workingDir(project.provider { outputDirectory }) - } - } - - compilations["main"].cinterops { - val sdl by creating { - when (preset) { - presets["macosX64"] -> includeDirs("/opt/local/include/SDL2", "/usr/local/include/SDL2") - presets["linuxX64"] -> includeDirs("/usr/include", "/usr/include/x86_64-linux-gnu", "/usr/include/SDL2") - presets["mingwX64"] -> includeDirs(mingw64Path.resolve("include/SDL2")) - presets["mingwX86"] -> includeDirs(mingw32Path.resolve("include/SDL2")) - } - } - } - - compilations["main"].enableEndorsedLibs = true - } -} \ No newline at end of file diff --git a/kotlin-native/samples/tetris/gradle.properties b/kotlin-native/samples/tetris/gradle.properties deleted file mode 100644 index 790a07d5124..00000000000 --- a/kotlin-native/samples/tetris/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def b/kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def deleted file mode 100644 index 10463bab759..00000000000 --- a/kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def +++ /dev/null @@ -1,9 +0,0 @@ -headers = SDL.h stdlib.h time.h -entryPoint = SDL_main - -headerFilter = SDL* stdlib.h time.h - -compilerOpts = -D_POSIX_SOURCE -compilerOpts.osx = -compilerOpts.linux = -D_REENTRANT -compilerOpts.ios = diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt deleted file mode 100644 index 6e4f9f59ff4..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.tetris - -import platform.posix.* -import kotlinx.cinterop.* - -object Config { - var width: Int = 10 - private set - var height: Int = 20 - private set - var startLevel = 0 - private set - - init { - val file = fopen("config.txt", "r") - if (file != null) { - try { - val buffer = ByteArray(2 * 1024) - while (true) { - val nextLine = fgets(buffer.refTo(0), buffer.size, file)?.toKString() - if (nextLine == null || nextLine.isEmpty()) break - val records = nextLine.split('=') - if (records.size != 2) continue - val key = records[0].trim() - val value = records[1].trim() - when (key) { - "width" -> width = value.toInt() - "height" -> height = value.toInt() - "startLevel" -> startLevel = value.toInt() - } - } - } finally { - fclose(file) - } - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt deleted file mode 100644 index 8d582b531b3..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.tetris - -import kotlinx.cinterop.* -import platform.posix.* -import sdl.* - -fun get_SDL_Error() = SDL_GetError()!!.toKString() - -fun sleep(millis: Int) { - SDL_Delay(millis.toUInt()) -} - -class SDL_Visualizer(val width: Int, val height: Int): GameFieldVisualizer, UserInput { - private val CELL_SIZE = 20 - private val COLORS = 10 - private val CELLS_WIDTH = COLORS * CELL_SIZE - private val CELLS_HEIGHT = 3 * CELL_SIZE - private val SYMBOL_SIZE = 21 - private val INFO_MARGIN = 10 - private val MARGIN = 2 - private val BORDER_WIDTH = 18 - private val INFO_SPACE_WIDTH = SYMBOL_SIZE * (2 + 8) - private val LINES_LABEL_WIDTH = 104 - private val SCORE_LABEL_WIDTH = 107 - private val LEVEL_LABEL_WIDTH = 103 - private val NEXT_LABEL_WIDTH = 85 - private val TETRISES_LABEL_WIDTH = 162 - - private var ratio: Float - - private fun stretch(value: Int) = (value.toFloat() * ratio + 0.5).toInt() - - inner class GamePadButtons(width: Int, height: Int, gamePadHeight: Int) { - val MOVE_BUTTON_SIZE = 50 - val ROTATE_BUTTON_SIZE = 80 - val BUTTONS_MARGIN = 25 - - val arena = Arena() - val leftRect: SDL_Rect - val rightRect: SDL_Rect - val downRect: SDL_Rect - val dropRect: SDL_Rect - val rotateRect: SDL_Rect - - init { - val moveButtonsWidth = 3 * MOVE_BUTTON_SIZE + 2 * BUTTONS_MARGIN + BUTTONS_MARGIN - val x = (width - moveButtonsWidth - ROTATE_BUTTON_SIZE) / 2 - MOVE_BUTTON_SIZE - val y2 = (gamePadHeight - 2 * MOVE_BUTTON_SIZE - BUTTONS_MARGIN) / 2 - leftRect = arena.alloc() - leftRect.w = MOVE_BUTTON_SIZE - leftRect.h = MOVE_BUTTON_SIZE - leftRect.x = x - leftRect.y = height - gamePadHeight + y2 + MOVE_BUTTON_SIZE + BUTTONS_MARGIN - - downRect = arena.alloc() - downRect.w = MOVE_BUTTON_SIZE - downRect.h = MOVE_BUTTON_SIZE - downRect.x = x + MOVE_BUTTON_SIZE + BUTTONS_MARGIN - downRect.y = leftRect.y - - dropRect = arena.alloc() - dropRect.w = MOVE_BUTTON_SIZE - dropRect.h = MOVE_BUTTON_SIZE - dropRect.x = downRect.x - dropRect.y = height - gamePadHeight + y2 - - rightRect = arena.alloc() - rightRect.w = MOVE_BUTTON_SIZE - rightRect.h = MOVE_BUTTON_SIZE - rightRect.x = x + 2 * MOVE_BUTTON_SIZE + 2 * BUTTONS_MARGIN - rightRect.y = height - gamePadHeight + y2 + MOVE_BUTTON_SIZE + BUTTONS_MARGIN - - rotateRect = arena.alloc() - rotateRect.w = ROTATE_BUTTON_SIZE - rotateRect.h = ROTATE_BUTTON_SIZE - rotateRect.x = x + moveButtonsWidth - rotateRect.y = height - gamePadHeight + y2 - BUTTONS_MARGIN - } - - fun getCommandAt(x: Int, y: Int): UserCommand? { - return when { - inside(leftRect, x, y) -> UserCommand.LEFT - inside(rightRect, x, y) -> UserCommand.RIGHT - inside(downRect, x, y) -> UserCommand.DOWN - inside(dropRect, x, y) -> UserCommand.DROP - inside(rotateRect, x, y) -> UserCommand.ROTATE - else -> null - } - } - - private fun inside(rect: SDL_Rect, x: Int, y: Int): Boolean { - return x >= stretch(rect.x) && x <= stretch(rect.x + rect.w) - && y >= stretch(rect.y) && y <= stretch(rect.y + rect.h) - } - - fun destroy() { - arena.clear() - } - } - - private val field: Field = Array(height) { ByteArray(width) } - private val nextPieceField: Field = Array(4) { ByteArray(4) } - private var linesCleared: Int = 0 - private var level: Int = 0 - private var score: Int = 0 - private var tetrises: Int = 0 - - private var displayWidth: Int = 0 - private var displayHeight: Int = 0 - private val fieldWidth: Int - private val fieldHeight: Int - private var windowX: Int - private var windowY: Int - private val window: CPointer - private val renderer: CPointer - private val texture: CPointer - private val gamePadButtons: GamePadButtons? - private val platform: String - - init { - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { - throw Error("SDL_Init Error: ${get_SDL_Error()}") - } - - platform = SDL_GetPlatform()!!.toKString() - - memScoped { - val displayMode = alloc() - if (SDL_GetCurrentDisplayMode(0, displayMode.ptr.reinterpret()) != 0) { - println("SDL_GetCurrentDisplayMode Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - displayWidth = displayMode.w - displayHeight = displayMode.h - } - fieldWidth = width * (CELL_SIZE + MARGIN) + MARGIN + BORDER_WIDTH * 2 - fieldHeight = height * (CELL_SIZE + MARGIN) + MARGIN + BORDER_WIDTH * 2 - var windowWidth = fieldWidth + INFO_SPACE_WIDTH - var windowHeight: Int - if (platform == "iOS") { - val gamePadHeight = (displayHeight * windowWidth - fieldHeight * displayWidth) / displayWidth - windowHeight = fieldHeight + gamePadHeight - gamePadButtons = GamePadButtons(windowWidth, windowHeight, gamePadHeight) - windowX = 0 - windowY = 0 - ratio = displayHeight.toFloat() / windowHeight - windowWidth = displayWidth - windowHeight = displayHeight - } else { - windowHeight = fieldHeight - gamePadButtons = null - windowX = (displayWidth - windowWidth) / 2 - windowY = (displayHeight - windowHeight) / 2 - ratio = 1.0f - } - val window = SDL_CreateWindow("Tetris", windowX, windowY, windowWidth, windowHeight, - SDL_WINDOW_SHOWN or SDL_WINDOW_ALLOW_HIGHDPI) - if (window == null) { - println("SDL_CreateWindow Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - this.window = window - - val renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC) - if (renderer == null) { - SDL_DestroyWindow(window) - println("SDL_CreateRenderer Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - this.renderer = renderer - - memScoped { - val realWidth = alloc() - val realHeight = alloc() - SDL_GetRendererOutputSize(renderer, realWidth.ptr, realHeight.ptr) - if (platform != "iOS" && windowHeight != realHeight.value) { - println("DPI differs ${realWidth.value} x ${realHeight.value} vs $windowWidth x $windowHeight") - ratio = realHeight.value.toFloat() / windowHeight - } - } - - texture = loadImage(window, renderer, findFile("tetris_all.bmp")) - } - - private fun findFile(name: String): String { - memScoped { - val dirs = listOf(".", SDL_GetBasePath()?.toKString() ?: "/") - val statBuffer = alloc() - dirs.forEach { - val candidate = "$it/$name" - if (stat(candidate, statBuffer.ptr) == 0) return candidate - } - throw Error("name not found") - } - } - - private fun loadImage(win: CPointer, ren: CPointer, imagePath: String): CPointer { - val bmp = SDL_LoadBMP_RW(SDL_RWFromFile(imagePath, "rb"), 1); - if (bmp == null) { - SDL_DestroyRenderer(ren) - SDL_DestroyWindow(win) - println("SDL_LoadBMP_RW Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - - val tex = SDL_CreateTextureFromSurface(ren, bmp) - SDL_FreeSurface(bmp) - if (tex == null) { - SDL_DestroyRenderer(ren) - SDL_DestroyWindow(win) - println("SDL_CreateTextureFromSurface Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - return tex - } - - override fun drawCell(x: Int, y: Int, cell: Byte) { - field[x][y] = cell - } - - override fun drawNextPieceCell(x: Int, y: Int, cell: Byte) { - nextPieceField[x][y] = cell - } - - override fun setInfo(linesCleared: Int, level: Int, score: Int, tetrises: Int) { - this.linesCleared = linesCleared - this.level = level - this.score = score - this.tetrises = tetrises - } - - override fun refresh() { - SDL_RenderClear(renderer) - drawField() - drawInfo() - drawNextPiece() - drawGamePad() - SDL_RenderPresent(renderer) - } - - private fun drawBorder(topLeftX: Int, topLeftY: Int, width: Int, height: Int) { - // Upper-left corner. - var srcX = CELLS_WIDTH - var srcY = 0 - var destX = topLeftX - var destY = topLeftY - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH + MARGIN, BORDER_WIDTH) - - // Upper margin. - srcX += BORDER_WIDTH + MARGIN - destX += BORDER_WIDTH + MARGIN - for (i in 0..width - 1) { - copyRect(srcX, srcY, destX, destY, CELL_SIZE + MARGIN, BORDER_WIDTH) - destX += CELL_SIZE + MARGIN - } - - // Upper-right corner. - srcX += CELL_SIZE + MARGIN - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, BORDER_WIDTH + MARGIN) - - // Right margin. - srcY += BORDER_WIDTH + MARGIN - destY += BORDER_WIDTH + MARGIN - for (j in 0..height - 1) { - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, CELL_SIZE + MARGIN) - destY += CELL_SIZE + MARGIN - } - - // Left margin. - srcX = CELLS_WIDTH - srcY = BORDER_WIDTH - destX = topLeftX - destY = topLeftY + BORDER_WIDTH - for (j in 0..height - 1) { - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, CELL_SIZE + MARGIN) - destY += CELL_SIZE + MARGIN - } - - // Left-down corner. - srcY += CELL_SIZE + MARGIN - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, BORDER_WIDTH + MARGIN) - - // Down marign. - srcX += BORDER_WIDTH - srcY += MARGIN - destX += BORDER_WIDTH - destY += MARGIN - for (i in 0..width - 1) { - copyRect(srcX, srcY, destX, destY, CELL_SIZE + MARGIN, BORDER_WIDTH) - destX += CELL_SIZE + MARGIN - - } - // Right-down corner. - srcX += CELL_SIZE + MARGIN - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH + MARGIN, BORDER_WIDTH) - } - - private fun drawField() { - drawField(field = field, - topLeftX = 0, - topLeftY = 0, - width = width, - height = height) - } - - private fun drawNextPiece() { - drawInt(labelSrcX = LEVEL_LABEL_WIDTH, - labelSrcY = CELLS_HEIGHT + SYMBOL_SIZE, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(5), - labelWidth = NEXT_LABEL_WIDTH, - totalDigits = 0, - value = 0) - drawField(field = nextPieceField, - topLeftX = fieldWidth + SYMBOL_SIZE, - topLeftY = getInfoY(6), - width = 4, - height = 4) - } - - private fun drawField(field: Field, topLeftX: Int, topLeftY: Int, width: Int, height: Int) { - drawBorder(topLeftX = topLeftX, - topLeftY = topLeftY, - width = width, - height = height) - for (i in 0..height - 1) - for (j in 0..width - 1) { - val cell = field[i][j].toInt() - if (cell == 0) continue - copyRect(srcX = (level % COLORS) * CELL_SIZE, - srcY = (3 - cell) * CELL_SIZE, - destX = topLeftX + BORDER_WIDTH + MARGIN + j * (CELL_SIZE + MARGIN), - destY = topLeftY + BORDER_WIDTH + MARGIN + i * (CELL_SIZE + MARGIN), - width = CELL_SIZE, - height = CELL_SIZE) - } - } - - private fun drawInfo() { - drawInt(labelSrcX = LINES_LABEL_WIDTH, - labelSrcY = CELLS_HEIGHT, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(0), - labelWidth = SCORE_LABEL_WIDTH, - totalDigits = 6, - value = score) - drawInt(labelSrcX = 0, - labelSrcY = CELLS_HEIGHT, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(1), - labelWidth = LINES_LABEL_WIDTH, - totalDigits = 3, - value = linesCleared) - drawInt(labelSrcX = 0, - labelSrcY = CELLS_HEIGHT + SYMBOL_SIZE, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(2), - labelWidth = LEVEL_LABEL_WIDTH, - totalDigits = 2, - value = level) - drawInt(labelSrcX = 0, - labelSrcY = CELLS_HEIGHT + SYMBOL_SIZE * 2, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(3), - labelWidth = TETRISES_LABEL_WIDTH, - totalDigits = 2, - value = tetrises) - } - - private fun getInfoY(line: Int): Int { - return SYMBOL_SIZE * (2 * line + 1) + INFO_MARGIN * line - } - - private fun drawInt(labelSrcX: Int, labelSrcY: Int, labelDestX: Int, labelDestY: Int, - labelWidth: Int, totalDigits: Int, value: Int) { - copyRect(srcX = labelSrcX, - srcY = labelSrcY, - destX = labelDestX, - destY = labelDestY, - width = labelWidth, - height = SYMBOL_SIZE) - val digits = IntArray(totalDigits) - var x = value - for (i in 0..totalDigits - 1) { - digits[totalDigits - 1 - i] = x % 10 - x = x / 10 - } - for (i in 0..totalDigits - 1) { - copyRect(srcX = digits[i] * SYMBOL_SIZE, - srcY = CELLS_HEIGHT + 3 * SYMBOL_SIZE, - destX = labelDestX + SYMBOL_SIZE + i * SYMBOL_SIZE, - destY = labelDestY + SYMBOL_SIZE, - width = SYMBOL_SIZE, - height = SYMBOL_SIZE) - } - } - - private fun drawGamePad() { - if (gamePadButtons == null) return - SDL_SetRenderDrawColor(renderer, 127, 127, 127, SDL_ALPHA_OPAQUE.toUByte()) - fillRect(gamePadButtons.leftRect) - fillRect(gamePadButtons.downRect) - fillRect(gamePadButtons.dropRect) - fillRect(gamePadButtons.rightRect) - fillRect(gamePadButtons.rotateRect) - SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE.toUByte()) - } - - private fun fillRect(rect: SDL_Rect) { - memScoped { - val stretchedRect = alloc() - stretchedRect.w = stretch(rect.w) - stretchedRect.h = stretch(rect.h) - stretchedRect.x = stretch(rect.x) - stretchedRect.y = stretch(rect.y) - SDL_RenderFillRect(renderer, stretchedRect.ptr.reinterpret()) - } - } - - private fun copyRect(srcX: Int, srcY: Int, destX: Int, destY: Int, width: Int, height: Int) { - memScoped { - val srcRect = alloc() - val destRect = alloc() - srcRect.w = width - srcRect.h = height - srcRect.x = srcX - srcRect.y = srcY - destRect.w = stretch(width) - destRect.h = stretch(height) - destRect.x = stretch(destX) - destRect.y = stretch(destY) - SDL_RenderCopy(renderer, texture, srcRect.ptr.reinterpret(), destRect.ptr.reinterpret()) - } - } - - override fun readCommands(): List { - val commands = mutableListOf() - memScoped { - val event = alloc() - while (SDL_PollEvent(event.ptr.reinterpret()) != 0) { - val eventType = event.type - when (eventType) { - SDL_QUIT -> commands.add(UserCommand.EXIT) - SDL_KEYDOWN -> { - val keyboardEvent = event.ptr.reinterpret().pointed - when (keyboardEvent.keysym.scancode) { - SDL_SCANCODE_LEFT -> commands.add(UserCommand.LEFT) - SDL_SCANCODE_RIGHT -> commands.add(UserCommand.RIGHT) - SDL_SCANCODE_DOWN -> commands.add(UserCommand.DOWN) - SDL_SCANCODE_Z, SDL_SCANCODE_SPACE -> commands.add(UserCommand.ROTATE) - SDL_SCANCODE_UP -> commands.add(UserCommand.DROP) - SDL_SCANCODE_ESCAPE -> commands.add(UserCommand.EXIT) - } - } - SDL_MOUSEBUTTONDOWN -> if (gamePadButtons != null) { - val mouseEvent = event.ptr.reinterpret().pointed - val x = mouseEvent.x - val y = mouseEvent.y - val command = gamePadButtons.getCommandAt(x, y) - if (command != null) - commands.add(command) - } - } - } - } - return commands - } - - fun destroy() { - SDL_DestroyTexture(texture) - SDL_DestroyRenderer(renderer) - SDL_DestroyWindow(window) - SDL_Quit() - gamePadButtons?.destroy() - } -} diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt deleted file mode 100644 index 0e26af76f4b..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.tetris - -import kotlinx.cinterop.* -import platform.posix.* - -typealias Field = Array - -enum class Move { - LEFT, - RIGHT, - DOWN, - ROTATE -} - -enum class PlacementResult(val linesCleared: Int = 0, val bonus: Int = 0) { - NOTHING, - GAMEOVER, - // For values of bonuses see https://tetris.wiki/Scoring - SINGLE(1, 40), - DOUBLE(2, 100), - TRIPLE(3, 300), - TETRIS(4, 1200) -} - -const val EMPTY: Byte = 0 -const val CELL1: Byte = 1 -const val CELL2: Byte = 2 -const val CELL3: Byte = 3 -const val BRICK: Byte = -1 - -class Point(var x: Int, var y: Int) - -operator fun Point.plus(other: Point): Point { - return Point(x + other.x, y + other.y) -} - -class PiecePosition(piece: Piece, private val origin: Point) { - private var p = piece.origin - val x get() = p.x + origin.x - val y get() = p.y + origin.y - - var state: Int get private set - val numberOfStates = piece.numberOfStates - - init { - state = 0 - } - - fun makeMove(move: Move) { - when (move) { - Move.LEFT -> --p.y - Move.RIGHT -> ++p.y - Move.DOWN -> ++p.x - Move.ROTATE -> state = (state + 1) % numberOfStates - } - } - - fun unMakeMove(move: Move) { - when (move) { - Move.LEFT -> ++p.y - Move.RIGHT -> --p.y - Move.DOWN -> --p.x - Move.ROTATE -> state = (state + numberOfStates - 1) % numberOfStates - } - } -} - -/* - * We use Nintendo Rotation System, right-handed version. - * See https://tetris.wiki/Nintendo_Rotation_System - */ -enum class Piece(private val origin_: Point, private vararg val states: Field) { - T(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL1, CELL1, CELL1), - byteArrayOf(EMPTY, CELL1, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL1, EMPTY), - byteArrayOf(CELL1, CELL1, EMPTY), - byteArrayOf(EMPTY, CELL1, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL1, EMPTY), - byteArrayOf(CELL1, CELL1, CELL1), - byteArrayOf(EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, CELL1, CELL1), - byteArrayOf(EMPTY, CELL1, EMPTY)) - ), - J(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL2, CELL2, CELL2), - byteArrayOf(EMPTY, EMPTY, CELL2)), - arrayOf( - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(CELL2, CELL2, EMPTY)), - arrayOf( - byteArrayOf(CELL2, EMPTY, EMPTY), - byteArrayOf(CELL2, CELL2, CELL2), - byteArrayOf(EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL2, CELL2), - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(EMPTY, CELL2, EMPTY)) - ), - Z(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL3, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, CELL3)), - arrayOf( - byteArrayOf(EMPTY, EMPTY, CELL3), - byteArrayOf(EMPTY, CELL3, CELL3), - byteArrayOf(EMPTY, CELL3, EMPTY)) - ), - O(Point(0, -1), - arrayOf( - byteArrayOf(CELL1, CELL1), - byteArrayOf(CELL1, CELL1)) - ), - S(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(EMPTY, CELL2, CELL2), - byteArrayOf(CELL2, CELL2, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(EMPTY, CELL2, CELL2), - byteArrayOf(EMPTY, EMPTY, CELL2)) - ), - L(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL3, CELL3, CELL3), - byteArrayOf(CELL3, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(CELL3, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, EMPTY, CELL3), - byteArrayOf(CELL3, CELL3, CELL3), - byteArrayOf(EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, CELL3)) - ), - I(Point(-2, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY, EMPTY), - byteArrayOf(EMPTY, EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL1, CELL1, CELL1, CELL1), - byteArrayOf(EMPTY, EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY)) - ); - - val origin get() = Point(origin_.x, origin_.y) - val numberOfStates: Int = states.size - - fun canBePlaced(field: Field, position: PiecePosition): Boolean { - val piece = states[position.state] - val x = position.x - val y = position.y - for (i in piece.indices) { - val pieceRow = piece[i] - val boardRow = field[x + i] - for (j in pieceRow.indices) { - if (pieceRow[j] != EMPTY && boardRow[y + j] != EMPTY) - return false - } - } - return true - } - - fun place(field: Field, position: PiecePosition) { - val piece = states[position.state] - val x = position.x - val y = position.y - for (i in piece.indices) { - val pieceRow = piece[i] - for (j in pieceRow.indices) { - if (pieceRow[j] != EMPTY) field[x + i][y + j] = pieceRow[j] - } - } - } - - fun unPlace(field: Field, position: PiecePosition) { - val piece = states[position.state] - val x = position.x - val y = position.y - for (i in piece.indices) { - val pieceRow = piece[i] - for (j in pieceRow.indices) { - if (pieceRow[j] != EMPTY) field[x + i][y + j] = EMPTY - } - } - } -} - -interface GameFieldVisualizer { - fun drawCell(x: Int, y: Int, cell: Byte) - fun drawNextPieceCell(x: Int, y: Int, cell: Byte) - fun setInfo(linesCleared: Int, level: Int, score: Int, tetrises: Int) - fun refresh() -} - -enum class UserCommand { - LEFT, - RIGHT, - DOWN, - DROP, - ROTATE, - EXIT -} - -interface UserInput { - fun readCommands(): List -} - -class GameField(val width: Int, val height: Int, val visualizer: GameFieldVisualizer) { - private val MARGIN = 4 - - private val field: Field - private val origin: Point - private val nextPieceField: Field - - init { - field = Array(height + MARGIN * 2) { ByteArray(width + MARGIN * 2) } - for (i in field.indices) { - val row = field[i] - for (j in row.indices) { - if (i >= (MARGIN + height) // Bottom (field is flipped over). - || (j < MARGIN) // Left - || (j >= MARGIN + width)) // Right - row[j] = BRICK - } - } - // Coordinates are relative to the central axis and top of the field. - origin = Point(MARGIN, MARGIN + (width + 1) / 2) - nextPieceField = Array(4) { ByteArray(4) } - } - - lateinit var currentPiece: Piece - lateinit var nextPiece: Piece - lateinit var currentPosition: PiecePosition - - fun reset() { - for (i in 0..height - 1) - for (j in 0..width - 1) - field[i + MARGIN][j + MARGIN] = 0 - srand(time(null).toUInt()) - nextPiece = getNextPiece(false) - switchCurrentPiece() - } - - private fun randInt() = (rand() and 32767) or ((rand() and 32767) shl 15) - - private fun getNextPiece(denyPrevious: Boolean): Piece { - val pieces = Piece.values() - if (!denyPrevious) - return pieces[randInt() % pieces.size] - while (true) { - val nextPiece = pieces[randInt() % pieces.size] - if (nextPiece != currentPiece) return nextPiece - } - } - - private fun switchCurrentPiece() { - currentPiece = nextPiece - nextPiece = getNextPiece(denyPrevious = true) // Forbid repeating the same piece for better distribution. - currentPosition = PiecePosition(currentPiece, origin) - } - - fun makeMove(move: Move): Boolean { - currentPosition.makeMove(move) - if (currentPiece.canBePlaced(field, currentPosition)) - return true - currentPosition.unMakeMove(move) - return false - } - - /** - * Places current piece at its current location. - */ - fun place(): PlacementResult { - currentPiece.place(field, currentPosition) - val linesCleared = clearLines() - if (isOutOfBorders()) return PlacementResult.GAMEOVER - switchCurrentPiece() - if (!currentPiece.canBePlaced(field, currentPosition)) - return PlacementResult.GAMEOVER - when (linesCleared) { - 1 -> return PlacementResult.SINGLE - 2 -> return PlacementResult.DOUBLE - 3 -> return PlacementResult.TRIPLE - 4 -> return PlacementResult.TETRIS - else -> return PlacementResult.NOTHING - } - } - - private fun clearLines(): Int { - val clearedLines = mutableListOf() - for (i in 0..height - 1) { - val row = field[i + MARGIN] - if ((0..width - 1).all { j -> row[j + MARGIN] != EMPTY }) { - clearedLines.add(i + MARGIN) - (0..width - 1).forEach { j -> row[j + MARGIN] = EMPTY } - } - } - if (clearedLines.size == 0) return 0 - draw(false) - visualizer.refresh() - sleep(500) - for (i in clearedLines) { - for (k in i - 1 downTo 1) - for (j in 0..width - 1) - field[k + 1][j + MARGIN] = field[k][j + MARGIN] - } - draw(false) - visualizer.refresh() - return clearedLines.size - } - - private fun isOutOfBorders(): Boolean { - for (i in 0..MARGIN - 1) - for (j in 0..width - 1) - if (field[i][j + MARGIN] != EMPTY) - return true - return false - } - - fun draw() { - draw(true) - drawNextPiece() - } - - private fun drawNextPiece() { - for (i in 0..3) - for (j in 0..3) - nextPieceField[i][j] = 0 - nextPiece.place(nextPieceField, PiecePosition(nextPiece, Point(1, 2))) - for (i in 0..3) - for (j in 0..3) - visualizer.drawNextPieceCell(i, j, nextPieceField[i][j]) - } - - private fun draw(drawCurrentPiece: Boolean) { - if (drawCurrentPiece) - currentPiece.place(field, currentPosition) - for (i in 0..height - 1) - for (j in 0..width - 1) - visualizer.drawCell(i, j, field[i + MARGIN][j + MARGIN]) - if (drawCurrentPiece) - currentPiece.unPlace(field, currentPosition) - } -} - -class Game(width: Int, height: Int, val visualizer: GameFieldVisualizer, val userInput: UserInput) { - private val field = GameField(width, height, visualizer) - - private var gameOver = true - private var startLevel = 0 - private var leveledUp = false - private var level = 0 - private var linesClearedAtCurrentLevel = 0 - private var linesCleared = 0 - private var tetrises = 0 - private var score = 0 - - /* - * For speed constants and level up thresholds see https://tetris.wiki/Tetris_(NES,_Nintendo) - */ - private val speeds = intArrayOf(48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) - private val levelUpThreshold - get() = - if (leveledUp) 10 - else minOf(startLevel * 10 + 10, maxOf(100, startLevel * 10 - 50)) - private val speed get() = if (level < 29) speeds[level] else 1 - - private var ticks = 0 - - fun startNewGame(level: Int) { - gameOver = false - startLevel = level - leveledUp = false - this.level = level - linesClearedAtCurrentLevel = 0 - linesCleared = 0 - tetrises = 0 - score = 0 - ticks = 0 - field.reset() - - visualizer.setInfo(linesCleared, level, score, tetrises) - field.draw() - visualizer.refresh() - - mainLoop() - } - - private fun placePiece() { - val placementResult = field.place() - ticks = 0 - when (placementResult) { - PlacementResult.NOTHING -> return - PlacementResult.GAMEOVER -> { - gameOver = true - return - } - else -> { - linesCleared += placementResult.linesCleared - linesClearedAtCurrentLevel += placementResult.linesCleared - score += placementResult.bonus * (level + 1) - if (placementResult == PlacementResult.TETRIS) - ++tetrises - val levelUpThreshold = levelUpThreshold - if (linesClearedAtCurrentLevel >= levelUpThreshold) { - ++level - linesClearedAtCurrentLevel -= levelUpThreshold - leveledUp = true - } - - visualizer.setInfo(linesCleared, level, score, tetrises) - } - } - } - - /* - * Number of additional gravity shifts before locking a piece landed on the ground. - * This is needed in order to let user to move a piece to the left/right before locking. - */ - private val LOCK_DELAY = 1 - - private fun mainLoop() { - var attemptsToLock = 0 - while (!gameOver) { - sleep(1000 / 60) // Refresh rate - 60 frames per second. - val commands = userInput.readCommands() - for (cmd in commands) { - val success: Boolean - when (cmd) { - UserCommand.EXIT -> return - UserCommand.LEFT -> success = field.makeMove(Move.LEFT) - UserCommand.RIGHT -> success = field.makeMove(Move.RIGHT) - UserCommand.ROTATE -> success = field.makeMove(Move.ROTATE) - UserCommand.DOWN -> { - success = field.makeMove(Move.DOWN) - if (!success) placePiece() - } - UserCommand.DROP -> { - while (field.makeMove(Move.DOWN)) { - } - success = true - placePiece() - } - } - if (success) { - field.draw() - visualizer.refresh() - } - } - ++ticks - if (ticks < speed) continue - if (!field.makeMove(Move.DOWN)) { - if (++attemptsToLock >= LOCK_DELAY) { - placePiece() - attemptsToLock = 0 - } - } - field.draw() - visualizer.refresh() - ticks -= speed - } - } - -} - diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt deleted file mode 100644 index 6548dcb6296..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.tetris - -import kotlinx.cli.* - -fun main(args: Array) { - val argParser = ArgParser("tetris", useDefaultHelpShortName = false) - val level by argParser.option(ArgType.Int, shortName = "l", description = "Game level").default(Config.startLevel) - val width by argParser.option(ArgType.Int, shortName = "w", description = "Width of the game field").default(Config.width) - val height by argParser.option(ArgType.Int, shortName = "h", description = "Height of the game field").default(Config.height) - argParser.parse(args) - val visualizer = SDL_Visualizer(width, height) - val game = Game(width, height, visualizer, visualizer) - game.startNewGame(level) - - return -} \ No newline at end of file diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist b/kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist deleted file mode 100644 index da637bfe644..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist +++ /dev/null @@ -1,77 +0,0 @@ - - - - - BuildMachineOSBuild - 15G1212 - CFBundleDevelopmentRegion - en - CFBundleExecutable - tetris.kexe - CFBundleIdentifier - tetris.kexe - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - tetris.kexe - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSupportedPlatforms - - iPhoneOS - - CFBundleVersion - 1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 14C89 - DTPlatformName - iphoneos - DTPlatformVersion - 10.2 - DTSDKBuild - 14C89 - DTSDKName - iphoneos10.2 - DTXcode - 0821 - DTXcodeBuild - 8C1002 - LSRequiresIPhoneOS - - MinimumOSVersion - 10.2 - UIDeviceFamily - - 1 - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - arm64 - - UIStatusBarHidden - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CFBundleIcons - - CFBundlePrimaryIcon - - CFBundleIconFiles - - Icon-60x2 - Icon-60 - - - - - diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc b/kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc deleted file mode 100644 index 6d1bcf075d3..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc +++ /dev/null @@ -1,23 +0,0 @@ -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "JetBrains LLC" - VALUE "FileDescription", "Tetris Demo Game" - VALUE "FileVersion", "1.0" - VALUE "InternalName", "Tetris" - VALUE "LegalCopyright", "©JetBrains" - VALUE "OriginalFilename", "Tetris.exe" - VALUE "ProductName", "Tetris for Windows" - VALUE "ProductVersion", "1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt b/kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt deleted file mode 100644 index da8f7d7d673..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt +++ /dev/null @@ -1,3 +0,0 @@ -width = 10 -height = 30 -startLevel = 0 \ No newline at end of file diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/tetris_all.bmp b/kotlin-native/samples/tetris/src/tetrisMain/resources/tetris_all.bmp deleted file mode 100644 index e5c57a6cc4f..00000000000 Binary files a/kotlin-native/samples/tetris/src/tetrisMain/resources/tetris_all.bmp and /dev/null differ diff --git a/kotlin-native/samples/torch/README.md b/kotlin-native/samples/torch/README.md deleted file mode 100644 index 7c0bf73a233..00000000000 --- a/kotlin-native/samples/torch/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Torch demo - -Trains a handwritten digit classifier using the [Torch](http://torch.ch) C backend. -Like other Torch clients, most prominently [PyTorch](http://pytorch.org), -this example is built on top of the -[ATen C API](https://github.com/pytorch/pytorch/tree/master/aten), -showing how a Torch client for Kotlin/Native could look like. - -## Installation - -To build [ATen (Torch for C)](https://github.com/pytorch/pytorch/tree/master/aten), -make sure you have Python 2.X and pyyaml installed: - - # macOS: if you don't have pip - sudo easy_install pip - # Linux: if you don't have pip - apt-get -y install python-pip - - # if you don't have pyyaml or typing - sudo pip install pyyaml typing - -Now - - ./downloadTorch.sh - -will install it into `$HOME/.konan/third-party/torch` (if not yet done). One may override the location of -`third-party/torch` by setting the `KONAN_DATA_DIR` environment variable. - -To build use `../gradlew assemble`. - - ./downloadMNIST.sh - -will download and unzip the [MNIST dataset](https://en.wikipedia.org/wiki/MNIST_database) of -[70000 labeled handwritten digits](http://yann.lecun.com/exdb/mnist/) for training and testing a classifier (if not yet done). - -Then run - - ../gradlew runReleaseExecutableTorch - -Alternatively you can run the artifact directly through - - ./build/bin/torch/main/release/executable/torch.kexe - -You may need to specify `LD_LIBRARY_PATH` or `DYLD_LIBRARY_PATH` environment variables -to point to `$HOME/.konan/third-party/torch/lib` if the ATen dynamic library cannot be found. - -Even on a CPU, training should only take some minutes, -and you should observe a classification accuracy of about 95% on the test dataset. diff --git a/kotlin-native/samples/torch/build.gradle.kts b/kotlin-native/samples/torch/build.gradle.kts deleted file mode 100644 index 113a5e6c617..00000000000 --- a/kotlin-native/samples/torch/build.gradle.kts +++ /dev/null @@ -1,62 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType - -plugins { - kotlin("multiplatform") -} - -val kotlinNativeDataPath = System.getenv("KONAN_DATA_DIR")?.let { File(it) } - ?: File(System.getProperty("user.home")).resolve(".konan") - -val torchHome = kotlinNativeDataPath.resolve("third-party/torch") - -kotlin { - // Determine host preset. - val hostOs = System.getProperty("os.name") - - // Create target for the host platform. - val hostTarget = when { - hostOs == "Mac OS X" -> macosX64("torch") - hostOs == "Linux" -> linuxX64("torch") - // Windows is not supported - else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.") - } - - hostTarget.apply { - binaries { - executable { - entryPoint = "sample.torch.main" - linkerOpts("-L${torchHome.resolve("lib")}", "-lATen") - runTask?.environment( - "LD_LIBRARY_PATH" to torchHome.resolve("lib"), - "DYLD_LIBRARY_PATH" to torchHome.resolve("lib") - ) - } - } - compilations["main"].cinterops { - val torch by creating { - includeDirs( - torchHome.resolve("include"), - torchHome.resolve("include/TH") - ) - } - } - } -} - -val downloadTorch by tasks.creating(Exec::class) { - workingDir = projectDir - commandLine("./downloadTorch.sh") -} - -val torch: KotlinNativeTarget by kotlin.targets -tasks[torch.compilations["main"].cinterops["torch"].interopProcessingTaskName].dependsOn(downloadTorch) - -val downloadMNIST by tasks.creating(Exec::class) { - workingDir = projectDir - commandLine("./downloadMNIST.sh") -} - -NativeBuildType.values() - .mapNotNull { torch.binaries.getExecutable(it).runTask } - .forEach { runTask -> runTask.dependsOn(downloadMNIST) } diff --git a/kotlin-native/samples/torch/downloadMNIST.sh b/kotlin-native/samples/torch/downloadMNIST.sh deleted file mode 100755 index ea348c32340..00000000000 --- a/kotlin-native/samples/torch/downloadMNIST.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -# See http://yann.lecun.com/exdb/mnist/ - -MNIST_TARGET_DIRECTORY="`pwd`/build/3rd-party/MNIST" - -echo "Downloading MNIST databases into $MNIST_TARGET_DIRECTORY ..." - -mkdir -p $MNIST_TARGET_DIRECTORY -cd $MNIST_TARGET_DIRECTORY - -wget -nv -N http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz -wget -nv -N http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz -wget -nv -N http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz -wget -nv -N http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz - -gunzip -fk *.gz diff --git a/kotlin-native/samples/torch/downloadTorch.sh b/kotlin-native/samples/torch/downloadTorch.sh deleted file mode 100755 index 4fa7c03c84a..00000000000 --- a/kotlin-native/samples/torch/downloadTorch.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -KONAN_USER_DIR=${KONAN_DATA_DIR:-"$HOME/.konan"} -TH_TARGET_DIRECTORY="$KONAN_USER_DIR/third-party/torch" -NO_CUDA=true # set to false for GPU support - -if [ ! -d $TH_TARGET_DIRECTORY/include/THNN ]; then - echo "Installing Torch into $TH_TARGET_DIRECTORY ..." - - mkdir -p build/3rd-party - cd build/3rd-party - - git clone https://github.com/pytorch/pytorch.git - # Current pytorch master fails the build so we need to checkout a correct revision. - cd pytorch && git checkout 310c3735b9eb97f30cee743b773e5bb054989edc^ && cd ../ - - mkdir build_torch - cd build_torch - - cmake -DNO_CUDA=$NO_CUDA ../pytorch/aten - make - make DESTDIR=$TH_TARGET_DIRECTORY install - - cd $TH_TARGET_DIRECTORY - - # remove 'usr/local' prefix produced by make: - mv usr/local/* . - rm -d usr/local usr - - # hack to solve "fatal error: 'generic/THNN.h' file not found" when linking, -I$/include/THNN did not work - cp include/THNN/generic/THNN.h include/TH/generic/THNN.h -fi diff --git a/kotlin-native/samples/torch/gradle.properties b/kotlin-native/samples/torch/gradle.properties deleted file mode 100644 index 790a07d5124..00000000000 --- a/kotlin-native/samples/torch/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def b/kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def deleted file mode 100644 index 958c948be70..00000000000 --- a/kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def +++ /dev/null @@ -1 +0,0 @@ -headers = TH/TH.h THNN/THNN.h diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt deleted file mode 100644 index 0526a49cbfe..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.torch - -fun Float.toRoundedString(digits: Int = 0): String { - var factor = 1 - - for (i in 0 until digits) { - factor *= 10 - } - - return (kotlin.math.round(this * factor) / factor).toString() -} - -fun Float.toPercentageString(roundToDigits: Int = 1) = (this * 100).toRoundedString(roundToDigits) - -fun List.maxIndex() = withIndex().maxByOrNull { it.value }!!.index - -fun accuracy(predictionBatch: FloatMatrix, labelBatch: FloatMatrix): Float { - val resultIndexes = predictionBatch.toList().map { it.maxIndex() } - val labelBatchIndexes = labelBatch.toList().map { it.maxIndex() } - return resultIndexes.zip(labelBatchIndexes). - count { (result, label) -> result == label }.toFloat() / resultIndexes.size -} - -fun Backpropagatable.trainClassifier( - dataset: Dataset, - lossByLabels: (FloatMatrix) -> Backpropagatable, - learningRateByProgress: (Float) -> Float = { 5f * kotlin.math.exp(-it * 3) }, - batchSize: Int = 64, - iterations: Int = 500) { - - for (i in 0 until iterations) { - disposeScoped { - val (inputBatch, labelBatch) = dataset.sampleBatch(batchSize) - val errorNetwork = this@trainClassifier before lossByLabels(labelBatch) - val forwardResults = use { errorNetwork.forwardPass(inputBatch) } - val accuracy = accuracy(forwardResults.hidden, labelBatch) - val progress = i.toFloat() / iterations - val learningRate = learningRateByProgress(progress) - val backpropResults = use { forwardResults.backpropagate(outputGradient = tensor(learningRate)) } - val crossEntropy = forwardResults.output[0] - backpropResults.descend() - println("Iteration ${i + 1}/$iterations: " + - "${accuracy.toPercentageString()}% training batch accuracy, " + - "cross entropy loss = ${crossEntropy.toRoundedString(4)}, " + - "learning rate = ${learningRate.toRoundedString(4)}") - } - } -} - -fun Backpropagatable.testClassifier(dataset: Dataset, batchSize: Int = 100): Float { - val testBatches = dataset.testBatches(batchSize) - return testBatches.withIndex().map { (i, batchPair) -> - val (inputBatch, outputBatch) = batchPair - val accuracy = accuracy(this.forwardPass(inputBatch).output, outputBatch) - println("Test batch ${i + 1}/${testBatches.size}: ${accuracy.toPercentageString()}% accuracy") - accuracy * inputBatch.shape[0] - }.sum() / dataset.inputs.size -} - -fun randomInit(size: Int) = random(-.01, .01, size) -fun randomInit(size0: Int, size1: Int) = random(-.1, .1, size0, size1) - -fun linear(inputSize: Int, outputSize: Int) = Linear(randomInit(outputSize, inputSize), randomInit(outputSize)) -fun twoLayerClassifier(dataset: Dataset, hiddenSize: Int = 64) = - linear(dataset.inputs[0].size, hiddenSize) before Relu before - linear(hiddenSize, dataset.labels[0].size) before Softmax - -fun main() { - val trainingDataset = MNIST.labeledTrainingImages() - val predictionNetwork = twoLayerClassifier(trainingDataset) - predictionNetwork.trainClassifier(trainingDataset, lossByLabels = { CrossEntropyLoss(labels = it) }) - - val testDataset = MNIST.labeledTestImages() - val averageAccuracy = predictionNetwork.testClassifier(testDataset) - println("Accuracy on the test set: ${averageAccuracy.toPercentageString()}") -} diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt deleted file mode 100644 index 8db12819f85..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.torch - -import kotlinx.cinterop.* -import platform.posix.* - -data class Dataset(val inputs: List, val labels: List) { - fun batch(indices: List): Pair { - val inputBatch = tensor(*(indices.map { inputs[it].toTypedArray() }.toTypedArray())) - val labelBatch = tensor(*(indices.map { labels[it].toTypedArray() }.toTypedArray())) - return inputBatch to labelBatch - } - - fun sampleBatch(batchSize: Int) = batch((0 until batchSize).map { randomInt(inputs.size) }) - private fun batchAt(batchIndex: Int, batchSize: Int) = - batch((0 until inputs.size).drop(batchSize + batchIndex).take(batchSize)) - - fun testBatches(batchSize: Int) = (0 until inputs.size / batchSize).map { batchAt(it, batchSize = batchSize) } -} - -/** - * Provides the MNIST labeled handwritten digit dataset, described at http://yann.lecun.com/exdb/mnist/ - */ -object MNIST { - private fun readFileData(fileName: String) = memScoped { - val path = "build/3rd-party/MNIST/$fileName" - fun fail(): Nothing = throw Error("Cannot read input file $path") - - val size = alloc().also { if (stat(path, it.ptr) != 0) fail() }.st_size.toInt() - - println("Reading $size bytes from $path...") - - val file = fopen(path, "rb") ?: fail() - try { - ByteArray(size).also { fread(it.refTo(0), 1, size.convert(), file) } - } finally { - fclose(file) - } - } - - private fun Byte.reinterpretAsUnsigned() = this.toInt().let { it + if (it < 0) 256 else 0 } - - private fun unsignedBytesToInt(bytes: List) = - bytes.withIndex().map { (i, value) -> value.reinterpretAsUnsigned().shl(8 * (3 - i)) }.sum() - - private val intSize = 4 - private fun ByteArray.getIntAt(index: Int) = - unsignedBytesToInt((index until (index + intSize)).map { this[it] }) - - private val imageLength = 28 - private val imageSize = imageLength * imageLength - - private fun ByteArray.getImageAt(index: Int) = - FloatArray(imageSize) { this[index + it].reinterpretAsUnsigned().toFloat() / 255 } - - private fun oneHot(size: Int, index: Int) = FloatArray(size) { if (it == index) 1f else 0f } - - private fun readLabels(fileName: String, totalLabels: Int = 10): List { - val data = readFileData(fileName) - val check = data.getIntAt(0) - val expectedCheck = 2049 - if (check != 2049) throw Error("File should start with int $expectedCheck, but was $check.") - - val count = data.getIntAt(4) - - val offset = 8 - - if (count + offset != data.size) throw Error("Unexpected file size: ${data.size}.") - - return (0 until count).map { oneHot(totalLabels, index = data[offset + it].reinterpretAsUnsigned()) } - } - - private fun readImages(fileName: String): List { - val data = readFileData(fileName) - val check = data.getIntAt(0) - val expectedCheck = 2051 - if (check != expectedCheck) throw Error("File should start with int $expectedCheck, but was $check.") - - val count = data.getIntAt(4) - val width = data.getIntAt(8) - val height = data.getIntAt(12) - - val offset = 16 - - if (width != imageLength) throw Error() - if (height != imageLength) throw Error() - - if (count * imageSize + offset != data.size) throw Error("Unexpected file size: ${data.size}.") - - return (0 until count).map { data.getImageAt(offset + imageSize * it) } - } - - fun labeledTrainingImages() = Dataset( - inputs = readImages("train-images-idx3-ubyte"), - labels = readLabels("train-labels-idx1-ubyte")) - - fun labeledTestImages() = Dataset( - inputs = readImages("t10k-images-idx3-ubyte"), - labels = readLabels("t10k-labels-idx1-ubyte")) -} \ No newline at end of file diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt deleted file mode 100644 index 2e94e0ed718..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.torch - -/** - * NOTE: resource management in this sample suffers from resource leaks - * and double-free bugs (see workaround in [FloatTensor.dispose]). - * - * This might mean that the entire approach for resource management in the sample is faulty. - * Please take this into account when considering reusing the same approach in your project. - * - * TODO: rework resource management. -*/ -interface Disposable { - fun dispose() -} - -open class DisposableContainer(private val disposables: MutableList = ArrayList()) : Disposable { - /** - * Creates the object and schedules its disposal for the end of the scope. - */ - fun use(create: () -> T) = create().also { disposables.add(it) } - - override fun dispose() { - for (disposable in disposables) { - disposable.dispose() - } - } -} - -fun disposeScoped(action: DisposableContainer.() -> T): T { - val scope = DisposableContainer() - - try { - return scope.action() - } finally { - scope.dispose() - } -} \ No newline at end of file diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt deleted file mode 100644 index bc07fa2a47b..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package sample.torch - -import kotlinx.cinterop.* -import torch.* - -// Defines network modules with the ability for backpropagation using both TH.h and THNN.h from the ATen library - -abstract class Backpropagatable { - abstract inner class ForwardResults(val input: Input) : DisposableContainer() { - init { - use { input } - } - - abstract val output: Output - abstract fun backpropagate(outputGradient: Output): BackpropagationResults - } - - abstract inner class BackpropagationResults( - val input: Input, - val output: Output, - val outputGradient: Output - ) : DisposableContainer() { - init { - use { input } - use { output } - use { outputGradient } - } - - abstract val inputGradient: Input - abstract fun descend() - } - - abstract fun forwardPass(input: Input): ForwardResults -} - -abstract class Module : Backpropagatable() { - abstract var parameters: Parameters - abstract fun parametersToList(parameters: Parameters): List - abstract fun parametersFromList(list: List): Parameters - private val parameterList get() = parametersToList(parameters) - - abstract operator fun invoke(input: Input): Output - abstract fun inputGradient(input: Input, outputGradient: Output, output: Output): Input - abstract fun parameterGradient(input: Input, outputGradient: Output, inputGradient: Input): Parameters - - override fun forwardPass(input: Input) = object : ForwardResults(input) { - override val output = use { this@Module(input) } - override fun backpropagate(outputGradient: Output) = - object : Backpropagatable.BackpropagationResults(input, output, outputGradient) { - override val inputGradient = use { this@Module.inputGradient(input, outputGradient, output) } - val parameterGradient = this@Module.parameterGradient(input, - outputGradient = outputGradient, inputGradient = inputGradient) - - override fun descend() = this@Module.descend(parameterGradient) - } - } - - open fun descend(parameterGradient: Parameters) { - parameters = parametersFromList(parameterList.zip( - parametersToList(parameterGradient)) { parameter, gradient -> parameter - gradient }) - } -} - -abstract class ParameterFreeModule : Module() { - override var parameters = Unit - override fun parametersToList(parameters: Unit) = emptyList() - override fun parametersFromList(list: List) = Unit - override fun parameterGradient(input: Input, outputGradient: Output, inputGradient: Input) = Unit - override fun descend(parameterGradient: Unit) {} -} - -class Chain( - val module1: Backpropagatable