home *** CD-ROM | disk | FTP | other *** search
/ GameStar Special 2004 August / GSSH0804.iso / Geschicklichkeit / Enigma / Enigma-081.exe / data / levels / natmaze.lua < prev    next >
Text File  |  2003-01-05  |  7KB  |  259 lines

  1. -- Maze module: maze generator and renderer for Enigma
  2. -- 
  3. -- Copyright (c) 2002 Nat Pryce
  4. -- License: GPL v2.0 or above
  5.  
  6. function remove_random_element( table )
  7.     return tremove( table, random( 1, getn(table) ) )
  8. end
  9.  
  10. function random_element( table )
  11.     return table[random( 1, getn(table) )]
  12. end
  13.  
  14.  
  15. -------------------------------------------------------------------------------
  16. -- Maze objects
  17.  
  18.  
  19. -- These constants conflict with those defined in init.lua; commented
  20. -- them out for now (dh).
  21.  
  22. -- NORTH = 1
  23. -- SOUTH = 2
  24. -- WEST = 3
  25. -- EAST = 4
  26.  
  27. function maze_coords_to_cell( maze, x, y )
  28.     return y*maze.width + x
  29. end
  30.  
  31. function maze_can_go_south( maze, x, y )
  32.     return y < (maze.height-1) and maze.linky[maze_coords_to_cell(maze,x,y)]
  33. end
  34.  
  35. function maze_can_go_north( maze, x, y )
  36.     return y > 0 and maze_can_go_south(maze,x,y-1)
  37. end
  38.  
  39. function maze_can_go_east( maze, x, y )
  40.     return x < (maze.width-1) and maze.linkx[maze_coords_to_cell(maze,x,y)]
  41. end
  42.  
  43. function maze_can_go_west( maze, x, y )
  44.     return x > 0 and maze_can_go_east( maze, x-1, y )
  45. end
  46.  
  47. function maze_link_south( maze, x, y )
  48.     assert( maze_contains_cell( maze, x, y+1 ) )
  49.     maze.linky[maze_coords_to_cell(maze,x,y)] = 1
  50. end
  51.  
  52. function maze_link_north( maze, x, y )
  53.     assert( maze_contains_cell( maze, x, y-1 ) )
  54.     maze_link_south( maze, x, y-1 )
  55. end
  56.  
  57. function maze_link_east( maze, x, y )
  58.     assert( maze_contains_cell( maze, x+1, y ) )
  59.     maze.linkx[maze_coords_to_cell(maze,x,y)] = 1
  60. end
  61.  
  62. function maze_link_west( maze, x, y )
  63.     assert( maze_contains_cell( maze, x-1, y ) )
  64.     maze_link_east( maze, x-1, y )
  65. end
  66.  
  67. function maze_contains_cell( maze, x, y )
  68.     return x >= 0 and x < maze.width and y >= 0 and y < maze.height
  69. end
  70.  
  71. function new_maze( width, height )
  72.     local maze = {}
  73.     
  74.     maze.width = width
  75.     maze.height = height
  76.     maze.linkx = {}
  77.     maze.linky = {}
  78.     
  79.     maze.contains_cell = maze_contains_cell
  80.     maze.coords_to_cell = maze_coords_to_cell
  81.     maze.can_go_north = maze_can_go_north
  82.     maze.can_go_south = maze_can_go_south
  83.     maze.can_go_west = maze_can_go_west
  84.     maze.can_go_east = maze_can_go_east
  85.     maze.link_north = maze_link_north
  86.     maze.link_south = maze_link_south
  87.     maze.link_west = maze_link_west
  88.     maze.link_east = maze_link_east
  89.     
  90.     return maze
  91. end
  92.  
  93.  
  94. -------------------------------------------------------------------------------
  95. -- Maze generator based on Kruskal's minimum spanning tree algorithm
  96.  
  97. function new_kruskal_maze( width, height )
  98.     local maze = new_maze(width,height)
  99.     local walls = maze_walls( maze )
  100.     local zones = {}
  101.     local zone_count = width*height
  102.     
  103.     randomseed( enigma.GetTicks() )
  104.     
  105.     while zone_count > 1 do
  106.         wall = remove_random_element( walls )
  107.         local x1 = wall.cellx
  108.         local y1 = wall.celly
  109.         local x2, y2
  110.         
  111.         if wall.side == SOUTH then
  112.             x2 = wall.cellx
  113.             y2 = wall.celly+1
  114.         else -- wall.side == EAST
  115.             x2 = wall.cellx+1
  116.             y2 = wall.celly
  117.         end
  118.         
  119.         cell1 = maze:coords_to_cell(x1,y1)
  120.         cell2 = maze:coords_to_cell(x2,y2)
  121.         zone1 = find_zone( zones, cell1 )
  122.         zone2 = find_zone( zones, cell2 )
  123.         
  124.         if zone1 ~= zone2 then
  125.             if wall.side == SOUTH then
  126.                 maze:link_south( x1, y1 )
  127.             else -- wall.side == EAST
  128.                 maze:link_east( x1, y1 )
  129.             end
  130.             
  131.             union_zones( zones, cell1, cell2 )
  132.             zone_count = zone_count - 1
  133.         end
  134.     end
  135.     
  136.     return maze
  137. end
  138.  
  139.  
  140. function maze_walls( maze )
  141.     walls = {}
  142.     for y = 0, maze.height-1 do
  143.         for x = 0, maze.width-1 do
  144.             if y < maze.height-1 then
  145.                 tinsert( walls, {cellx=x,celly=y,side=SOUTH} )
  146.             end
  147.             if x < maze.width-1 then
  148.                 tinsert( walls, {cellx=x,celly=y,side=EAST} )
  149.             end
  150.         end
  151.     end
  152.     
  153.     return walls
  154. end
  155.  
  156.  
  157.  
  158. -- Union-find algorithm for merging "zones" of the maze.  Each zone is
  159. -- a tree of cells identified by the cell at the root of the tree.  A root
  160. -- cell is represented by a nil reference in the zones table indexed by the
  161. -- cell number.
  162.  
  163. function find_zone( zones, cell )
  164.     if zones[cell] == nil then
  165.         return cell
  166.     else
  167.         zones[cell] = find_zone( zones, zones[cell] )
  168.         return zones[cell]
  169.     end
  170. end
  171.  
  172. function union_zones( zones, cell1, cell2 )
  173.     zones[find_zone(zones,cell2)] = find_zone(zones,cell1)
  174. end
  175.  
  176.  
  177.  
  178. -------------------------------------------------------------------------------
  179. -- Maze renderers
  180.  
  181.  
  182. function render_maze( maze, cell_renderer )
  183.     for cellx = 0, maze.width-1 do
  184.         for celly = 0, maze.height-1 do
  185.             cell_renderer( maze, cellx, celly )
  186.         end
  187.     end
  188. end
  189.  
  190. function tight_maze( maze, maze_floor, wall_floor, wall_stone )
  191.     local originx = 1
  192.     local originy = 1
  193.     
  194.     function cell_to_level( cellx, celly )
  195.         return %originx + cellx * 2, %originy + celly * 2
  196.     end
  197.     
  198.     function draw_maze_border( maze, stone )
  199.         width = maze.width*2
  200.         height = maze.height*2
  201.         
  202.         draw_stones( stone, {0,0}, {1,0}, width )
  203.         draw_stones( stone, {0,height-1},{1,0}, width )
  204.         draw_stones( stone, {0,0}, {0,1}, height )
  205.         draw_stones( stone, {width-1,0},{0,1}, height )
  206.     end
  207.     
  208.     function render_cell( maze, cellx, celly )
  209.         local x, y = cell_to_level( cellx, celly )
  210.         
  211.         if %wall_stone then 
  212.             set_stone( %wall_stone, x+1, y+1 )
  213.         end
  214.         if %maze_floor then
  215.             set_floor( %maze_floor, x, y )
  216.         end
  217.         if maze:can_go_south(cellx,celly) then
  218.             if %maze_floor then
  219.                 set_floor( %maze_floor, x, y+1 )
  220.             end
  221.         else
  222.             if %wall_stone then
  223.                 set_stone( %wall_stone, x, y+1 )
  224.             end
  225.         end
  226.         if maze:can_go_east(cellx,celly) then
  227.             if %maze_floor then
  228.                 set_floor( %maze_floor, x+1, y )
  229.             end
  230.         else
  231.             if %wall_stone then
  232.                 set_stone( %wall_stone, x+1, y )
  233.             end
  234.         end
  235.     end
  236.     
  237.     create_world( maze.width*2 + 1, maze.height*2 + 1 )
  238.     if wall_stone then
  239.         draw_border( wall_stone )
  240.     end
  241.     if wall_floor then
  242.         fill_floor( wall_floor, 0, 0, level_width, level_height )
  243.     else
  244.         fill_floor( maze_floor, 0, 0, level_width, level_height )
  245.     end
  246.     render_maze( maze, render_cell )
  247.     
  248.     oxyd(1,0)
  249.     oxyd(2*maze.width-1,2*maze.height)
  250.     oxyd(1,2*maze.height)
  251.     oxyd(2*maze.width-1,0)
  252.  
  253.     local actorx, actory = cell_to_level( random(maze.width)-1, 
  254.                                           random(maze.height)-1 )
  255.     set_actor( "ac-blackball", actorx + 0.5, actory + 0.5,
  256.                { player=0 } )
  257. end
  258.  
  259.