Maze generation: Difference between revisions

Content added Content deleted
m (→‎{{header|Tcl}}: tinkering)
m (→‎{{header|Tcl}}: more tinkering, making this code a class)
Line 234: Line 234:
=={{header|Tcl}}==
=={{header|Tcl}}==
{{trans|Javascript}}
{{trans|Javascript}}
<lang tcl>package require Tcl 8.5
<lang tcl>package require TclOO; # Or Tcl 8.6

# Helper to pick a random number
# Helper to pick a random number
proc rand n {expr {int(rand() * $n)}}
proc rand n {expr {int(rand() * $n)}}
# Helper to pick a random element of a list
# Helper to pick a random element of a list
proc pick list {
proc pick list {lindex $list [rand [llength $list]]}
lindex $list [rand [llength $list]]
}
# Helper _function_ to index into a list of lists
# Helper _function_ to index into a list of lists
proc tcl::mathfunc::idx {v x y} {lindex $v $x $y}
proc tcl::mathfunc::idx {v x y} {lindex $v $x $y}
# Helper to write into a list of lists (with offsets)
proc unvisited= {x y value} {
upvar 1 unvisited u
lset u [expr {$x+1}] [expr {$y+1}] $value
}


oo::class create maze {
# Maze builder; returns a dictionary
variable x y horiz verti
proc maze {y x} {
constructor {width height} {
set n [expr {$x * $y - 1}]
set y $width
if {$n < 0} {error "illegal maze dimensions"}
set x $height
set horiz [set verti [lrepeat [expr {$x+1}] [lrepeat [expr {$y+1}] 0]]]

set unvisited [lrepeat [expr {$x+2}] [lrepeat [expr {$y+2}] 0]]
lappend stack [set here [list [rand $x] [rand $y]]]
set n [expr {$x * $y - 1}]
for {set j 0} {$j < $x} {incr j} {
if {$n < 0} {error "illegal maze dimensions"}
for {set k 0} {$k < $y} {incr k} {
set horiz [set verti [lrepeat [expr {$x+1}] [lrepeat [expr {$y+1}] 0]]]
unvisited= $j $k [expr {$here ne [list $j $k]}]
set unvisited [lrepeat [expr {$x+2}] [lrepeat [expr {$y+2}] 0]]
# Helper to write into a list of lists (with offsets)
proc unvisited= {x y value} {
upvar 1 unvisited u
lset u [expr {$x+1}] [expr {$y+1}] $value
}
}

}
lappend stack [set here [list [rand $x] [rand $y]]]
while {0 < $n} {
for {set j 0} {$j < $x} {incr j} {
for {set k 0} {$k < $y} {incr k} {
lassign $here hx hy
unvisited= $j $k [expr {$here ne [list $j $k]}]
set neighbours {}
foreach {dx dy} {1 0 0 1 -1 0 0 -1} {
if {idx($unvisited, $hx+$dx+1, $hy+$dy+1)} {
lappend neighbours [list [expr {$hx+$dx}] [expr {$hy+$dy}]]
}
}
}
}
if {[llength $neighbours]} {
while {0 < $n} {
lassign [set here [pick $neighbours]] nx ny
unvisited= $nx $ny 0
lassign $here hx hy
if {$nx == $hx} {
set neighbours {}
foreach {dx dy} {1 0 0 1 -1 0 0 -1} {
lset horiz $nx [expr {min($ny, $hy)}] 1
if {idx($unvisited, $hx+$dx+1, $hy+$dy+1)} {
lappend neighbours [list [expr {$hx+$dx}] [expr {$hy+$dy}]]
}
}
if {[llength $neighbours]} {
lassign [set here [pick $neighbours]] nx ny
unvisited= $nx $ny 0
if {$nx == $hx} {
lset horiz $nx [expr {min($ny, $hy)}] 1
} else {
lset verti [expr {min($nx, $hx)}] $ny 1
}
lappend stack $here
incr n -1
} else {
} else {
set here [lindex $stack end]
lset verti [expr {min($nx, $hx)}] $ny 1
set stack [lrange $stack 0 end-1]
}
}
lappend stack $here
incr n -1
} else {
set here [lindex $stack end]
set stack [lrange $stack 0 end-1]
}
}
}
}
return [dict create x $x y $y horiz $horiz verti $verti]
}


# Maze displayer; takes a maze dictionary
# Maze displayer; takes a maze dictionary, returns a string
proc display {m} {
method view {} {
set text {}
set text {}
dict with m {
for {set j 0} {$j < $x*2+1} {incr j} {
for {set j 0} {$j < $x*2+1} {incr j} {
set line {}
set line {}
Line 315: Line 317:
}
}
}
}
return [join $text \n]
}
}
return [join $text \n]
}
}

# Demonstration
# Demonstration
puts [display [maze 11 8]]</lang>
maze create m 11 8
puts [m view]</lang>
Output:
Output:
<pre>
<pre>