Mundo Maker
¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.
Conectarse

Recuperar mi contraseña

Temas importantes
----------------------------------------
Páginas con recursos RPG Maker
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
Afiliados
Estadísticas
Tenemos 4139 miembros registrados.
El último usuario registrado es pepus2008.

Nuestros miembros han publicado un total de 84794 mensajes en 12069 argumentos.

[XP][VX][Ace] [Herramienta de Scripter] Tree

Ver el tema anterior Ver el tema siguiente Ir abajo

[XP][VX][Ace] [Herramienta de Scripter] Tree

Mensaje por Wecoc el 2016-11-05, 10:12

Otro de mis bastante inútiles pero sensuales scripts (?).

Tree es una nueva clase similar a Array pero en la que cada valor puede tener brancas secundarias. Actúa de modo recursivo así que puede haber branca dentro de branca... y así montar todo un árbol complejo. Los créditos opcionales. Puede modificarse libremente, solo hay lo más básico.

Código:
#==============================================================================
# ** [XP|VX|Ace][Herramienta de scripter] Tree v1.0
#------------------------------------------------------------------------------
#  Nueva clase similar a Array pero en la que cada valor puede tener brancas
#  secundarias. Créditos opcionales. Puede modificarse libremente.
#------------------------------------------------------------------------------
#  Autor: Wecoc
#==============================================================================

#==============================================================================
# ** Tree
#==============================================================================

class Tree
  #--------------------------------------------------------------------------
  attr_reader   :hash
  attr_accessor :default
  attr_accessor :parent
  #--------------------------------------------------------------------------
  def initialize(*args)
    @hash = {}
    @hash.default = TreeNode.new
    for i in 0...args.size
      @hash[i] = TreeNode.new
      @hash[i].root = self
      @hash[i].content = args[i]
    end
    @default = nil
    @parent = nil
  end
  #--------------------------------------------------------------------------
  def node(n, index=0)
    return @hash.values.select{|v| v.content == n}[index]
  end
  #--------------------------------------------------------------------------
  def node_index(n)
    @hash[n]
  end
  #--------------------------------------------------------------------------
  def [](n)
    @hash[n].content
  end
  #--------------------------------------------------------------------------
  def []=(n, value)
    if value != nil
      @hash[n] = TreeNode.new if @hash[n].nil?
      @hash[n].root = self
      @hash[n].content = value
    else
      @hash.delete(n)
    end
    return value
  end
  #--------------------------------------------------------------------------
  def has_content?(n)
    @hash[n].has_content?
  end
  #--------------------------------------------------------------------------
  def is_root?
    @hash.any?{|k,v| v.root.parent == nil}
  end
  #--------------------------------------------------------------------------
  def is_leaf?
    !@hash.any?{|k,v| v.has_children?}
  end
  #--------------------------------------------------------------------------
  def to_a
    array = []
    array.default = @default if @default != nil
    @hash.each {|k,v| array[k] = v}
    return array
  end
  #--------------------------------------------------------------------------
  def include?(value)
    return @hash.any? {|k,v| v.children.include?(value)} if value.is_a?(Tree)
    main = @hash.any? {|k,v| v == value || v.content == value}
    return true if main == true
    return @hash.any? {|k,v| v.children.any? {|c| c.include?(value) }}
  end
  #--------------------------------------------------------------------------
  def index(value, rindex=0)
    r = @hash.select {|k,v| v == value || v.content == value}
    return r[rindex][0] rescue nil
  end
  #--------------------------------------------------------------------------
  def find(value, rindex=0)
    return self if @hash.any? {|k,v| v == value || v.content == value}
    for v in @hash.values
      r = v.children.select{|c| c.find(value) != nil }
      return r[rindex] if !r[rindex].nil?
    end
    return nil
  end
  #--------------------------------------------------------------------------
  def sequence(*args) # (end_node) | (start_node, end_node)
    case args.size
      when 1 then o, e = node_index(0), args[0]
      when 2 then o, e = *args
    end
    return nil if !include?(o) or !include?(e)
    nodes = [o]
    i = o
    loop do
      i = self.next(i, e)
      break if i == nil
      nodes << i
      break if i == e
    end
    return nodes
  end
  #--------------------------------------------------------------------------
  def next(o, e)
    if find(o) == find(e)
      tree = find(o)
      if tree.index(o) < tree.index(e)
        return tree.node_index(tree.index(o) + 1).content
      else
        return tree.node_index(tree.index(o) - 1).content
      end
    end
    if find(o).hash.any? {|k,v| v.children.any? {|c| c.include?(e) }}
      tree = find(o)
      r = tree.hash.select {|k,v| v.children.any? {|c| c.include?(e) }}[0]
      if tree.index(o) == r[0]
        return r[1].children.select{|c| c.include?(e)}[0].node_index(0).content
      elsif tree.index(o) < r[0]
        return tree.node_index(tree.index(o) + 1).content
      else
        return tree.node_index(tree.index(o) - 1).content
      end
    end
    tree = find(o)
    index = internal_index(o)
    if index > 0
      return tree.node_index(index - 1).content
    end
    return tree.node_index(index).root.parent
  end
  #--------------------------------------------------------------------------
  def internal_index(n, rindex=0)
    if self.include?(n)
      if self.index(n, rindex) != nil
        return self.index(n, rindex)
      end
      r = @hash.select {|k,v| v.children.any? {|c| c.include?(n) }}[0]
      tree = r[1].children.select{|c| c.include?(n) }[0]
      return tree.internal_index(n, rindex)
    end
    return nil
  end
  #--------------------------------------------------------------------------
  def to_s
    self.to_a.to_s
  end
  #--------------------------------------------------------------------------
  def inspect
    self.to_a.inspect
  end
