Skip to content

Instantly share code, notes, and snippets.

@jorgecc
Created January 8, 2019 01:17
Show Gist options
  • Save jorgecc/b95f421a5bdedea3e510f1584e25461d to your computer and use it in GitHub Desktop.
Save jorgecc/b95f421a5bdedea3e510f1584e25461d to your computer and use it in GitHub Desktop.
amazing original
100 ' NAME: AMAZING***
105 '
110 ' BY: Jack Hauber and S. J. Garland on 12/13/72
115 '
120 ' DESCRIPTION: Constructs a maze of any size the user wishes (up
125 ' to 25 rows by 23 columns). Each maze is unique and guaranteed
130 ' to have only one solution.
135 '
140 ' INSTRUCTIONS: Type "RUN" for complete instructions.
145 '
150 ' CATEGORY: DEMONS***
155 '
160 ' LANGUAGE: BASIC
165 '
170 ' INDEX LINE:
175 ' |Constructs unique, 1 solution |maze
180 '
185 '
220 RANDOMIZE
230 PRINT "THIS PROGRAM WILL PRINT A DIFFERENT MAZE EACH TIME IT IS"
240 PRINT "RUN. THERE WILL BE A UNIQUE PATH THROUGH THE MAZE. YOU"
250 PRINT "CAN CHOOSE ANY DIMENSIONS FOR THE MAZE UP TO 25 SQUARES"
260 PRINT "LONG AND 23 SQUARES WIDE."
270 PRINT
280 PRINT "WHAT ARE YOUR LENGTH AND WIDTH (E. G. 13,10)";
290 INPUT R9, C9
300 DIM W(25,23), V(25,23)
310 LET N9 = R9*C9
320 MAT W = ZER(R9,C9) 'KEEPS TRACK OF SQUARES VISITED
330 MAT V = ZER(R9,C9) 'AND THEIR RIGHT, BOTTOM WALLS
340 LET B = 0 'FLAG NO EXIT TO BOTTOM YET
350 REM FIND SQUARE IN WHICH TO START
360 LET F = INT(RND*C9+1)
370 PRINT 'PRINT TOP BORDER
380 FOR C = 1 TO C9
390 IF C = F THEN 420
400 PRINT ":--";
410 GOTO 430
420 PRINT ": ";
430 NEXT C
440 PRINT ":"
450 LET R = 1 'START IN FIRST ROW
460 LET C = F 'AND COLUMN UNDER HOLE IN BORDER
470 LET N = 1 'COUNT OF SQUARES VISITED
480 LET W(R,C) = N
490 '
500 ' A CORRIDOR IS CONSTRUCTED BY MOVING IN A RANDOM DIRECTION FROM
510 ' THE CURRENT SQUARE TO SOME SQUARE THAT HAS NOT BEEN VISITED
520 ' YET AND ERASING THE WALL BETWEEN THE TWO SQUARES. IF NO SUCH
530 ' MOVE IS POSSIBLE, A SIDE CORRIDOR IS STARTED IN SOME SQUARE
540 ' ALREADY VISITED WHICH IS ADJACENT TO AN UNVISITED SQUARE. ONLY
550 ' ONE EXIT TO THE BOTTOM OF THE MAZE IS ALLOWED.
560 '
570 REM MAKE LIST OF UNBLOCKED DIRECTIONS
580 LET D = 0
590 REM CAN WE GO LEFT
600 IF C = 1 THEN 640 'NO, ON BORDER
610 IF W(R,C-1) > 0 THEN 640 'NO, SQUARE USED ALREADY
620 LET D = D+1 'YES, ADD "LEFT" TO LIST
630 LET D(D) = 1
640 REM CAN WE GO RIGHT
650 IF C = C9 THEN 690 'NO, ON BORDER
660 IF W(R,C+1) > 0 THEN 690 'NO, SQUARE USED ALREADY
670 LET D = D+1 'YES, ADD "RIGHT" TO LIST
680 LET D(D) = 2
690 REM CAN WE GO UP
700 IF R = 1 THEN 740 'NO, ON BORDER
710 IF W(R-1,C) > 0 THEN 740 'NO, SQUARE USED ALREADY
720 LET D = D+1 'YES, ADD "UP" TO LIST
730 LET D(D) = 3
740 REM CAN WE GO DOWN
750 IF R < R9 THEN 780 'MAYBE, NOT ON BORDER
760 IF B = 1 THEN 810 'NO, ALREADY HAVE EXIT TO BOTTOM
770 GOTO 790 'YES, ALLOW EXIT TO BOTTOM
780 IF W(R+1,C) > 0 THEN 810 'NO, SQUARE USED ALREADY
790 LET D = D+1 'YES, ADD "DOWN" TO LIST
800 LET D(D) = 4
810 REM CHOOSE DIRECTION
820 IF D = 0 THEN 1090 'ALL DIRECTIONS BLOCKED
830 LET X = INT(D*RND+1) 'PICK RANDOM DIRECTION
840 ON D(X) GOTO 850,890,930,970
850 REM GO LEFT
860 LET C = C-1
870 LET V(R,C) = 2 'NEW SQUARE HAS ONLY BOTTOM WALL
880 GOTO 1030
890 REM GO RIGHT
900 LET V(R,C) = V(R,C) + 2 'ERASE RIGHT WALL OF THIS SQUARE
910 LET C = C+1
920 GOTO 1030
930 REM GO UP
940 LET R = R-1
950 LET V(R,C) = 1 'NEW SQUARE HAS ONLY RIGHT WALL
960 GOTO 1030
970 REM GO DOWN
980 LET V(R,C) = V(R,C) + 1 'ERASE BOTTOM WALL OF THIS SQUARE
990 LET R = R+1
1000 IF R <= R9 THEN 1030 'STILL IN MAZE
1010 LET B = 1 'FLAG EXIT TO BOTTOM
1020 GOTO 1140 'AND GO VISIT OTHER SQUARES
1030 REM MARK SQUARE AS USED
1040 LET N = N+1
1050 LET W(R,C) = N
1060 IF N < N9 THEN 570
1070 REM DONE
1080 GOTO 1180
1090 REM RESTART IN USED SQUARE ADJACENT TO UNUSED SQUARE
1100 LET C = C+1
1110 IF C <= C9 THEN 1160
1120 LET R = R+1
1130 IF R <= R9 THEN 1150
1140 LET R = 1
1150 LET C = 1
1160 IF W(R,C) > 0 THEN 570
1170 GOTO 1100
1180 REM PRINT OUT MAZE
1190 FOR R = 1 TO R9
1200 PRINT "I";
1210 FOR C = 1 TO C9
1220 IF V(R,C) < 2 THEN 1250
1230 PRINT " ";
1240 GOTO 1260
1250 PRINT " I";
1260 NEXT C
1270 PRINT
1280 FOR C = 1 TO C9
1290 IF MOD(V(R,C),2) = 0 THEN 1320
1300 PRINT ": ";
1310 GOTO 1330
1320 PRINT ":--";
1330 NEXT C
1340 PRINT ":"
1350 NEXT R
1360 END
@jbaraga
Copy link

