Mercurial > maze-src
view grid.rb @ 0:1eef88068f9f tip
initial commit of maze game source
| author | ferencd |
|---|---|
| date | Sun, 15 Sep 2019 11:46:47 +0200 |
| parents | |
| children |
line wrap: on
line source
#--- # Excerpted from "Mazes for Programmers", # published by The Pragmatic Bookshelf. # Copyrights apply to this code. It may not be used to create training material, # courses, books, articles, and the like. Contact us if you are in doubt. # We make no guarantees that this code is fit for any purpose. # Visit http://www.pragmaticprogrammer.com/titles/jbmaze for more book information. #--- require 'cell' # Corner constants, to know where to put a torch TOP_LEFT = 1 TOP_RIGHT = 2 BOTTOM_LEFT = 4 BOTTOM_RIGHT = 8 class Room attr_reader :x1, :y1, :x2, :y2 def initialize(px1,py1,px2,py2) @x1 = px1 @x2 = px2 @y1 = py1 @y2 = py2 end def in(x, y) return x > @x1-1 && x < @x2+1 && y > @y1-1 && y < @y2+1 end end class Grid attr_reader :rows, :columns, :dead_ends def initialize(rows, columns) @rows = rows @columns = columns @grid = prepare_grid @rooms = [] # Where food will go @dead_ends = {} @dead_ends[1] = [] @dead_ends[2] = [] @dead_ends[4] = [] @dead_ends[8] = [] configure_cells end def prepare_grid Array.new(rows) do |row| Array.new(columns) do |column| Cell.new(row, column) end end end def configure_cells each_cell do |cell| row, col = cell.row, cell.column cell.north = self[row - 1, col] cell.south = self[row + 1, col] cell.west = self[row, col - 1] cell.east = self[row, col + 1] end end # # Creates a room in the grid # def create_room(x1,y1, x2,y2) # Firstly: empty the room puts "x1:#{x1}, y1, x2, y2" (x1..x2).each do |col| (y1..y2).each do |row| @grid[row][col].link(@grid[row][col+1]) # -> Next to right @grid[row][col].link(@grid[row+1][col]) # -> Next to down end end # then create the surrounding walls (x1 + 1..x2-1).each do |col| @grid[y1+1][col].unlink(@grid[y1][col]) @grid[y2-1][col].unlink(@grid[y2][col]) end (y1+1..y2-1).each do |row| @grid[row][x1+1].unlink(@grid[row][x1]) @grid[row][x2-1].unlink(@grid[row][x2]) end r = Room.new(x1,y1,x2,y2) @rooms << r end def [](row, column) return nil unless row.between?(0, @rows - 1) return nil unless column.between?(0, @grid[row].count - 1) @grid[row][column] end def random_cell row = rand(@rows) column = rand(@grid[row].count) self[row, column] end def size @rows * @columns end def each_row @grid.each do |row| yield row end end def each_cell each_row do |row| row.each do |cell| yield cell if cell end end end # By default, we'll simply display a cell as a blank space. We'll use this # to add other ways of displaying cells. def contents_of(cell) ' ' end # def background_color_for(cell) nil end def to_s maze_js_array end # # Returns the number for the given cell # def number_for_cell(cell) number = 0 number |= EAST if cell.linked?(cell.east) number |= NORTH if cell.linked?(cell.north) number |= SOUTH if cell.linked?(cell.south) number |= WEST if cell.linked?(cell.west) number end # # Returns the maze as a javascript array. This also will initialize all the dead ends # where we will put food or jevelry items # def maze_js_array output = "var maze = [\n" dist_strings = [] each_row do |row| # num array, the number for the row numarray = [] row_string = '' row.each do |cell| cell = Cell.new(-1, -1) unless cell cell_nr = number_for_cell(cell) numarray << cell_nr # Add this cell as a dead end destination @dead_ends[cell_nr] << cell if [1,2,4,8].include? cell_nr end row_string << '[' << numarray.join(', ') << ']' dist_strings << row_string end output << dist_strings.join( ",\n" ) output << "];\n" output end def direction(d) return 'N' if d == NORTH return 'W' if d == WEST return 'E' if d == EAST return 'S' if d == SOUTH return '?' end # # Returns the distances as a js array # def distances_js_array_path output = '' dist_strings = [] each_row do |row| row.each do |cell| cell = Cell.new(-1, -1) unless cell conts = contents_of(cell).to_s if conts.strip.length > 0 dist_strings << {:idx => conts.to_i, :row => cell.row, :col => cell.column} end end end sorted = dist_strings.sort_by {|el| el[:idx]} # The directions this will go walk_string = '' # Now create a direction array from the elements current_cell = self[sorted[0][:row], sorted[0][:col] ] sorted.each_with_index do |cell, index| if index > 0 # Find the direction from curent_cell to cell the_cell = self[cell[:row], cell[:col] ] dest = direction(current_cell.direction(the_cell)) walk_string << dest current_cell = the_cell end end output << "#{walk_string}" output end # # Returns the distances as a js array # def distances_js_array output = "var distances = [\n" dist_strings = [] each_row do |row| row_string = '' numarray = [] row.each do |cell| cell = Cell.new(-1, -1) unless cell conts = contents_of(cell).to_s if conts.strip.length > 0 numarray << conts else numarray << '-1' end end row_string << '[' << numarray.join(', ') << ']' dist_strings << row_string end output << dist_strings.join(",\n") output << "];\n" output end def maze_serialized_text output = [] each_row do |row| numarray = [] row.each do |cell| cell = Cell.new(-1, -1) unless cell numarray << number_for_cell(cell) end output << numarray.join(',') end output.join(':') end def deadends list = [] each_cell do |cell| list << cell if cell.links.count == 1 end list end def braid(p=1.0) deadends.shuffle.each do |cell| next if cell.links.count != 1 || rand > p neighbors = cell.neighbors.reject { |n| cell.linked?(n) } best = neighbors.select { |n| n.links.count == 1 } best = neighbors if best.empty? neighbor = best.sample cell.link(neighbor) end end # # Tells us if we can make a room at the given coordinates # def can_make_room(x1, y1, x2, y2) @rooms.each do |room| return FALSE if room.in(x1, y1) return FALSE if room.in(x2, y2) return FALSE if room.in(x1, y2) return FALSE if room.in(x2, y1) end TRUE end # # Creates a list of locations where torches can be found, mostly in corners at unfinshed walls # def identify_torch_locations numarray = [] j = 0 each_row do |row| i = 0 row.each do |cell| number = 0 number |= TOP_RIGHT if cell.east && cell.north && cell.linked?(cell.east) && cell.linked?(cell.north) && !cell.east.linked?(cell.east.north) && !cell.north.linked?(cell.north.east) number |= TOP_LEFT if cell.west && cell.north && cell.linked?(cell.west) && cell.linked?(cell.north) && !cell.west.linked?(cell.west.north) && !cell.north.linked?(cell.north.west) number |= BOTTOM_RIGHT if cell.east && cell.south && cell.linked?(cell.east) && cell.linked?(cell.south) && !cell.east.linked?(cell.east.south) && !cell.south.linked?(cell.south.east) number |= BOTTOM_LEFT if cell.west && cell.south && cell.linked?(cell.west) && cell.linked?(cell.south) && !cell.west.linked?(cell.west.south) && !cell.south.linked?(cell.south.west) if number != 0 torch_data = { :i => i, :j => j, :number => number} numarray << torch_data end i += 1 end j += 1 end numarray end end
