/* * File: SelfAvoidingRandomWalk.kt * Compilation: kotlinc -cp .:stdlib.jar SelfAvoidingRandomWalk.kt * Execution: kotlin -cp .:stdlib.jar SelfAvoidingRandomWalk n t * where n and t are positive integers * Purpose: Do t trials of self-avoiding random walk on an n x n * lattice. Each trial ends either in an escape or getting stuck * in a dead end. */ import java.awt.Color const val SHORT_PAUSE = 100 val randGen = java.util.Random() fun takeAWalk(maxCoord: Int): Int { val dMaxCoord = maxCoord.toDouble() // maxCoord as a Double // this keeps track of visited intersections val visited = Array(maxCoord+1) { BooleanArray(maxCoord+1) } val range = 0..maxCoord StdDraw.clear(Color.WHITE) // draw the lattice in gray with mildly thick pen StdDraw.setPenColor(Color.GRAY) StdDraw.setPenRadius() var d = 0.0 while (d <= dMaxCoord) { StdDraw.line(d, 0.0, d, dMaxCoord) StdDraw.line(0.0, d, dMaxCoord, d) d += 1.0 } StdDraw.setPenColor(Color.BLUE) StdDraw.setPenRadius(.01) var x = (maxCoord+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]) { // dead end return 1 } // 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 an unvisited neighboring point inner@ do { var 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) } // escape return 0 } const val LONG_PAUSE = 2000 fun main(args: Array) { if (args.size != 2) { println(""" | |usage: kotlin -cp .:stdlib.jar SelfAvoidingRandomWalk n t | where n and t are positive integers | | This program simulates t trials of taking a self-avoiding random | walk starting from the center of an n x n lattice until it escapes | from the lattice or gets stuck in a dead end. It then prints out | the percentage of trials that result in a dead end. | """.trimMargin()) kotlin.system.exitProcess(1) } val n = args[0].toInt() // lattice size is n x n val trials = args[1].toInt() // number of trials var numDeadEnds = 0 // set a reasonable scale, given the lattice StdDraw.setScale(0.0, n-1.0) repeat (trials) { numDeadEnds += takeAWalk(n-1) StdDraw.pause(LONG_PAUSE) } println("%.2f%% dead ends.".format(100.0 * numDeadEnds / trials)) }