jbaraga commented Dec 18, 2019

I have been translating vintage BASIC games into Swift. Amazing was very difficult to understand, until I found this version. I was able to deduce the algorithm. Sorry, I am not proficient with GitHub, here is my code:

` //MARK:-Generate and print maze
private func generateMaze(width: Int, height: Int) {

    struct Square {
        var hasRightWall = true
        var hasBottomWall = true
        var hasBeenVisited = false
        
        var hasNotBeenVisited: Bool {
            return !hasBeenVisited
        }
        
        mutating func eraseRightWall() {
            self.hasRightWall = false
        }
        
        mutating func eraseBottomWall() {
            self.hasBottomWall = false
        }
        
        mutating func markVisited() {
            self.hasBeenVisited = true
        }
    }
    
    enum Direction {
        case left
        case right
        case up
        case down
    }
    
    let numberOfSquares = width * height
    var squares: [[Square]] = Array(repeating: Array(repeating: Square(), count: width), count: height)
    
    var isThereAnExit = false
    var row = 0
    var column = 0
    var squaresVisited = 1
    
    //Enter maze at random column
    let entryColumn = rnd(width)
    column = entryColumn
    squares[row][column].markVisited()
    
    /*A CORRIDOR IS CONSTRUCTED BY MOVING IN A RANDOM DIRECTION FROM THE CURRENT SQUARE TO SOME SQUARE THAT HAS NOT BEEN VISITED YET AND ERASING THE WALL BETWEEN THE TWO SQUARES. IF NO SUCH MOVE IS POSSIBLE, A SIDE CORRIDOR IS STARTED IN SOME SQUARE ALREADY VISITED WHICH IS ADJACENT TO AN UNVISITED SQUARE. ONLY ONE EXIT TO THE BOTTOM OF THE MAZE IS ALLOWED.*/
    
    //Moves left to right, up to down from current square in raster fashion
    func moveToNextSquare() {
        column += 1
        if column == width {
            column = 0
            row += 1
            if row == height {
                row = 0
            }
        }
    }

    while squaresVisited < numberOfSquares || !isThereAnExit {
        //MAKE LIST OF UNBLOCKED DIRECTIONS
        var allowedDirections = [Direction]()
        
        //Left
        if column > 0 && squares[row][column - 1].hasNotBeenVisited { allowedDirections.append(.left) }
        
        //Right
        if column < width - 1 && squares[row][column + 1].hasNotBeenVisited { allowedDirections.append(.right) }
        
        //Up
        if row > 0 && squares[row - 1][column].hasNotBeenVisited { allowedDirections.append(.up) }
        
        //Down - allow for exit
        if row < height - 1 {
            if squares[row + 1][column].hasNotBeenVisited { allowedDirections.append(.down) }
        } else {
            //At bottom row - allow for exit through bottom
            if !isThereAnExit { allowedDirections.append(.down) }
        }
        
        if allowedDirections.count > 0 {
            //Pick random direction from allowed directions
            let x = rnd(allowedDirections.count)
            let direction = allowedDirections[x]
            
            switch direction {
            case .left:
                column -= 1
                squares[row][column].eraseRightWall()
            case .right:
                squares[row][column].eraseRightWall()
                column += 1
            case .up:
                row -= 1
                squares[row][column].eraseBottomWall()
            case .down:
                squares[row][column].eraseBottomWall()
                row += 1
            }
            
            if row < height {
                //Still in maze. Mark square as used and increment counter
                squares[row][column].markVisited()
                squaresVisited += 1
            } else {
                //Exited bottom
                isThereAnExit = true
                //Go visit other squares, starting at origin (0,0)
                column = 0
                row = 0
                //Raster scan to the first used square
                while squares[row][column].hasNotBeenVisited {
                    moveToNextSquare()
                }
            }
        } else {
            //All directions blocked. Restart in next used square to right and below,
            //raster scan - from square to right of current position (column, row)
            moveToNextSquare()
            while squares[row][column].hasNotBeenVisited {
                moveToNextSquare()
            }
        }
    }
    
    //Print out maze
    //Print top line with entry
    for i in 0..<width {
        i == entryColumn ? print(".  ") : print(".--")
    }
    println(".")
    
    //Print remainder of maze
    for rowOfSquares in squares {
        //Print vertical walls
        print("I")
        for square in rowOfSquares {
            square.hasRightWall ? print("  I") : print("   ")
        }
        println()
        
        //Print horizontal walls
        for square in rowOfSquares {
            square.hasBottomWall ? print(":--") : print(":  ")
        }
        println(".")
    }
}

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment