object Maze { def main() : Unit = { /* prints a maze of size 20x20 */ println(new MazeArray().init(20).printMaze()); } } class MazeArray { var size : Int; var prng : PseudoRandomNumberGenerator; var walls : Int[]; var wallCount : Int; var vertOffset : Int; var wallIDs : Int[]; var cells : Int[]; var cellCount : Int; var pipeChar : String; var horzChar : String; var plusChar : String; var t1Char : String; var t2Char : String; var t3Char : String; var t4Char : String; var l1Char : String; var l2Char : String; var l3Char : String; var l4Char : String; var i1Char : String; var i2Char : String; var i3Char : String; var i4Char : String; var arrBdyChar : String; var arrTipChar : String; def init(sze : Int) : MazeArray = { var i : Int; var dummy : Bool; // Drawing characters. I use Unicode, but you may want to replace that by // something else if it breaks (note that scala.io.Source handles it just // fine). Use the alternatives otherwise. pipeChar = "┃"; // "|"; horzChar = "━"; // "-"; plusChar = "╋"; // "+"; t1Char = "┳"; // "+"; t2Char = "┫"; // "+"; t3Char = "┻"; // "+"; t4Char = "┣"; // "+"; l1Char = "┗"; // "+"; l2Char = "┏"; // "+"; l3Char = "┓"; // "+"; l4Char = "┛"; // "+"; i1Char = "╻"; // "+"; i2Char = "╸"; // "+"; i3Char = "╹"; // "+"; i4Char = "╺"; // "+"; arrBdyChar = " "; // "="; arrTipChar = " "; // ">"; size = sze; prng = new PseudoRandomNumberGenerator().init(); wallCount = 2 * size * (size - 1); walls = new Int[wallCount]; vertOffset = wallCount / 2; wallIDs = new Int[wallCount]; cellCount = size * size; cells = new Int[cellCount]; i = 0; while (i < wallCount) { walls[i] = 1; wallIDs[i] = i; i = i + 1; } i = 0; while (i < cellCount) { cells[i] = i; i = i + 1; } wallIDs = this.shuffleArray(wallIDs); i = 0; while(!this.allMerged()) { dummy = this.destroyIfNotConnected(wallIDs[i]); i = i + 1; } return this; } def cellRepresentative(cid : Int) : Int = { var ptr : Int; ptr = cid; while(!(cells[ptr] == ptr)) { ptr = cells[ptr]; } cells[cid] = ptr; // speeds up further lookups. return ptr; } def setRepresentative(cid : Int, repr : Int) : Bool = { cells[this.cellRepresentative(cid)] = this.cellRepresentative(repr); return true; } def allMerged() : Bool = { var i : Int; i = 1; while(i < cellCount && this.cellRepresentative(i) == this.cellRepresentative(0)) { i = i + 1; } return i == cellCount; } def cellID(row : Int, col : Int) : Int = { return (row * size) + col; } def cellRow(cid : Int) : Int = { return cid / size; } def cellCol(cid : Int) : Int = { return prng.mod(cid, size); } def wallID(horizontal : Bool, row : Int, col : Int) : Int = { var toRet : Int; if(horizontal) { toRet = row * size + col; } else { toRet = row * (size - 1) + col + vertOffset; } return toRet; } def wallRow(wid : Int) : Int = { var toRet : Int; if(wid < vertOffset) { toRet = wid / size; } else { toRet = (wid - vertOffset) / (size - 1); } return toRet; } def wallCol(wid : Int) : Int = { var toRet : Int; if(wid < vertOffset) { toRet = prng.mod(wid, size); } else { toRet = prng.mod(wid - vertOffset, size - 1); } return toRet; } def cellOneOfWall(wid : Int) : Int = { return this.cellID(this.wallRow(wid), this.wallCol(wid)); } def cellTwoOfWall(wid : Int) : Int = { var toRet : Int; if(wid < vertOffset) { toRet = this.cellID(this.wallRow(wid) + 1, this.wallCol(wid)); } else { toRet = this.cellID(this.wallRow(wid), this.wallCol(wid) + 1); } return toRet; } def destroyIfNotConnected(wid : Int) : Bool = { var c1 : Int; var c2 : Int; var dummy : Bool; c1 = this.cellOneOfWall(wid); c2 = this.cellTwoOfWall(wid); if(!(this.cellRepresentative(c1) == this.cellRepresentative(c2))) { walls[wid] = 0; dummy = this.setRepresentative(c1, c2); } return true; } def printMaze() : String = { var i : Int; var j : Int; var str : String; var c : String; var w1 : Bool; var w2 : Bool; var w3 : Bool; var w4 : Bool; i = 0; j = 0; str = ""; c = ""; w1 = false; w2 = false; w3 = false; w4 = false; // top row i = 0; str = " " + l2Char; while (i < size) { str = str + horzChar + horzChar + horzChar; if(i == size - 1) str = str + l3Char; else if(0 < walls[this.wallID(false, 0, i)]) str = str + t1Char; else str = str + horzChar; i = i + 1; } println(str); i = 0; str = ""; c = ""; while (i < size) { // the vertical walls if(i == 0) str = " " + arrBdyChar + arrBdyChar + arrBdyChar + arrTipChar + " "; else str = " " + pipeChar + " "; j = 0; while (j < size - 1) { if (walls[this.wallID(false, i, j)] == 1) c = pipeChar; else c = " "; str = str + c; if(!(i == (size - 1) && j == (size - 2))) str = str + " "; else str = str + " " + arrBdyChar; j = j + 1; } if (!(i == (size - 1))) str = str + pipeChar; else str = str + arrBdyChar + arrBdyChar + arrTipChar; println(str); // the horizontal walls if(i < (size-1)) { str = " "; if(walls[this.wallID(true, i, 0)] == 1) str = str + t4Char; else str = str + pipeChar; j = 0; while (j < size) { if (walls[this.wallID(true, i, j)] == 1) c = horzChar + horzChar + horzChar; else c = " "; str = str + c; if(j < size - 1) { w1 = (walls[this.wallID(false, i, j)] == 1); // up w2 = (walls[this.wallID(true, i, j + 1)] == 1); // right w3 = (walls[this.wallID(false, i + 1, j)] == 1); // down w4 = (walls[this.wallID(true, i, j)] == 1); // left if(w1 && w2 && w3 && w4) str = str + plusChar; else if(w1 && w2 && w3 && !w4) str = str + t4Char; else if(w1 && w2 && !w3 && w4) str = str + t3Char; else if(w1 && !w2 && w3 && w4) str = str + t2Char; else if(!w1 && w2 && w3 && w4) str = str + t1Char; else if(w1 && !w2 && w3 && !w4) str = str + pipeChar; else if(!w1 && w2 && !w3 && w4) str = str + horzChar; else if(w1 && w2 && !w3 && !w4) str = str + l1Char; else if(!w1 && w2 && w3 && !w4) str = str + l2Char; else if(!w1 && !w2 && w3 && w4) str = str + l3Char; else if(w1 && !w2 && !w3 && w4) str = str + l4Char; else if(w1 && !w2 && !w3 && !w4) str = str + i3Char; else if(!w1 && w2 && !w3 && !w4) str = str + i4Char; else if(!w1 && !w2 && w3 && !w4) str = str + i1Char; else if(!w1 && !w2 && !w3 && w4) str = str + i2Char; } else if(walls[this.wallID(true, i, size - 1)] == 1) str = str + t2Char; else str = str + pipeChar; j = j + 1; } println(str); } i = i + 1; } // top row i = 0; str = " " + l1Char; while (i < size) { str = str + horzChar + horzChar + horzChar; if(i == size - 1) str = str + l4Char; else if(0 < walls[this.wallID(false, size-1, i)]) str = str + t3Char; else str = str + horzChar; i = i + 1; } println(str); return " ** Enjoy ! **"; } // only works for arrays with positive numbers. def shuffleArray(arr : Int[]) : Int[] = { var newarr : Int[]; var i : Int; var j : Int; newarr = new Int[arr.length]; i = 0; while(i < newarr.length) { newarr[i] = 0 - 1; i = i + 1; } i = 0; while(i < arr.length) { j = prng.getInt(0, arr.length); while(!(newarr[j] == 0 - 1)) { j = j + 1; if (j == newarr.length) j = 0; } newarr[j] = arr[i]; i = i + 1; } return newarr; } } class PseudoRandomNumberGenerator { var a : Int; var b : Int; def init() : PseudoRandomNumberGenerator = { a = 12345; // put whatever you like in here b = 67890; return this; } def getInt(min : Int, max : Int) : Int = { var posInt : Int; posInt = this.nextInt(); if(posInt < 0) posInt = 0 - posInt; return min + (this.mod(posInt, max - min)); } def mod(i : Int, j : Int) : Int = { return i - (i / j * j); } def nextInt() : Int = { b = 36969 * ((b * 65536) / 65536) + (b / 65536); a = 18000 * ((a * 65536) / 65536) + (a / 65536); return (b * 65536) + a; } }