Fallen Scripter
 |
|
Location: Canada
|
Ok Trickster, I see now that my original submissions are redundant. This time however I added to the Table class and scripted a descendant Object_Table class. It stores the objects numerical id then retrieves the original object using the included module ObjectSpace's _id2ref method. However, since object ids are often greater than 32,767 I had to create a secondary Table to properly store the values. So, what's the verdict on this one? [spoiler=RGSS.Table]
#============================================================================== # ** RGSS.Table #------------------------------------------------------------------------------ # Description: # ------------ # Adds new features to the Table class. [] and []= methods now accept # coordinate key arrays and negative coordinate indexes. It also adds # iteration methods, the Enumerable module and several miscellaneous methods # all objects in the array are of class Numeric. # # Modified Methods: # ----------------- # initialize # [] # []= # _dump # self._load # # Methods Added: # ------------ # Enumerable (see below) # each # each_coordinates # each_with_coordinates # coordinates # each_index # index # clear # nitems # compact # compact! # plane # column # row #============================================================================== #============================================================================== # ** Table #============================================================================== class Table #------------------------------------------------------------------------- # Include # * Names : all?, any?, collect, map, each_with_index, find, detect, # find_all, select, grep, inject, member?, include?, max, # min, partition, reject, sort, sort_by, to_a, entries, zip #------------------------------------------------------------------------- include Enumerable #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_accessor :negitive_read # allow negitive index reading? #-------------------------------------------------------------------------- # * Object Initialization #-------------------------------------------------------------------------- alias_method :icarus_table_initialize, :initialize def initialize(*args) icarus_table_initialize(*args) # Default value for negitive index reading @negitive_read = true # Store number of axis for each coordinate method @axis = args.size end #------------------------------------------------------------------------- # * [] #------------------------------------------------------------------------- alias_method :icarus_table_nth, :[] def [](*args) # Remove nil arguments from the end of the array args.delete_at(-1) while args[-1].nil? # If negitive reading is enabled if @negitive_read # Modify arguments if they are negative indexes args[0] += self.xsize unless args[0] >= 0 args[1] += self.ysize unless args[1].nil? or args[1] >= 0 args[2] += self.zsize unless args[2].nil? or args[2] >= 0 end # Call original method with modified arguments return icarus_table_nth(*args) end #------------------------------------------------------------------------- # * []= #------------------------------------------------------------------------- alias_method :icarus_table_nthequals, :[]= def []=(*args) # Modify arguments if they are negative indexes args[0] += self.xsize unless args[0] >= 0 args[1] += self.ysize unless args[2].nil? or args[1] >= 0 args[2] += self.zsize unless args[3].nil? or args[2] >= 0 # Call original method with modified arguments icarus_table_nthequals(*args) end #------------------------------------------------------------------------- # * _dump #------------------------------------------------------------------------- alias_method :icarus_table_dump, :_dump def _dump(i) return icarus_table_dump(i) + '~~' + Marshal.dump(@negitive_read) + '~~' + Marshal.dump(@axis) end #------------------------------------------------------------------------- # * self._load #------------------------------------------------------------------------- class << self alias_method :icarus_table_load, :_load end def self._load(string) array = string.split('~~') table = self.icarus_table_load(array[0]) unless array[1].nil? table.instance_variable_set(:@negitive_read, Marshal.load(array[1])) table.instance_variable_set(:@axis, Marshal.load(array[2])) end return table end #------------------------------------------------------------------------- # * Name : Each # Info : Iterates through all coordinates, yielding each value # Author : Icarus Featherfight # Call Info : A block # Comments : Provides the basis for included Enumerable methods #------------------------------------------------------------------------- def each each_coordinates{|key| yield self[*key]} end #------------------------------------------------------------------------- # * Name : Each Coordinates # Info : Iterates through all coordinates in the table # Author : Icarus Featherfight # Call Info : A block # Comments : See Each or Coordinates methods for proper block setup #------------------------------------------------------------------------- def each_coordinates for x in 0...self.xsize if @axis == 1 yield [x] else for y in 0...self.ysize if @axis == 2 yield [x, y] else for z in 0...self.zsize yield [x, y, z] end end end end end return nil end #------------------------------------------------------------------------- # * Name : Each With Coordinates # Info : Iterates through table, yielding each value and key # Author : Icarus Featherfight # Call Info : One numeric value to be found #------------------------------------------------------------------------- def each_with_coordinates each_coordinates{|key| yield (self[*key], key)} end #------------------------------------------------------------------------- # * Name : Coordinates # Info : Finds the first coordinates to contain a value # Author : Icarus Featherfight # Call Info : One numeric value to be found #------------------------------------------------------------------------- def coordinates(value) each_coordinates{|key| return key if self[*key] == value} end #------------------------------------------------------------------------- # * Name : Each Index # Info : Iterates through all indexes in a table array # Author : Icarus Featherfight # Call Info : A block #------------------------------------------------------------------------- def each_index self.to_a.each_index{|index| yield(index)} end #------------------------------------------------------------------------- # * Name : Index # Info : Finds the first index to contain a value # Author : Icarus Featherfight # Call Info : One numeric value to be found #------------------------------------------------------------------------- def index(value) each_with_index{|val, index| return index if val == value} end #------------------------------------------------------------------------- # * Name : Clear # Info : Reinitializes table # Author : Icarus Featherfight # Call Info : No arguments # Comments : See Array.clear #------------------------------------------------------------------------- def clear # Reset table if self.ysize == 1 then initialize(self.xsize) elsif self.zsize == 1 then initialize(self.xsize, self.ysize) else initialize(self.xsize, self.ysize, self.zsize) end return self end #------------------------------------------------------------------------- # * Name : NItems # Info : Iterates through index, counting all non-zero elements # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def nitems n = 0 each{|value| n += 1 unless value == false} return n end #------------------------------------------------------------------------- # * Name : Compact # Info : Returns a new table with nil elements removed from positive # extremities of table # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def compact return self.dup.compact! end #------------------------------------------------------------------------- # * Name : Compact! # Info : Removes nil elements from positive extremities of table # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def compact! if self.zsize == 1 x = self.xsize y = self.ysize x -= 1 while row(x - 1).all?{|item| item.nil?} && x > 1 y -= 1 while column(y - 1).all?{|item| item.nil?} && y > 1 resize(x, y) else planes = [] for z in 0...self.zsize planes[z] = plane(z).compact! end planes.delete_at(-1) while planes[-1].all?{|item| item.nil?} xmax, ymax = 1, 1 planes.each{|table| xmax = table.xsize if xmax < table.xsize ymax = table.ysize if ymax < table.ysize } resize(xmax, ymax, planes.size) end return self end #------------------------------------------------------------------------- # * Name : Plane # Info : On a 3D table returns the 2D plane at z value # Author : Icarus Featherfight # Call Info : A numerical z #------------------------------------------------------------------------- def plane(z) return if self.ysize == 1 || self.zsize == 1 || z.nil? || z >= self.zsize if self.class == Object_Table plane = Object_Table.new(self.xsize, self.ysize) else plane = Table.new(self.xsize, self.ysize) end for x in 0...self.xsize for y in 0...self.ysize plane[x, y] = self[x, y, z] end end return plane end #------------------------------------------------------------------------- # * Name : Column # Info : On a 3D or 2D table returns the array at y and z values. # Author : Icarus Featherfight # Call Info : A numerical y and an optional z for 3D tables #------------------------------------------------------------------------- def column(x, z = nil) column = [] for y in 0...self.ysize column[y] = self[x, y, z] end end #------------------------------------------------------------------------- # * Name : Row # Info : On a 3D or 2D table returns the array at x and z values. # Author : Icarus Featherfight # Call Info : A numerical x and an optional z for 3D tables #------------------------------------------------------------------------- def row(y, z = nil) row = [] for x in 0...self.xsize row[x] = self[x, y, z] end end end
Expand to see the code.
#============================================================================== # ** Object Table By Icarus Featherfight #------------------------------------------------------------------------------ # The multidimensional array class; extended to hold objects. # - when resizing table, all data from before the size change is retained #============================================================================== class Object_Table < Table #------------------------------------------------------------------------- # Include ObjectSpace # * Names : _id2ref, define_finalizer, each_object, garbage_collect, # undefine_finalizer #------------------------------------------------------------------------- include ObjectSpace #------------------------------------------------------------------------- # * Name : Initialize # Info : Creates main table and additional depth table # Author : Icarus Featherfight # Call Info : 1..3 coordinate maximums (xsize[, ysize[, zsize]]) #------------------------------------------------------------------------- def initialize(*args) super # Creates depth table @depth = Table.new(*args) # Initialize table with nil values self.each_coordinates{|key| self[*key] = nil} end #------------------------------------------------------------------------- # * Name : Element Reference # Info : Extends method to return objects; stored as ids # Author : Icarus Featherfight # Call Info : 1..3 coordinate arguments or one coordinate key array # Comments : Prevents ArgumentErrors when using a coordinate key array #------------------------------------------------------------------------- def [](*args) # Abort if coordinates are outside of table return nil if super.nil? # Returns original object after recalculating its id return _id2ref(super + (32_768 * @depth[*args])) end #------------------------------------------------------------------------- # * Name : Element Assignment # Info : Extends method to store an objects id # Author : Icarus Featherfight # Call Info : 1..3 coordinate arguments or array and value # Comments : Prevents ArgumentErrors when using a coordinate key array #------------------------------------------------------------------------- def []=(*args) # Free current contents for GC a = args.dup a.pop undefine_finalizer(self[*a]) unless self[*a] == false # Define finalizer to prevent GC define_finalizer(args[-1], proc {|id| p "Object Table Entry: #{id}" }) # Replace object with its id args[-1] = args[-1].id # Create key for secondary depth table key = args.dup key.pop # Store depth and reduce id integer to effective range of table @depth[*key] = args[-1] / 32_768 args[-1] %= 32_768 # Store modified object id value return super(*args) end #------------------------------------------------------------------------- # * Name : _dump # Info : Marshals Object_Table data # Author : Icarus Featherfight # Call Info : An Interger i # Comments : Adds @depth Table to dump #------------------------------------------------------------------------- def _dump(i) return super(i) + '~|~' + Marshal.dump(@depth) end #------------------------------------------------------------------------- # * Name : self._load # Info : Retores Object_Table from a marshaled string # Author : Icarus Featherfight # Call Info : A String string # Comments : Restores @depth Table #------------------------------------------------------------------------- def self._load(string) array = string.split('~|~') table = super(array[0]) table.instance_variable_set(:@depth, Marshal.load(array[1])) return table end #------------------------------------------------------------------------- # * Name : Resize # Info : Resizes main table and additional depth table # Author : Icarus Featherfight # Call Info : 1..3 coordinate maximums (xsize[, ysize[, zsize]]) # Comments : All data from before the size change is retained #------------------------------------------------------------------------- def resize(*args) # Resize main table super # Resize depth table @depth.resize(*args) end #------------------------------------------------------------------------- # * Name : Clear # Info : Reinitializes table # Author : Icarus Featherfight # Call Info : No arguments # Comments : See Array.clear #------------------------------------------------------------------------- def clear self.each{|obj| undefine_finalizer(obj)} super end #------------------------------------------------------------------------- # * Name : Expand # Info : Returns the tables array with nested arrays expanded # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def expand array = self.to_a array.each_index{|i| array[i, 1] = array[i] if array[i].class == Array} return array end end
Expand to see the code.
P.S. I know Selwyn already created Array_2D and Table_Object classes for the MaCL but his were based on the Array class.
[/spoiler]
As it turns out, the above code suffers from a critical oversight. Since all objects are disposed on exit, saving only their ids is not enough. The version below fixes this and is based on the array class.
#============================================================================== # ** Object Table By Icarus Featherfight #------------------------------------------------------------------------------ # The multidimensional array class; can hold all objects. # - when resizing table, all data from before the size change is retained # - negative coordinate indexes can be used # - includes the Enumerable module #============================================================================== class Object_Table #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_accessor :negative_read # allow negative index reading? attr_reader :data # data array attr_reader :xsize, :ysize, :zsize # numerical coordinate maximums #------------------------------------------------------------------------- # * Name : Initialize # Info : Initializes Object_Table # Author : Icarus Featherfight # Call Info : 1..3 Numeric coordinate maximums (xsize[, ysize[, zsize]]) #------------------------------------------------------------------------- def initialize(*args) # Store number of axis and axial maximums @axis = args.size @xsize, @ysize, @zsize = args[0], args[1], args[2] # Create data table array @data = [] if @axis >= 2 for x in 0...@xsize @data[x] = [] end if @axis == 3 for x in 0...@xsize for y in 0...@ysize @data[x][y] = [] end end end end # Default value for negative index reading @negitive_read = true end #------------------------------------------------------------------------- # * Name : Element Reference # Info : Returns Object stored at coordinates # Author : Icarus Featherfight # Call Info : 1..3 Numeric coordinate arguments #------------------------------------------------------------------------- def [](*args) # Raise ArgumentError if there is the wrong number of arguments raise ArgumentError if args.size != @axis # Return if negative reading is disabled and a coordinate is negative return nil if !@negitive_read and args.any?{|num| num < 0} # Return Object stored at coordinates case @axis when 1 return @data[args[0]] when 2 return @data[args[0]][args[1]] when 3 return @data[args[0]][args[1]][args[2]] end end #------------------------------------------------------------------------- # * Name : Element Assignment # Info : Stores Object at designated coordinates # Author : Icarus Featherfight # Call Info : 1..3 coordinate arguments and a Object value #------------------------------------------------------------------------- def []=(*args) # Raise ArgumentError if there is the wrong number of arguments raise ArgumentError if args.size - 1 != @axis # Raise IndexError if coordinates are out of range raise IndexError if args[0] >= @xsize or args[1] != nil && args[1] >= @ysize or args[2] != nil && args[2] >= @zsize # Store Object at coordinates case @axis when 1 return @data[args[0]] = args[-1] when 2 return @data[args[0]][args[1]] = args[-1] when 3 return @data[args[0]][args[1]][args[2]] = args[-1] end end #------------------------------------------------------------------------- # Include # * Names : all?, any?, collect, map, each_with_index, find, detect, # find_all, select, grep, inject, member?, include?, max, # min, partition, reject, sort, sort_by, to_a, entries, zip #------------------------------------------------------------------------- include Enumerable #------------------------------------------------------------------------- # * Name : Each # Info : Iterates through all coordinates, yielding each value # Author : Icarus Featherfight # Call Info : A block # Comments : Provides the basis for included Enumerable methods #------------------------------------------------------------------------- def each each_coordinates{|key| yield self[*key]} end #------------------------------------------------------------------------- # * Name : Each Coordinates # Info : Iterates through all coordinates in the table # Author : Icarus Featherfight # Call Info : A block # Comments : See Each or Coordinates methods for proper block setup #------------------------------------------------------------------------- def each_coordinates for x in 0...@xsize if @axis == 1 yield [x] else for y in 0...@ysize if @axis == 2 yield [x, y] else for z in 0...@zsize yield [x, y, z] end end end end end return nil end #------------------------------------------------------------------------- # * Name : Each With Coordinates # Info : Iterates through table, yielding each value and key # Author : Icarus Featherfight # Call Info : One numeric value to be found #------------------------------------------------------------------------- def each_with_coordinates each_coordinates{|key| yield (self[*key], key)} end #------------------------------------------------------------------------- # * Name : Coordinates # Info : Finds the first coordinates to contain a value # Author : Icarus Featherfight # Call Info : One numeric value to be found #------------------------------------------------------------------------- def coordinates(value) each_coordinates{|key| return key if self[*key] == value} end #------------------------------------------------------------------------- # * Name : Each Index # Info : Iterates through all indexes in a table array # Author : Icarus Featherfight # Call Info : A block #------------------------------------------------------------------------- def each_index self.to_a.each_index{|index| yield(index)} end #------------------------------------------------------------------------- # * Name : Index # Info : Finds the first index to contain a value # Author : Icarus Featherfight # Call Info : One numeric value to be found #------------------------------------------------------------------------- def index(value) each_with_index{|val, index| return index if val == value} end #------------------------------------------------------------------------- # * Name : Clear # Info : Reinitializes table # Author : Icarus Featherfight # Call Info : No arguments # Comments : See Array.clear #------------------------------------------------------------------------- def clear initialize(@xsize, @ysize, @zsize) end #------------------------------------------------------------------------- # * Name : Resize # Info : Resizes main table and additional depth table # Author : Icarus Featherfight # Call Info : 1..3 coordinate maximums (xsize[, ysize[, zsize]]) # Comments : All data from before the size change is retained #------------------------------------------------------------------------- def resize(*args) # Abort if new dimentions equal the old return if args[0], args[1], agrs[2] == @xsize, @ysize, @zsize # Destroy axis if args[1].nil? case @axis when 2 # Destroy y axis for x in 0...@xsize @data[x] = @data[x][0] end when 3 # Destroy y and z axis for x in 0...@xsize @data[x] = @data[x][0][0] end end @axis = 1 @ysize, @zsize = nil, nil elsif args[2].nil? if @axis = 3 # Destroy z axis for x in 0...@xsize for y in 0...@ysize @data[x][y] = @data[x][y][0] end end end @axis = 2 @zsize = nil end # Resize x axis if args[0] < @xsize # Crop table for x in args[0]...@xsize @data.delete_at(x) end elsif args[0] > @xsize and @axis >= 2 # Extend table for x in @xsize...args[0] @data[x] = [] end if @axis == 3 for x in @xsize...args[0] for y in @ysize...args[1] @data[x][y] = [] end end end end return if @axis == 1 # Resize y axis if args[1] < @ysize # Crop table for x in 0...args[0] for y in args[1]...@ysize @data[x].delete_at(y) end end elsif args[1] > @ysize and @axis == 3 # Extend table for x in @xsize...args[0] for y in @ysize...args[1] @data[x][y] = [] end end end return if @axis != 3 # Resize z axis if args[2] < @zsize # Crop table for x in 0...args[0] for y in args[1]...@ysize for z in args[2]...@zsize @data[x][y].delete_at(z) end end end elsif args[2] > @zsize # Extend table for x in @xsize...args[0] for y in @ysize...args[1] @data[x][y] = [] end end end end #------------------------------------------------------------------------- # * Name : NItems # Info : Iterates through index, counting all non-zero elements # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def nitems n = 0 each{|value| n += 1 unless value == false} return n end #------------------------------------------------------------------------- # * Name : Compact # Info : Returns a new table with nil elements removed from positive # extremities of table # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def compact return self.dup.compact! end #------------------------------------------------------------------------- # * Name : Compact! # Info : Removes nil elements from positive extremities of table # Author : Icarus Featherfight # Call Info : No arguments #------------------------------------------------------------------------- def compact! if @zsize == nil x = @xsize y = @ysize x -= 1 while row(x - 1).all?{|item| item.nil?} && x > 1 y -= 1 while column(y - 1).all?{|item| item.nil?} && y > 1 resize(x, y) else planes = [] for z in 0...@zsize planes[z] = plane(z).compact! end planes.delete_at(-1) while planes[-1].all?{|item| item.nil?} xmax, ymax = 1, 1 planes.each{|table| xmax = table.xsize if xmax < table.xsize ymax = table.ysize if ymax < table.ysize } resize(xmax, ymax, planes.size) end return self end #------------------------------------------------------------------------- # * Name : Plane # Info : On a 3D table returns the 2D plane at z value # Author : Icarus Featherfight # Call Info : A numerical z #------------------------------------------------------------------------- def plane(z) return if @ysize == 1 || @zsize == 1 || z.nil? || z >= @zsize plane = Object_Table.new(@xsize, @ysize) for x in 0...@xsize for y in 0...@ysize plane[x, y] = @data[x][y][z] end end return plane end #------------------------------------------------------------------------- # * Name : Column # Info : On a 3D or 2D table returns the array at y and z values. # Author : Icarus Featherfight # Call Info : A numerical y and an optional z for 3D tables #------------------------------------------------------------------------- def column(x, z = nil) column = [] if z.nil? for y in 0...@ysize column[y] = @data[x][y] end else for y in 0...@ysize column[y] = @data[x][y][z] end end end #------------------------------------------------------------------------- # * Name : Row # Info : On a 3D or 2D table returns the array at x and z values. # Author : Icarus Featherfight # Call Info : A numerical x and an optional z for 3D tables #------------------------------------------------------------------------- def row(y, z = nil) row = [] if z.nil? for x in 0...@xsize row[x] = @data[x][y] end else for x in 0...@xsize row[x] = @data[x][y][z] end end end end
_________________
Last edited by Icarus Featherfight on Fri Oct 19, 2007 3:06 am, edited 1 time in total.
|
|