Ant task - "longer examples" compiled and run
This commit is contained in:
+62
-39
@@ -8,52 +8,29 @@
|
|||||||
</classpath>
|
</classpath>
|
||||||
</taskdef>
|
</taskdef>
|
||||||
|
|
||||||
<path id="sourcepath.buildTools">
|
|
||||||
<dirset dir="${basedir}/build-tools">
|
|
||||||
<include name="core/src"/>
|
|
||||||
<include name="ant/src"/>
|
|
||||||
<include name="maven/src"/>
|
|
||||||
<include name="gradle/src"/>
|
|
||||||
</dirset>
|
|
||||||
</path>
|
|
||||||
|
|
||||||
<path id="classpath.buildTools">
|
|
||||||
<path refid="classpath.kotlin"/>
|
|
||||||
<fileset dir="${idea.sdk}/ant/lib" includes="*.jar"/>
|
|
||||||
</path>
|
|
||||||
|
|
||||||
<path id="dist.jars">
|
<path id="dist.jars">
|
||||||
<fileset dir="${idea.sdk}" includes="*.jar"/>
|
<fileset dir="${idea.sdk}" includes="*.jar"/>
|
||||||
<fileset dir="${basedir}/lib" includes="*.jar"/>
|
<fileset dir="${basedir}/lib" includes="*.jar"/>
|
||||||
<fileset dir="${output}" includes="*.jar"/>
|
<fileset dir="${output}" includes="*.jar"/>
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
<target name="buildToolsJar" depends="compile">
|
<presetdef name="run-java">
|
||||||
<mkdir dir ="${output}/classes/buildTools"/>
|
<java classpathref = "dist.jars" failonerror = "true">
|
||||||
<javac destdir="${output}/classes/buildTools" debug="true" debuglevel="lines,vars,source">
|
<classpath path = "${tests-dir}"/>
|
||||||
<src refid="sourcepath.buildTools"/>
|
</java>
|
||||||
<classpath refid="classpath.buildTools"/>
|
</presetdef>
|
||||||
</javac>
|
|
||||||
<jar destfile="${output}/kotlin-build-tools.jar">
|
|
||||||
<fileset dir="${output}/classes/buildTools"/>
|
|
||||||
<fileset dir="${basedir}/build-tools/ant/src" includes="**/*.xml"/>
|
|
||||||
</jar>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<macrodef name="hello-java">
|
<macrodef name="hello-java">
|
||||||
<attribute name="root"/>
|
<attribute name="root"/>
|
||||||
<attribute name="args" default=""/>
|
<attribute name="args" default=""/>
|
||||||
<attribute name="out"/>
|
<attribute name="out"/>
|
||||||
<sequential>
|
<sequential>
|
||||||
<var name = "java-out"
|
<var name = "java-out" unset = "true"/>
|
||||||
unset = "true"/>
|
<run-java outputproperty = "java-out"
|
||||||
<java classpathref = "dist.jars"
|
classname = "namespace">
|
||||||
classname = "namespace"
|
<arg line = "@{args}"/>
|
||||||
failonerror = "true"
|
</run-java>
|
||||||
outputproperty = "java-out">
|
|
||||||
<classpath path = "${tests-dir}"/>
|
|
||||||
<arg line = "@{args}"/>
|
|
||||||
</java>
|
|
||||||
<if>
|
<if>
|
||||||
<equals arg1="${java-out}" arg2="@{out}"/>
|
<equals arg1="${java-out}" arg2="@{out}"/>
|
||||||
<then>
|
<then>
|
||||||
@@ -74,21 +51,67 @@
|
|||||||
<taskdef resource = "org/jetbrains/jet/buildtools/ant/antlib.xml"
|
<taskdef resource = "org/jetbrains/jet/buildtools/ant/antlib.xml"
|
||||||
classpathref = "dist.jars"/>
|
classpathref = "dist.jars"/>
|
||||||
|
|
||||||
<delete dir = "${tests-dir}" verbose = "false" includes="**/*.class"/>
|
<delete dir = "${tests-dir}" verbose = "false" includes="**/*.class"/>
|
||||||
<kotlinc file = "@{root}/Hello.kt" destdir = "${tests-dir}"/>
|
<kotlinc destdir = "${tests-dir}" file = "@{root}/Hello.kt" />
|
||||||
<hello-java root = "@{root}" args = "@{args}" out = "@{out}"/>
|
<hello-java root = "@{root}" args = "@{args}" out = "@{out}"/>
|
||||||
|
|
||||||
<delete dir = "${tests-dir}" verbose = "false" includes="**/*.class"/>
|
<delete dir = "${tests-dir}" verbose = "false" includes="**/*.class"/>
|
||||||
<kotlinc srcdir = "@{root}" destdir = "${tests-dir}"/>
|
<kotlinc destdir = "${tests-dir}" srcdir = "@{root}" />
|
||||||
<hello-java root = "@{root}" args = "@{args}" out = "@{out}"/>
|
<hello-java root = "@{root}" args = "@{args}" out = "@{out}"/>
|
||||||
</sequential>
|
</sequential>
|
||||||
</macrodef>
|
</macrodef>
|
||||||
|
|
||||||
|
|
||||||
|
<macrodef name="longer-examples">
|
||||||
|
<sequential>
|
||||||
|
<taskdef resource = "org/jetbrains/jet/buildtools/ant/antlib.xml"
|
||||||
|
classpathref = "dist.jars"/>
|
||||||
|
|
||||||
|
<delete dir = "${tests-dir}" verbose = "false" includes="**/*.class"/>
|
||||||
|
<kotlinc destdir = "${tests-dir}" srcdir = "${basedir}/build-tools/test/longer-examples" />
|
||||||
|
|
||||||
|
<run-java classname = "bottles.namespace"/>
|
||||||
|
<run-java classname = "maze.namespace"/>
|
||||||
|
<run-java classname = "life.namespace"/>
|
||||||
|
<run-java classname = "html.namespace"/>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Creates build tools distribution jar -->
|
||||||
|
<target name="buildToolsJar" depends="compile">
|
||||||
|
<mkdir dir ="${output}/classes/buildTools"/>
|
||||||
|
<javac destdir="${output}/classes/buildTools" debug="true" debuglevel="lines,vars,source">
|
||||||
|
<src>
|
||||||
|
<dirset dir="${basedir}/build-tools">
|
||||||
|
<include name="core/src"/>
|
||||||
|
<include name="ant/src"/>
|
||||||
|
<include name="maven/src"/>
|
||||||
|
<include name="gradle/src"/>
|
||||||
|
</dirset>
|
||||||
|
</src>
|
||||||
|
<classpath>
|
||||||
|
<path refid="classpath.kotlin"/>
|
||||||
|
<fileset dir="${idea.sdk}/ant/lib" includes="*.jar"/>
|
||||||
|
</classpath>
|
||||||
|
</javac>
|
||||||
|
<jar destfile="${output}/kotlin-build-tools.jar">
|
||||||
|
<fileset dir="${output}/classes/buildTools"/>
|
||||||
|
<fileset dir="${basedir}/build-tools/ant/src" includes="**/*.xml"/>
|
||||||
|
</jar>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<!-- Tests build tools distribution jar -->
|
||||||
<target name="buildToolsTest" depends="jarRT, jar, buildToolsJar">
|
<target name="buildToolsTest" depends="jarRT, jar, buildToolsJar">
|
||||||
<hello-test root="${basedir}/build-tools/test/hello/1" out="Hello, world!"/>
|
|
||||||
|
<!-- Compiles every "Hello, World!" example and verifies the output of <java> run -->
|
||||||
|
<hello-test root="${basedir}/build-tools/test/hello/1" out="Hello, world!"/>
|
||||||
<hello-test root="${basedir}/build-tools/test/hello/2" args="Kotlin-Developer" out="Hello, Kotlin-Developer!"/>
|
<hello-test root="${basedir}/build-tools/test/hello/2" args="Kotlin-Developer" out="Hello, Kotlin-Developer!"/>
|
||||||
<hello-test root="${basedir}/build-tools/test/hello/3" args="Mickey-Mouse" out="Hello, Mickey-Mouse!"/>
|
<hello-test root="${basedir}/build-tools/test/hello/3" args="Mickey-Mouse" out="Hello, Mickey-Mouse!"/>
|
||||||
<hello-test root="${basedir}/build-tools/test/hello/4" args="IT" out="Ciao!"/>
|
<hello-test root="${basedir}/build-tools/test/hello/4" args="IT" out="Ciao!"/>
|
||||||
<hello-test root="${basedir}/build-tools/test/hello/5" args="Donald-Duck" out="Hello, Donald-Duck!"/>
|
<hello-test root="${basedir}/build-tools/test/hello/5" args="Donald-Duck" out="Hello, Donald-Duck!"/>
|
||||||
|
|
||||||
|
<!-- Compiles and runs all longer examples (99 Bottles of Beer, Maze, Life, HTML Builder) -->
|
||||||
|
<longer-examples/>
|
||||||
</target>
|
</target>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* This example implements the famous "99 Bottles of Beer" program
|
||||||
|
* See http://99-bottles-of-beer.net/
|
||||||
|
*
|
||||||
|
* The point is to print out a song with the following lyrics:
|
||||||
|
*
|
||||||
|
* The "99 bottles of beer" song
|
||||||
|
*
|
||||||
|
* 99 bottles of beer on the wall, 99 bottles of beer.
|
||||||
|
* Take one down, pass it around, 98 bottles of beer on the wall.
|
||||||
|
*
|
||||||
|
* 98 bottles of beer on the wall, 98 bottles of beer.
|
||||||
|
* Take one down, pass it around, 97 bottles of beer on the wall.
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* 2 bottles of beer on the wall, 2 bottles of beer.
|
||||||
|
* Take one down, pass it around, 1 bottle of beer on the wall.
|
||||||
|
*
|
||||||
|
* 1 bottle of beer on the wall, 1 bottle of beer.
|
||||||
|
* Take one down, pass it around, no more bottles of beer on the wall.
|
||||||
|
*
|
||||||
|
* No more bottles of beer on the wall, no more bottles of beer.
|
||||||
|
* Go to the store and buy some more, 99 bottles of beer on the wall.
|
||||||
|
*
|
||||||
|
* Additionally, you can pass the desired initial number of bottles to use (rather than 99)
|
||||||
|
* as a command-line argument
|
||||||
|
*/
|
||||||
|
package bottles
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
if (args.isEmpty) {
|
||||||
|
printBottles(99)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
printBottles(Integer.parseInt(args[0]))
|
||||||
|
}
|
||||||
|
catch (e : NumberFormatException) {
|
||||||
|
System.err?.println("You have passed '${args[0]}' as a number of bottles, " +
|
||||||
|
"but it is not a valid integral number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printBottles(bottleCount : Int) {
|
||||||
|
if (bottleCount <= 0) {
|
||||||
|
println("No bottles - no song")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
println("The \"${bottlesOfBeer(bottleCount)}\" song\n")
|
||||||
|
|
||||||
|
var bottles = bottleCount
|
||||||
|
while (bottles > 0) {
|
||||||
|
val bottlesOfBeer = bottlesOfBeer(bottles)
|
||||||
|
print("$bottlesOfBeer on the wall, $bottlesOfBeer.\nTake one down, pass it around, ")
|
||||||
|
bottles--
|
||||||
|
println("${bottlesOfBeer(bottles)} on the wall.\n")
|
||||||
|
}
|
||||||
|
println("No more bottles of beer on the wall, no more bottles of beer.\n" +
|
||||||
|
"Go to the store and buy some more, ${bottlesOfBeer(bottleCount)} on the wall.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bottlesOfBeer(count : Int) : String =
|
||||||
|
when (count) {
|
||||||
|
0 -> "no more bottles"
|
||||||
|
1 -> "1 bottle"
|
||||||
|
else -> "$count bottles"
|
||||||
|
} + " of beer"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An excerpt from the Standard Library
|
||||||
|
*/
|
||||||
|
|
||||||
|
// From the std.io package
|
||||||
|
// These are simple functions that wrap standard Java API calls
|
||||||
|
fun print(message : String) { System.out?.print(message) }
|
||||||
|
fun println(message : String) { System.out?.println(message) }
|
||||||
|
|
||||||
|
// From the std package
|
||||||
|
// This is an extension property, i.e. a property that is defined for the
|
||||||
|
// type Array<T>, but does not sit inside the class Array
|
||||||
|
val <T> Array<T>.isEmpty : Boolean get() = size == 0
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/**
|
||||||
|
* This is an example of a Type-Safe Groovy-style Builder
|
||||||
|
*
|
||||||
|
* Builders are good for declaratively describing data in your code.
|
||||||
|
* In this example we show how to describe an HTML page in Kotlin.
|
||||||
|
*
|
||||||
|
* See this page for details:
|
||||||
|
* http://confluence.jetbrains.net/display/Kotlin/Type-safe+Groovy-style+builders
|
||||||
|
*/
|
||||||
|
package html
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
val result =
|
||||||
|
html {
|
||||||
|
head {
|
||||||
|
title {+"XML encoding with Kotlin"}
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
h1 {+"XML encoding with Kotlin"}
|
||||||
|
p {+"this format can be used as an alternative markup to XML"}
|
||||||
|
|
||||||
|
// an element with attributes and text content
|
||||||
|
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
||||||
|
|
||||||
|
// mixed content
|
||||||
|
p {
|
||||||
|
+"This is some"
|
||||||
|
b {+"mixed"}
|
||||||
|
+"text. For more see the"
|
||||||
|
a(href = "http://jetbrains.com/kotlin") {+"Kotlin"}
|
||||||
|
+"project"
|
||||||
|
}
|
||||||
|
p {+"some text"}
|
||||||
|
|
||||||
|
// content generated from command-line arguments
|
||||||
|
p {
|
||||||
|
+"Command line arguments were:"
|
||||||
|
ul {
|
||||||
|
for (arg in args)
|
||||||
|
li {+arg}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Element {
|
||||||
|
fun render(builder : StringBuilder, indent : String)
|
||||||
|
|
||||||
|
fun toString() : String? {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
render(builder, "")
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextElement(val text : String) : Element {
|
||||||
|
override fun render(builder : StringBuilder, indent : String) {
|
||||||
|
builder.append("$indent$text\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Tag(val name : String) : Element {
|
||||||
|
val children = ArrayList<Element>()
|
||||||
|
val attributes = HashMap<String, String>()
|
||||||
|
|
||||||
|
protected fun initTag<T : Element>(tag : T, init : T.() -> Unit) : T {
|
||||||
|
tag.init()
|
||||||
|
children.add(tag)
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(builder : StringBuilder, indent : String) {
|
||||||
|
builder.append("$indent<$name${renderAttributes()}>\n")
|
||||||
|
for (c in children) {
|
||||||
|
c.render(builder, indent + " ")
|
||||||
|
}
|
||||||
|
builder.append("$indent</$name>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderAttributes() : String? {
|
||||||
|
val builder = StringBuilder()
|
||||||
|
for (a in attributes.keySet()) {
|
||||||
|
builder.append(" $a=\"${attributes[a]}\"")
|
||||||
|
}
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TagWithText(name : String) : Tag(name) {
|
||||||
|
fun String.plus() {
|
||||||
|
children.add(TextElement(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HTML() : TagWithText("html") {
|
||||||
|
fun head(init : Head.() -> Unit) = initTag(Head(), init)
|
||||||
|
|
||||||
|
fun body(init : Body.() -> Unit) = initTag(Body(), init)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Head() : TagWithText("head") {
|
||||||
|
fun title(init : Title.() -> Unit) = initTag(Title(), init)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Title() : TagWithText("title")
|
||||||
|
|
||||||
|
abstract class BodyTag(name : String) : TagWithText(name) {
|
||||||
|
fun b(init : B.() -> Unit) = initTag(B(), init)
|
||||||
|
fun p(init : P.() -> Unit) = initTag(P(), init)
|
||||||
|
fun h1(init : H1.() -> Unit) = initTag(H1(), init)
|
||||||
|
fun ul(init : UL.() -> Unit) = initTag(UL(), init)
|
||||||
|
fun a(href : String, init : A.() -> Unit) {
|
||||||
|
val a = initTag(A(), init)
|
||||||
|
a.href = href
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Body() : BodyTag("body")
|
||||||
|
class UL() : BodyTag("ul") {
|
||||||
|
fun li(init : LI.() -> Unit) = initTag(LI(), init)
|
||||||
|
}
|
||||||
|
|
||||||
|
class B() : BodyTag("b")
|
||||||
|
class LI() : BodyTag("li")
|
||||||
|
class P() : BodyTag("p")
|
||||||
|
class H1() : BodyTag("h1")
|
||||||
|
class A() : BodyTag("a") {
|
||||||
|
public var href : String
|
||||||
|
get() = attributes["href"]
|
||||||
|
set(value) {
|
||||||
|
attributes["href"] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun html(init : HTML.() -> Unit) : HTML {
|
||||||
|
val html = HTML()
|
||||||
|
html.init()
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
|
// An excerpt from the Standard Library
|
||||||
|
fun <K, V> Map<K, V>.set(key : K, value : V) = this.put(key, value)
|
||||||
|
|
||||||
|
fun println(message : Any?) {
|
||||||
|
System.out?.println(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun print(message : Any?) {
|
||||||
|
System.out?.print(message)
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
/**
|
||||||
|
* This is a straightforward implementation of The Game of Life
|
||||||
|
* See http://en.wikipedia.org/wiki/Conway's_Game_of_Life
|
||||||
|
*/
|
||||||
|
package life
|
||||||
|
|
||||||
|
import java.util.Collections.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A field where cells live. Effectively immutable
|
||||||
|
*/
|
||||||
|
class Field(
|
||||||
|
val width : Int,
|
||||||
|
val height : Int,
|
||||||
|
// This function tells the constructor which cells are alive
|
||||||
|
// if init(i, j) is true, the cell (i, j) is alive
|
||||||
|
init : (Int, Int) -> Boolean
|
||||||
|
) {
|
||||||
|
private val live : Array<Array<Boolean>> = Array(height) {i -> Array(width) {j -> init(i, j)}}
|
||||||
|
|
||||||
|
private fun liveCount(i : Int, j : Int)
|
||||||
|
= if (i in 0..height-1 &&
|
||||||
|
j in 0..width-1 &&
|
||||||
|
live[i][j]) 1 else 0
|
||||||
|
|
||||||
|
// How many neighbors of (i, j) are alive?
|
||||||
|
fun liveNeighbors(i : Int, j : Int) =
|
||||||
|
liveCount(i - 1, j - 1) +
|
||||||
|
liveCount(i - 1, j) +
|
||||||
|
liveCount(i - 1, j + 1) +
|
||||||
|
liveCount(i, j - 1) +
|
||||||
|
liveCount(i, j + 1) +
|
||||||
|
liveCount(i + 1, j - 1) +
|
||||||
|
liveCount(i + 1, j) +
|
||||||
|
liveCount(i + 1, j + 1)
|
||||||
|
|
||||||
|
// You can say field[i, j], and this function gets called
|
||||||
|
fun get(i : Int, j : Int) = live[i][j]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function takes the present state of the field
|
||||||
|
* and return a new field representing the next moment of time
|
||||||
|
*/
|
||||||
|
fun next(field : Field) : Field {
|
||||||
|
return Field(field.width, field.height) {i, j ->
|
||||||
|
val n = field.liveNeighbors(i, j)
|
||||||
|
if (field[i, j])
|
||||||
|
// (i, j) is alive
|
||||||
|
n in 2..3 // It remains alive iff it has 2 or 3 neighbors
|
||||||
|
else
|
||||||
|
// (i, j) is dead
|
||||||
|
n == 3 // A new cell is born if there are 3 neighbors alive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A few colony examples here */
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
// Simplistic demo
|
||||||
|
printField("***", 3)
|
||||||
|
// "Star burst"
|
||||||
|
printField("""
|
||||||
|
__*__
|
||||||
|
_***_
|
||||||
|
__*__
|
||||||
|
""", 10)
|
||||||
|
// Stable colony
|
||||||
|
printField("""
|
||||||
|
__*__
|
||||||
|
_*_*_
|
||||||
|
__*__
|
||||||
|
""", 3)
|
||||||
|
// Stable from the step 2
|
||||||
|
printField("""
|
||||||
|
__**__
|
||||||
|
__**__
|
||||||
|
__**__
|
||||||
|
""", 3)
|
||||||
|
// Oscillating colony
|
||||||
|
printField("""
|
||||||
|
__**__
|
||||||
|
__**__
|
||||||
|
__**__
|
||||||
|
__**__
|
||||||
|
""", 6)
|
||||||
|
// A fancier oscillating colony
|
||||||
|
printField("""
|
||||||
|
---------------
|
||||||
|
---***---***---
|
||||||
|
---------------
|
||||||
|
-*----*-*----*-
|
||||||
|
-*----*-*----*-
|
||||||
|
-*----*-*----*-
|
||||||
|
---***---***---
|
||||||
|
---------------
|
||||||
|
---***---***---
|
||||||
|
-*----*-*----*-
|
||||||
|
-*----*-*----*-
|
||||||
|
-*----*-*----*-
|
||||||
|
---------------
|
||||||
|
---***---***---
|
||||||
|
---------------
|
||||||
|
""", 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTILITIES
|
||||||
|
|
||||||
|
fun printField(s : String, steps : Int) {
|
||||||
|
var field = makeField(s)
|
||||||
|
for (step in 1..steps) {
|
||||||
|
println("Step: $step")
|
||||||
|
for (i in 0..field.height-1) {
|
||||||
|
for (j in 0..field.width-1) {
|
||||||
|
print(if (field[i, j]) "*" else " ")
|
||||||
|
}
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
field = next(field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun makeField(s : String) : Field {
|
||||||
|
val lines = s.split("\n").sure()
|
||||||
|
val w = max<String?>(lines.toList(), comparator<String?> {o1, o2 ->
|
||||||
|
val l1 : Int = o1?.size ?: 0
|
||||||
|
val l2 = o2?.size ?: 0
|
||||||
|
l1 - l2
|
||||||
|
}).sure()
|
||||||
|
val data = Array(lines.size) {Array(w.size) {false}}
|
||||||
|
|
||||||
|
// workaround
|
||||||
|
for (i in data.indices) {
|
||||||
|
data[i] = Array(w.size) {false}
|
||||||
|
for (j in data[i].indices)
|
||||||
|
data[i][j] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for (line in lines.indices) {
|
||||||
|
for (x in lines[line].indices) {
|
||||||
|
val c = lines[line].sure()[x]
|
||||||
|
data[line][x] = c == '*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Field(w.size, lines.size) {i, j -> data[i][j]}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An excerpt from the Standard Library
|
||||||
|
val String?.indices : IntRange get() = IntRange(0, this.sure().size)
|
||||||
|
|
||||||
|
fun <K, V> Map<K, V>.set(k : K, v : V) { put(k, v) }
|
||||||
|
|
||||||
|
fun comparator<T> (f : (T, T) -> Int) : Comparator<T> = object : Comparator<T> {
|
||||||
|
override fun compare(o1 : T, o2 : T) : Int = f(o1, o2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun println(message : Any?) {
|
||||||
|
System.out?.println(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun print(message : Any?) {
|
||||||
|
System.out?.print(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
val <T> Array<T>.isEmpty : Boolean get() = size == 0
|
||||||
|
|
||||||
|
fun String.split(s : String) = (this as java.lang.String).split(s)
|
||||||
|
|
||||||
|
val String.size : Int
|
||||||
|
get() = length
|
||||||
|
|
||||||
|
fun <T, C: Collection<T>> Array<T>.to(result: C) : C {
|
||||||
|
for (elem in this)
|
||||||
|
result.add(elem)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Array<T>.toList() : List<T> = this.to(ArrayList<T>())
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/**
|
||||||
|
* Let's Walk Through a Maze.
|
||||||
|
*
|
||||||
|
* Imagine there is a maze whose walls are the big 'O' letters.
|
||||||
|
* Now, I stand where a big 'I' stands and some cool prize lies
|
||||||
|
* somewhere marked with a '$' sign. Like this:
|
||||||
|
*
|
||||||
|
* OOOOOOOOOOOOOOOOO
|
||||||
|
* O O
|
||||||
|
* O$ O O
|
||||||
|
* OOOOO O
|
||||||
|
* O O
|
||||||
|
* O OOOOOOOOOOOOOO
|
||||||
|
* O O I O
|
||||||
|
* O O
|
||||||
|
* OOOOOOOOOOOOOOOOO
|
||||||
|
*
|
||||||
|
* I want to get the prize, and this program helps me do so as soon
|
||||||
|
* as I possibly can by finding a shortest path through the maze.
|
||||||
|
*/
|
||||||
|
package maze
|
||||||
|
|
||||||
|
import java.util.Collections.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function looks for a path from max.start to maze.end through
|
||||||
|
* free space (a path does not go through walls). One can move only
|
||||||
|
* straightly up, down, left or right, no diagonal moves allowed.
|
||||||
|
*/
|
||||||
|
fun findPath(maze : Maze) : List<#(Int, Int)>? {
|
||||||
|
val previous = HashMap<#(Int, Int), #(Int, Int)>
|
||||||
|
|
||||||
|
val queue = LinkedList<#(Int, Int)>
|
||||||
|
val visited = HashSet<#(Int, Int)>
|
||||||
|
|
||||||
|
queue.offer(maze.start)
|
||||||
|
visited.add(maze.start)
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
val cell = queue.poll()
|
||||||
|
if (cell == maze.end) break
|
||||||
|
|
||||||
|
for (newCell in maze.neighbors(cell._1, cell._2)) {
|
||||||
|
if (newCell in visited) continue
|
||||||
|
previous[newCell] = cell
|
||||||
|
queue.offer(newCell)
|
||||||
|
visited.add(cell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous[maze.end] == null) return null
|
||||||
|
|
||||||
|
val path = ArrayList<#(Int, Int)>()
|
||||||
|
var current = previous[maze.end]
|
||||||
|
while (current != maze.start) {
|
||||||
|
path.add(0, current)
|
||||||
|
current = previous[current]
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find neighbors of the (i, j) cell that are not walls
|
||||||
|
*/
|
||||||
|
fun Maze.neighbors(i : Int, j : Int) : List<#(Int, Int)> {
|
||||||
|
val result = ArrayList<#(Int, Int)>
|
||||||
|
addIfFree(i - 1, j, result)
|
||||||
|
addIfFree(i, j - 1, result)
|
||||||
|
addIfFree(i + 1, j, result)
|
||||||
|
addIfFree(i, j + 1, result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Maze.addIfFree(i : Int, j : Int, result : List<#(Int, Int)>) {
|
||||||
|
if (i !in 0..height-1) return
|
||||||
|
if (j !in 0..width-1) return
|
||||||
|
if (walls[i][j]) return
|
||||||
|
|
||||||
|
result.add(#(i, j))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data class that represents a maze
|
||||||
|
*/
|
||||||
|
class Maze(
|
||||||
|
// Number or columns
|
||||||
|
val width : Int,
|
||||||
|
// Number of rows
|
||||||
|
val height : Int,
|
||||||
|
// true for a wall, false for free space
|
||||||
|
val walls : Array<out Array<out Boolean>>,
|
||||||
|
// The starting point (must not be a wall)
|
||||||
|
val start : #(Int, Int),
|
||||||
|
// The target point (must not be a wall)
|
||||||
|
val end : #(Int, Int)
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A few maze examples here */
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
printMaze("I $")
|
||||||
|
printMaze("I O $")
|
||||||
|
printMaze("""
|
||||||
|
O $
|
||||||
|
O
|
||||||
|
O
|
||||||
|
O
|
||||||
|
O I
|
||||||
|
""")
|
||||||
|
printMaze("""
|
||||||
|
OOOOOOOOOOO
|
||||||
|
O $ O
|
||||||
|
OOOOOOO OOO
|
||||||
|
O O
|
||||||
|
OOOOO OOOOO
|
||||||
|
O O
|
||||||
|
O OOOOOOOOO
|
||||||
|
O OO
|
||||||
|
OOOOOO IO
|
||||||
|
""")
|
||||||
|
printMaze("""
|
||||||
|
OOOOOOOOOOOOOOOOO
|
||||||
|
O O
|
||||||
|
O$ O O
|
||||||
|
OOOOO O
|
||||||
|
O O
|
||||||
|
O OOOOOOOOOOOOOO
|
||||||
|
O O I O
|
||||||
|
O O
|
||||||
|
OOOOOOOOOOOOOOOOO
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTILITIES
|
||||||
|
|
||||||
|
fun printMaze(str : String) {
|
||||||
|
val maze = makeMaze(str)
|
||||||
|
|
||||||
|
println("Maze:")
|
||||||
|
val path = findPath(maze)
|
||||||
|
for (i in 0..maze.height - 1) {
|
||||||
|
for (j in 0..maze.width - 1) {
|
||||||
|
val cell = #(i, j)
|
||||||
|
print(
|
||||||
|
if (maze.walls[i][j]) "O"
|
||||||
|
else if (cell == maze.start) "I"
|
||||||
|
else if (cell == maze.end) "$"
|
||||||
|
else if (path != null && path.contains(cell)) "~"
|
||||||
|
else " "
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
println("Result: " + if (path == null) "No path" else "Path found")
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A maze is encoded in the string s: the big 'O' letters are walls.
|
||||||
|
* I stand where a big 'I' stands and the prize is marked with
|
||||||
|
* a '$' sign.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* OOOOOOOOOOOOOOOOO
|
||||||
|
* O O
|
||||||
|
* O$ O O
|
||||||
|
* OOOOO O
|
||||||
|
* O O
|
||||||
|
* O OOOOOOOOOOOOOO
|
||||||
|
* O O I O
|
||||||
|
* O O
|
||||||
|
* OOOOOOOOOOOOOOOOO
|
||||||
|
*/
|
||||||
|
fun makeMaze(s : String) : Maze {
|
||||||
|
val lines = s.split("\n").sure()
|
||||||
|
val w = max<String?>(lines.toList(), comparator<String?> {o1, o2 ->
|
||||||
|
val l1 : Int = o1?.size ?: 0
|
||||||
|
val l2 = o2?.size ?: 0
|
||||||
|
l1 - l2
|
||||||
|
}).sure()
|
||||||
|
val data = Array<Array<Boolean>>(lines.size) {Array<Boolean>(w.size) {false}}
|
||||||
|
|
||||||
|
var start : #(Int, Int)? = null
|
||||||
|
var end : #(Int, Int)? = null
|
||||||
|
|
||||||
|
for (line in lines.indices) {
|
||||||
|
for (x in lines[line].indices) {
|
||||||
|
val c = lines[line].sure()[x]
|
||||||
|
data[line][x] = c == 'O'
|
||||||
|
when (c) {
|
||||||
|
'I' -> start = #(line, x)
|
||||||
|
'$' -> end = #(line, x)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == null) {
|
||||||
|
throw IllegalArgumentException("No starting point in the maze (should be indicated with 'I')")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == null) {
|
||||||
|
throw IllegalArgumentException("No goal point in the maze (should be indicated with a '$' sign)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return Maze(w.size, lines.size, data, start.sure(), end.sure())
|
||||||
|
}
|
||||||
|
|
||||||
|
// An excerpt from the Standard Library
|
||||||
|
val String?.indices : IntRange get() = IntRange(0, this.sure().size)
|
||||||
|
|
||||||
|
val String.size : Int
|
||||||
|
get() = length
|
||||||
|
|
||||||
|
fun <K, V> Map<K, V>.set(k : K, v : V) { put(k, v) }
|
||||||
|
|
||||||
|
fun comparator<T> (f : (T, T) -> Int) : Comparator<T> = object : Comparator<T> {
|
||||||
|
override fun compare(o1 : T, o2 : T) : Int = f(o1, o2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.split(s : String) = (this as java.lang.String).split(s)
|
||||||
|
|
||||||
|
fun println(message : Any?) {
|
||||||
|
System.out?.println(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun print(message : Any?) {
|
||||||
|
System.out?.print(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, C: Collection<T>> Array<T>.to(result: C) : C {
|
||||||
|
for (elem in this)
|
||||||
|
result.add(elem)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Array<T>.toList() : List<T> = this.to(ArrayList<T>())
|
||||||
Reference in New Issue
Block a user