/* * File: DrawASelfAvoidingRandomWalk.kt * Compilation: kotlinc -cp .:stdlib.jar DrawASelfAvoidingRandomWalk.kt * Execution: kotlin -cp .:stdlib.jar DrawASelfAvoidingRandomWalk n * where n is a positive integer * Purpose: Simulate a self-avoiding random walk on an n x n lattice * until it escapes or gets stuck in a dead end. */ import java.awt.Color const val SHORT_PAUSE = 100 fun main(args: Array) { if (args.size != 1) { println(""" | |usage: kotlin -cp .:stdlib.jar DrawASelfAvoidingRandomWalk n | where n is a positive integer | """.trimMargin()) kotlin.system.exitProcess(1) } val randGen = java.util.Random() val n = args[0].toInt() // lattice size is n x n val MIN_COORD = 0 val MAX_COORD = n-1 val D_MIN_COORD = 0.0 // MIN_COORD as a Double val D_MAX_COORD = n - 1.0 // MAX_COORD as a Double val range = MIN_COORD..MAX_COORD // this keeps track of visited intersections val visited = Array(n) { BooleanArray(n) } // set a reasonable scale, given the lattice StdDraw.setScale(D_MIN_COORD, D_MAX_COORD) // draw the lattice in gray with mildly thick pen StdDraw.setPenColor(Color.GRAY) var d = D_MIN_COORD while (d <= D_MAX_COORD) { StdDraw.line(d, D_MIN_COORD, d, D_MAX_COORD) StdDraw.line(D_MIN_COORD, d, D_MAX_COORD, d) d += 1.0 } StdDraw.setPenColor(Color.BLUE) StdDraw.setPenRadius(.01) var x = (MAX_COORD+1) / 2 /* x-coord of current position */ var y = x /* y-coord of current position */ // repeatedly take a random step, unless you've already escaped outer@ while (x in range && y in range) { if (x-1 in range && visited[x-1][y] && x+1 in range && visited[x+1][y] && y-1 in range && visited[x][y-1] && y+1 in range && visited[x][y+1]) // at dead end break // mark (x, y) as visited visited[x][y] = true val xd = x + 0.0 // x as a Double val yd = y + 0.0 // y as a Double // take a random step to unvisited neighbor inner@ do { val r = randGen.nextInt(4) when (r) { 0 -> if (x+1 !in range) break@outer else if (!visited[x+1][y]) { StdDraw.line(xd, yd, xd+1, yd) x++ break@inner } 1 -> if (x-1 !in range) break@outer else if (!visited[x-1][y]) { StdDraw.line(xd, yd, xd-1, yd) x-- break@inner } 2 -> if (y+1 !in range) break@outer else if (!visited[x][y+1]) { StdDraw.line(xd, yd, xd, yd+1) y++ break@inner } 3 -> if (y-1 !in range) break@outer else if (!visited[x][y-1]) { StdDraw.line(xd, yd, xd, yd-1) y-- break@inner } } } while (true) StdDraw.pause(SHORT_PAUSE) } }