end

#==============================================================================
# ** TreeNode [Internal]
#==============================================================================

class TreeNode
  #--------------------------------------------------------------------------
  attr_accessor :content
  attr_accessor :children
  attr_accessor :root
  #--------------------------------------------------------------------------
  def initialize(content=nil)
    @content = content
    @children = []
  end
  #--------------------------------------------------------------------------
  def has_content?
    !@content.nil?
  end
  #--------------------------------------------------------------------------
  def has_children?
    @children.size > 0
  end
  #--------------------------------------------------------------------------
  def add(n)
    @children.push(n)
    n.parent = self
  end
  #--------------------------------------------------------------------------
  def inspect
    @content.inspect
  end
end

Montar un árbol

Usaré siempre el mismo árbol para los ejemplos.

Podemos definir un árbol del siguiente modo, similar a como funcionan las Array:

root = Tree.new('A', 'B', 'C', 'F', 'H')

Éste será el árbol raíz o principal, por ello le puse de nombre root.
Por ahora es prácticamente como una array normal.

Las brancas se crean como un árbol a parte, crearé dos y las llamaré a y b

a = Tree.new('D', 'E')
b = Tree.new('G')


Luego unimos cada branca a nuestro árbol en el nodo que queramos, usando el método node para buscar ese nodo y le anclamos la branca con add del siguiente modo:

root.node('C').add(a)
root.node('F').add(b)


Cada nodo puede tener tantas brancas como se quiera.

root en sí no ha cambiado, pero tiene esa información extra almacenada, y pese a cambiar el valor de 'C', en esa posición seguirá teniendo esa branca.

Si os fijáis el árbol completo, que es el que se usará en todos los ejemplos, tiene la siguiente estructura:



Llamadas de script

Para cambiar un valor o devolverlo se hace como siempre en array, usando el índice entre claudátors:

root[1] # 'B'
root[1] = 'Wecoc' # 'Wecoc'


No solo acepta strings sino cualquier cosa, es decir funciona como cualquier array.

node

Permite acceder al nodo de un valor concreto. Para ello se recomienda no usar nodos repetidos a lo largo del árbol, aunque en casos más complejos en los que se requiera hay formas de evitar problemas con eso.

root.node('C') # Devueve el nodo 'C'

A ese nodo se le puede abregar una branca como ya se ha visto antes, y también se puede comprobar si tiene un valor definido (en éste caso sí; 'C') o si tiene brancas atadas (también, la branca ['D', 'E']). Esas brancas se llaman children, es decir, brancas 'hijas' de la principal.

root.node('C').has_content? # true
root.node('C').has_children? # true


node_index

Lo mismo que node pero con el índice en la branca en vez de con el valor

root.node_index(0) # Devuelve 'A'
root.node_index(3) # Devuelve 'F'


parent | root

El método parent devuelve el nodo al que está anclada una branca.
El método root devuelve la branca a la que pertenece un determinado nodo. Ese valor es definido cuando se define ese nodo, así que aunque haya distintos árboles con un mismo nodo siempre identificará correctamente a cual se corresponde.

a.parent # 'C'
a.parent.root # ['A', 'B', 'C', 'F', 'H']


has_content?

Comprueba si una posición concreta del árbol tiene contenido definido o no

root.has_content?(3) # true
root.has_content?(7) # false


is_root? | is_leaf?

El método is_root? comprueban si la branca es una branca principal (la raíz del árbol) y is_leaf? si es un extremo de la branca.

root.is_root? # true
a.is_root? # false
b.is_root? # false


root.is_leaf? # false
a.is_leaf? # true
b.is_leaf? # true


Aquellas brancas que no sean ni la branca raíz ni el extremo por lo tanto tendrán false en ámbos parámetros, así que no son antónimos.

to_a | to_s

Conversores de árbol a array o a string (similar que en array)

include?

Comprueba si incluye un valor. ATENCIÓN, en éste caso si una branca secundaria lo incluye valdrá true, ya que las comprueba todas de modo recursivo.

root.include?('D') # true

index

Devuelve el índice en el que se encuentra un valor, si no devuelve nil. ATENCIÓN, en éste caso solo usa la branca principal que está mirando.

root.index('C') # 2
root.index('D') # nil


Si hay más de un índice con ese valor devuelve el primero, aunque en casos más complejos hay modos de obtener cada uno separadamente.

find

Busca en qué branca del árbol se encuentra un valor.

root.find('C') # ['A', 'B', 'C', 'F', 'H']
root.find('D') # ['D', 'E']


sequence

Busca la cadena entre un nodo y otro. Puedes definirlo solo el modo final y lo comprobará desde el primero y hasta el indicado, o puedes indicarle los dos.

root.sequence('A', 'E') # ['A', 'B', 'C', 'D', 'E']
root.sequence('E', 'A') # ['E', 'D', 'C', 'B', 'A']
root.sequence('E', 'G') # ['E', 'D', 'C', 'F', 'G']


Eso es todo, los demás que hay son de uso interno.
avatar
Wecoc
Administrador
Administrador



Créditos 9218

Gracias : 493

Volver arriba Ir abajo

Re: [XP][VX][Ace] [Herramienta de Scripter] Tree

Mensaje por Noragami-kun el 2016-11-05, 21:37

Genial!
avatar
Noragami-kun
Iniciado
Iniciado

0/3

Créditos 18

Gracias : 3

Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


Permisos de este foro:
No puedes responder a temas en este foro.