
  require 'sketchup' # First we pull in the standard API hooks.
  require 'ShaDe//lib//utils.rb'
  require 'ShaDe//lib//geometry.rb'
  require 'ShaDe//lib//data-structures.rb'
  require 'ShaDe//lib//constraints.rb'

#The next seven classes may be stored in a separate ruby module (e.g. montaner.rb)
class WallsCompacityProblem
	def initialize(wall_side)
		@center_labels = LinearLinkedList.new
		@wall_side = wall_side
	end

	def reset()
		@center_labels = LinearLinkedList.new
	end

	def get_reward(state, is_final_step)
		if is_final_step
			perimeter = 0
			area = 0

			#First, we make the list of points representing the center labels. For every point in this list, there is a square in the shape
			@center_labels = LinearLinkedList.new
			label_points = state.shape.p["Layer0"].get_node(Label.new("Black")).list
			label_points.reset_iterator
			while  (p = label_points.get_next)
				point = OrderedPoint.new(Point.new(p.key.x, p.key.y, 0))  
				point_node = LinearLinkedListNode.new(point, nil, nil)
				@center_labels.insert_node(point_node)
			end

			state_features = Array.new(number_of_features, 0)
			#Then, for every point, we count the number of neighbors and depending on this number, we update the perimeter
			#Second, we go over the list in order to search neighbors
			@center_labels.reset_iterator
			while (p = @center_labels.get_next)
				number_of_neighbors = 0
				top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @wall_side, 0)) 
				right_neighbor = OrderedPoint.new(Point.new(p.key.x + @wall_side, p.key.y, 0))
				bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @wall_side, 0))
				left_neighbor = OrderedPoint.new(Point.new(p.key.x - @wall_side, p.key.y, 0))
				if @center_labels.get_node top_neighbor
					number_of_neighbors += 1
				end
				if @center_labels.get_node right_neighbor
					number_of_neighbors += 1
				end
				if @center_labels.get_node bottom_neighbor
					number_of_neighbors += 1
				end
				if @center_labels.get_node left_neighbor
					number_of_neighbors += 1
				end
				if number_of_neighbors > 0
					state_features[number_of_neighbors - 1] += 1
				end
				perimeter += (@wall_side*(4-number_of_neighbors))  
			end

			#Last, we compute the area, simply multiplying the number of points by 8^2
			area = @center_labels.size * @wall_side * @wall_side

			return (area.quo(perimeter * perimeter))
		else
			return 0
		end
	end

	#Returns a 4-position array with the number of squares with 1, 2, 3, and 4 neighbors that the generated shape has
	def get_features(state_action)
		features = Array.new(number_of_features,0)

		state = state_action.state

		#First, we make the list of points representing the center labels. For every point in this list, there is a square in the shape
		@center_labels = LinearLinkedList.new
		label_points = state.shape.p["Layer0"].get_node(Label.new("Black")).list
		label_points.reset_iterator
		while  (p = label_points.get_next)
			point = OrderedPoint.new(Point.new(p.key.x, p.key.y, 0))
			point_node = LinearLinkedListNode.new(point, nil, nil)
			@center_labels.insert_node(point_node)
		end

		#Second, put the square added by the action into the grid
		t = state_action.action.transformation
		ax = t[0]
		bx = t[1]
		cx = t[2]
		ay = t[3]
		by = t[4]
		cy = t[5]
		added_label_x = @wall_side*1.5* ax + @wall_side.quo(2) * bx + cx
		added_label_y = @wall_side*1.5 * ay + @wall_side.quo(2) * by + cy
		added_x = added_label_x - @wall_side.quo(2)  #<--
		added_y = added_label_y - @wall_side.quo(2)
		point = OrderedPoint.new(Point.new(added_x, added_y, 0))   
		point_node = LinearLinkedListNode.new(point, nil, nil)
		aux_labels = @center_labels.clone
		aux_labels.insert_node(point_node)

		#Third, we go over the list in order to search neighbors
		aux_labels.reset_iterator
		while (p = aux_labels.get_next)
			number_of_neighbors = 0
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @wall_side, 0))   
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @wall_side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @wall_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @wall_side, p.key.y, 0))
			if aux_labels.get_node top_neighbor
				number_of_neighbors += 1
			end
			if aux_labels.get_node right_neighbor
				number_of_neighbors += 1
			end
			if aux_labels.get_node bottom_neighbor
				number_of_neighbors += 1
			end
			if aux_labels.get_node left_neighbor
				number_of_neighbors += 1
			end
			if number_of_neighbors > 0
				features[number_of_neighbors-1] += 1
			end
		end
		
		max = features.max
		features.each_index{ |i|
			#features[i] = features[i].quo(max)
			features[i] = features[i].quo(45)
		}

		return features
	end

	
	
	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	def get_actions(state, print = false)

		actions = Array.new

		#First, we make the list of points representing the bottom-left corner of every square. For every point in this list, there is a square in the shape
		@center_labels = LinearLinkedList.new
		label_points = state.shape.p["Layer0"].get_node(Label.new("Black")).list
		label_points.reset_iterator
		while  (p = label_points.get_next)
			point = OrderedPoint.new(Point.new(p.key.x, p.key.y, 0))
			point_node = LinearLinkedListNode.new(point, nil, nil)
			@center_labels.insert_node(point_node)
		end
		
		wall_labels = LinearLinkedList.new
		label_points = state.shape.p["Layer0"].get_node(Label.new("White")).list
		label_points.reset_iterator
		while  (p = label_points.get_next)
			point = OrderedPoint.new(Point.new(p.key.x, p.key.y, 0))
			point_node = LinearLinkedListNode.new(point, nil, nil)
			wall_labels.insert_node(point_node)
		end

		#Second, we go over the list in order to find the next possible actions (where to add squares)
		@center_labels.reset_iterator
		while (p = @center_labels.get_next)

			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @wall_side, 0))   
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @wall_side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @wall_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @wall_side, p.key.y, 0))
			top_right_label = OrderedPoint.new(Point.new(p.key.x + (@wall_side.quo(2)), p.key.y + (@wall_side.quo(2)), 0))
			bottom_right_label = OrderedPoint.new(Point.new(p.key.x + (@wall_side.quo(2)), p.key.y - (@wall_side.quo(2)), 0))
			bottom_left_label = OrderedPoint.new(Point.new(p.key.x - (@wall_side.quo(2)), p.key.y - (@wall_side.quo(2)), 0))
			top_left_label = OrderedPoint.new(Point.new(p.key.x - (@wall_side.quo(2)), p.key.y + (@wall_side.quo(2)), 0))
			
			bottom_left_corner = OrderedPoint.new(Point.new(p.key.x - @wall_side.quo(2), p.key.y - @wall_side.quo(2), 0))
			
			if (!(@center_labels.get_node top_neighbor) && (wall_labels.get_node top_left_label) && (wall_labels.get_node top_right_label))
				top_point_node = LinearLinkedListNode.new(top_neighbor, nil, nil)
				aux_labels = @center_labels.clone
				aux_labels.insert_node(top_point_node)

				triple = Array.new(3)
				triple[0] = 1 #rule to apply
				triple[1] = [0, -1, bottom_left_corner.x + @wall_side, 1, 0, bottom_left_corner.y] #transformation to apply   
				triple[2] = get_features_of_grid(aux_labels)

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			if (!(@center_labels.get_node right_neighbor) && (wall_labels.get_node top_right_label) && (wall_labels.get_node bottom_right_label))
				right_point_node = LinearLinkedListNode.new(right_neighbor, nil, nil)
				aux_labels = @center_labels.clone
				aux_labels.insert_node(right_point_node)

				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [1, 0, bottom_left_corner.x, 0, 1, bottom_left_corner.y]  
				triple[2] = get_features_of_grid(aux_labels)

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			if (!(@center_labels.get_node bottom_neighbor) && (wall_labels.get_node bottom_right_label) && (wall_labels.get_node bottom_left_label))
				bottom_point_node = LinearLinkedListNode.new(bottom_neighbor, nil, nil)
				aux_labels = @center_labels.clone
				aux_labels.insert_node(bottom_point_node)

				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [0, 1, bottom_left_corner.x, -1, 0, bottom_left_corner.y + @wall_side]   
				triple[2] = get_features_of_grid(aux_labels)

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			if (!(@center_labels.get_node left_neighbor) && (wall_labels.get_node bottom_left_label) && (wall_labels.get_node top_left_label))
				left_point_node = LinearLinkedListNode.new(left_neighbor, nil, nil)
				aux_labels = @center_labels.clone
				aux_labels.insert_node(left_point_node)

				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [-1, 0, bottom_left_corner.x + @wall_side, 0, 1, bottom_left_corner.y]   
				triple[2] = get_features_of_grid(aux_labels)

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
		end

		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)

		#First, we make the list of points representing the bottom-left corner of every square. For every point in this list, there is a square in the shape
		@center_labels = LinearLinkedList.new
		label_points = state.shape.p["Layer0"].get_node(Label.new("Black")).list
		label_points.reset_iterator
		while  (p = label_points.get_next)
			point = OrderedPoint.new(Point.new(p.key.x , p.key.y, 0))   
			point_node = LinearLinkedListNode.new(point, nil, nil)
			@center_labels.insert_node(point_node)
		end
		
		wall_labels = LinearLinkedList.new
		label_points = state.shape.p["Layer0"].get_node(Label.new("White")).list
		label_points.reset_iterator
		while  (p = label_points.get_next)
			point = OrderedPoint.new(Point.new(p.key.x, p.key.y, 0))  
			point_node = LinearLinkedListNode.new(point, nil, nil)
			wall_labels.insert_node(point_node)
		end

		next_features = Array.new

		#Second, we go over the list in order to find the next possible actions (where to add squares)
		@center_labels.reset_iterator
		while (p = @center_labels.get_next)
			
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @wall_side, 0))  
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @wall_side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @wall_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @wall_side, p.key.y, 0))
			top_right_label = OrderedPoint.new(Point.new(p.key.x + (@wall_side.quo(2)), p.key.y + (@wall_side.quo(2)), 0))
			bottom_right_label = OrderedPoint.new(Point.new(p.key.x + (@wall_side.quo(2)), p.key.y - (@wall_side.quo(2)), 0))
			bottom_left_label = OrderedPoint.new(Point.new(p.key.x - (@wall_side.quo(2)), p.key.y - (@wall_side.quo(2)), 0))
			top_left_label = OrderedPoint.new(Point.new(p.key.x - (@wall_side.quo(2)), p.key.y + (@wall_side.quo(2)), 0))
			
			bottom_left_corner = OrderedPoint.new(Point.new(p.key.x - @wall_side.quo(2), p.key.y - @wall_side.quo(2), 0))
			
			if (!(wall_labels.get_node top_neighbor) && (wall_labels.get_node top_left_label) && (wall_labels.get_node top_right_label))
				action = Array.new(2)
				action[0] = 1 #rule to apply
				action[1] = [0, -1, bottom_left_corner.x + @wall_side, 1, 0, bottom_left_corner.y] #transformation to apply   
				#Now, we add the features just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [action[0], action[1]]
					top_point_node = LinearLinkedListNode.new(top_neighbor, nil, nil)
					aux_labels = @center_labels.clone
					aux_labels.insert_node(top_point_node)
					#Now, we add the features of aux_labels
					next_features.push get_features_of_grid(aux_labels)
				end
			end
			if (!(wall_labels.get_node right_neighbor) && (wall_labels.get_node top_right_label) && (wall_labels.get_node bottom_right_label))
				action = Array.new(2)
				action[0] = 1
				action[1] = [1, 0, bottom_left_corner.x, 0, 1, bottom_left_corner.y]   
				#Now, we add the features just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [action[0], action[1]]
					right_point_node = LinearLinkedListNode.new(right_neighbor, nil, nil)
					aux_labels = @center_labels.clone
					aux_labels.insert_node(right_point_node)
					#Now, we add the features of aux_labels
					next_features.push get_features_of_grid(aux_labels)
				end			
			end
			if (!(wall_labels.get_node bottom_neighbor) && (wall_labels.get_node bottom_right_label) && (wall_labels.get_node bottom_left_label))
				action = Array.new(2)
				action[0] = 1
				action[1] = [0, 1, bottom_left_corner.x, -1, 0, bottom_left_corner.y + @wall_side]  
				#Now, we add the features just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [action[0], action[1]]
					bottom_point_node = LinearLinkedListNode.new(bottom_neighbor, nil, nil)
					aux_labels = @center_labels.clone
					aux_labels.insert_node(bottom_point_node)
					#Now, we add the features of aux_labels
					next_features.push get_features_of_grid(aux_labels)
				end
			end
			if (!(wall_labels.get_node left_neighbor) && (wall_labels.get_node bottom_left_label) && (wall_labels.get_node top_left_label))
				action = Array.new(2)
				action[0] = 1
				action[1] = [-1, 0, bottom_left_corner.x + @wall_side, 0, 1, bottom_left_corner.y]  
				#Now, we add the features just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [action[0], action[1]]
					left_point_node = LinearLinkedListNode.new(left_neighbor, nil, nil)
					aux_labels = @center_labels.clone
					aux_labels.insert_node(left_point_node)
					#Now, we add the features of aux_labels
					next_features.push get_features_of_grid(aux_labels)
				end
			end
			
		end

		return next_features
	end

	def get_features_of_grid(grid)
		features = Array.new(number_of_features,0)

		#Third, we go over the list in order to search neighbors
		grid.reset_iterator
		while (p = grid.get_next)
			number_of_neighbors = 0
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @wall_side, 0))  
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @wall_side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @wall_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @wall_side, p.key.y, 0))
			if grid.get_node top_neighbor
				number_of_neighbors += 1
			end
			if grid.get_node right_neighbor
				number_of_neighbors += 1
			end
			if grid.get_node bottom_neighbor
				number_of_neighbors += 1
			end
			if grid.get_node left_neighbor
				number_of_neighbors += 1
			end
			if number_of_neighbors > 0
				features[number_of_neighbors-1] += 1
			end
		end
		
		max = features.max
		features.each_index{ |i|
			#features[i] = features[i].quo(max)
			features[i] = features[i].quo(45)
		}

		return features
	end

	
	def is_final_state?(state)
		return false
	end
	
	def number_of_features
		return 4
	end
end

class SeedKitchenProblem
	
	attr_accessor :contour_face
	
	def initialize(contour_face, side)
		@side = side
		@contour_face = contour_face
		@module_side = (0.6).m #<--
	end
	
	def get_reward(state, is_final_step)
		reward  = 0
		
		orange_label =state.shape.p["Layer0"].get_node(Label.new("Green")).list.first.key	
		distributor_label = state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		features = get_features_of_grid(orange_label, distributor_label)
						
		features.each_with_index {|f, i|

			s = f
			reward += s
		}

		
		return reward
	end
	
	def get_features_of_grid(orange_label, distributor_label, print = false)
		added_orange = orange_label
		features = Array.new(number_of_features, 0)
		
		#First feature: the module is at a proper distance of the distributor
		
		distance = added_orange.point.distance distributor_label.point
		#Conversion to meters...
		aux_distance = distance * 3.93.m * 0.0254.m
		#distance = distance * 3.93
		proper_distance = true
		if ((distance > 4.m) || (distance < 2.m)) #<--
			proper_distance = false
		end
		
		if print
			UI.messagebox(aux_distance)
		end
		
		if proper_distance
			features[0] = 1
		end
		
		#The second feature is 1 if the added module is separated enough from the walls
		edges = Array.new
		@contour_face.entities.each { |e|
			if e.kind_of? Sketchup::Edge
				edges.push e
			end
		}
		separated = true
		point = added_orange.point
		i = 0
		while (i < edges.size && separated)
			distance = point_edge_distance(point, edges[i])
			is_projected = is_projected?(point, edges[i])
			if is_projected
				if distance < ((1.1).m + @module_side.quo(2)) #the label is in the center of the modules
					if (distance > @module_side.quo(2))
						separated = false
					end
				end
			end
			i += 1
		end
		if separated
			features[1] = 1
		end
		
		return features
	end
	
	def point_edge_distance(point, edge)
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			distance = point.distance_to_line(edge.line)
		else
			distance_start = point.distance(edge.start.position)
			distance_end = point.distance(edge.end.position)
			distance = distance_end
			if distance_start < distance_end
				distance = distance_start
			end
		end
		return distance
	end
	
	def is_projected?(point, edge)
		result = false
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			result = true
		end
		return result
	end

	def get_features(state_action, print = false)
		#The first feature is the distance w.r.t. the distributor
		a = state_action.action
		
		
		rule = Shade.project.execution.grammar.search_rule_by_id(a.rule_id)
		beta_orange = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new("Green")).list.first.key

		added_orange = beta_orange.clone
		added_orange.transform(a.transformation)
		
		if print
			transformed_orange_point = added_orange.clone
			transformed_orange_point.point.transform! Constants::AXIOM_T
			Sketchup.active_model.entities.add_cpoint transformed_orange_point.point
		end
		
		distributor_label = state_action.state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		
		features = get_features_of_grid(added_orange, distributor_label, print)
	
		

		return features
	end

	
	
	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	#Concretely, it removes scales
	def get_actions(state, get_features = true, print = false)
		actions = Array.new
		
		white_labels = state.shape.p["Layer0"].get_node(Label.new("White")).list
		black_labels = state.shape.p["Layer0"].get_node(Label.new("Black")).list
				
		white_labels.reset_iterator
		while (p = white_labels.get_next)
			top_neighbor = OrderedPoint.new(Geom::Point3d.new(p.key.x, p.key.y + @side, 0))  
			right_neighbor = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side, p.key.y, 0))
			
			if white_labels.get_node top_neighbor
				black_left = OrderedPoint.new(Geom::Point3d.new(p.key.x - @side.quo(2), p.key.y + @side.quo(2), 0))
				black_right = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y + @side.quo(2), 0))
				if black_labels.get_node black_right
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [1, 0, p.key.x, 0, 1, p.key.y] #transformation to apply  
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple	
					
					#Second possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [1, 0, p.key.x, 0, -1, p.key.y + @side] #transformation to apply  
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple	
				end
				if black_labels.get_node black_left
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [-1, 0, p.key.x, 0, 1, p.key.y] #transformation to apply  
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple
					
					#Second possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [-1, 0, p.key.x , 0, -1, p.key.y + @side] #transformation to apply  
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple
				end
			end
				
			if white_labels.get_node right_neighbor
				black_top = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y + @side.quo(2), 0))  
				black_bottom = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y - @side.quo(2), 0))
				if black_labels.get_node black_top
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, 1, p.key.x, 1, 0, p.key.y] #transformation to apply
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple
					
					#Second possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, -1, p.key.x + @side, 1, 0, p.key.y] #transformation to apply
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple
				end
				if black_labels.get_node black_bottom
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, 1, p.key.x, -1, 0, p.key.y] #transformation to apply
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple
					
					#Second possibility					
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, -1, p.key.x + @side, -1, 0, p.key.y ] #transformation to apply
					if get_features
						triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					end
					
					#Now, we add the triple	
					actions.push triple
				end				
			end
		end
		
		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)
		next_features = Array.new
		actions = get_actions(state)
		actions.each {|a|
			next_features.push a[2]
		}
		return next_features
	end
	
	
	def is_final_state?(state)
		return false

	end
	
	def number_of_features
		return 2
	end
end

class KitchenProblem
	
	attr_accessor :contour_face
	
	def initialize(contour_face, wall_side, total_meters)
		@contour_face = contour_face
		@wall_side = wall_side
		@total_meters = total_meters
		@module_side = (0.6).m
	end
	
	def get_reward(state, is_final_step)
		reward  = 0
			
		orange_labels =state.shape.p["Layer0"].get_node(Label.new("Green")).list	
		intersection_labels = state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		distributor_label = state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		
		features = get_features_of_grid(orange_labels, intersection_labels, distributor_label)
		
		features.each_with_index {|f, i|

			s = f
			reward += s
		}
		
		return reward
	end
	
	def point_edge_distance(point, edge)
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			distance = point.distance_to_line(edge.line)
		else
			distance_start = point.distance(edge.start.position)
			distance_end = point.distance(edge.end.position)
			distance = distance_end
			if distance_start < distance_end
				distance = distance_start
			end
		end
		return distance
	end
	
	def is_projected?(point, edge)
		result = false
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			result = true
		end
		return result
	end

	def get_features(state_action, print = false)
		#The unique feature is the distance w.r.t. the distributor
		a = state_action.action
		
		features = Array.new(number_of_features, 0)
		
		rule = Shade.project.execution.grammar.search_rule_by_id(a.rule_id)
		beta_orange = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new("Green")).list.first.key

		added_orange = beta_orange.clone
		added_orange.transform(a.transformation)
		
		beta_intersections = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		added_intersections = beta_intersections.clone
		added_intersections.reset_iterator
		while (p = added_intersections.get_next)
			p.key.transform(a.transformation)
		end
		
		if print 
			transformed_orange_point = added_orange.clone
			transformed_orange_point.point.transform! Constants::AXIOM_T
			Sketchup.active_model.entities.add_cpoint transformed_orange_point.point
		end
		
		orange_labels =state_action.state.shape.p["Layer0"].get_node(Label.new("Green")).list
		orange_labels_aux = orange_labels.clone
		
		orange_labels_aux.insert_node(LinearLinkedListNode.new(added_orange, nil, nil))
		
		intersection_labels = state_action.state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		intersection_labels_aux = intersection_labels.clone
		added_intersections.reset_iterator
		while (p = added_intersections.get_next)
			intersection_labels_aux.insert_node(LinearLinkedListNode.new(p.key, nil, nil))
		end
		
		distributor_label = state_action.state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		
		features = get_features_of_grid(orange_labels_aux, intersection_labels_aux, distributor_label)

		return features
	end
	
	def get_features_of_grid(orange_labels, intersection_labels, distributor_label)
		
		features = Array.new(6, 0)
		
		edges = Array.new
		face = nil
		@contour_face.entities.each {|e|
			if e.kind_of? Sketchup::Edge
				edges.push e
			elsif e.kind_of? Sketchup::Face
				face = e
			end
		}
		
		#First (condition): are the kitchen modules inside the walls?
		#For doing this, we iterate over the intersection points and see if they are inside the face
		intersection_labels.reset_iterator
		inside = true
		while ((p = intersection_labels.get_next) && inside)
			point = p.key.point
			if (face.classify_point point) > Sketchup::Face::PointOnEdge
				inside = false
			end
		end
		
		if inside
			features[0] = 1
		end
		
		#Second (condition): are the modules side-accessible? (that is, they are not surrounded by other modules)
		#To do this, check if all the modules have less than three neighbors and they are not in a square
		orange_labels.reset_iterator
		accessible = true
		while ((p = orange_labels.get_next) && accessible)
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @module_side, 0))  
			top_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y + @module_side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y, 0))
			bottom_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y - @module_side, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @module_side, 0))
			bottom_left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side, p.key.y - @module_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side, p.key.y, 0))
			top_left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side, p.key.y + @module_side, 0))
			top_right_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side*2, p.key.y + @module_side, 0))
			bottom_right_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side*2, p.key.y - @module_side, 0))
			top_top_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y + @module_side*2, 0))
			bottom_bottom_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y - @module_side*2, 0))
			
			number_of_neighbors = 0
			if accessible && (orange_labels.get_node top_neighbor)
				number_of_neighbors += 1
			end
			if accessible && (orange_labels.get_node right_neighbor)
				number_of_neighbors += 1
			end
			if accessible && (orange_labels.get_node bottom_neighbor)
				number_of_neighbors += 1
			end
			if accessible && (orange_labels.get_node left_neighbor)
				number_of_neighbors += 1
			end
			if number_of_neighbors > 2
				accessible = false
			else
				#top right square
				if (accessible && (orange_labels.get_node top_neighbor) && (orange_labels.get_node top_right_neighbor) && (orange_labels.get_node right_neighbor))
					accessible = false
				end
				#bottom right square
				if (accessible && (orange_labels.get_node right_neighbor) && (orange_labels.get_node bottom_right_neighbor) && (orange_labels.get_node bottom_neighbor))
					accessible = false
				end
				#bottom left square
				if (accessible && (orange_labels.get_node bottom_neighbor) && (orange_labels.get_node bottom_left_neighbor) && (orange_labels.get_node left_neighbor))
					accessible = false
				end
				#top left square
				if (accessible && (orange_labels.get_node left_neighbor) && (orange_labels.get_node top_left_neighbor) && (orange_labels.get_node top_neighbor))
					accessible = false
				end 
				#bottom-top diagonal
				if (accessible && (orange_labels.get_node bottom_left_neighbor) && (orange_labels.get_node top_right_neighbor))
					accessible = false
				end
				#top-bottom diagonal
				if (accessible && (orange_labels.get_node top_left_neighbor) && (orange_labels.get_node bottom_right_neighbor))
					accessible = false
				end
				#bottom-topright diagonal
				if (accessible && (orange_labels.get_node bottom_left_neighbor) && (orange_labels.get_node top_right_right_neighbor))
					accessible = false
				end
				
				#top-bottomright diagonal
				if (accessible && (orange_labels.get_node top_left_neighbor) && (orange_labels.get_node bottom_right_right_neighbor))
					accessible = false
				end
				
				#bottom-toptopright diagonal
				if (accessible && (orange_labels.get_node bottom_left_neighbor) && (orange_labels.get_node top_top_right_neighbor))
					accessible = false
				end
				
				#top-bottombottomright diagonal
				if (accessible && (orange_labels.get_node top_left_neighbor) && (orange_labels.get_node bottom_bottom_right_neighbor))
					accessible = false
				end
			end
		end
		
		if accessible
			features[1] = 1
		end
		
		#Third (condition): are the modules separated enough from the walls?
		#To do this, compute the distance between each point and each edge of the @contour_face
		#If is >= (1.10 + @module_side.quo(2)), it is ok
		#If it is < 1.10, then...
			#If the distance is exactly @module_side.quo(2), then it is ok
			
			#If the distance is > @module_side.quo(2), then...
				#If the point has the correspondent neighbor, then it is ok
				
				#If the point does not have the correspondent neighbor, then it is wrong
		
		orange_labels.reset_iterator
		separated = true
		while ((p = orange_labels.get_next) && separated)
			point = p.key.point
			i = 0
			while (i < edges.size && inside)
				distance = point_edge_distance(point, edges[i])
				is_projected = is_projected?(point, edges[i])
				if is_projected
					if distance < ((1.1).m + @module_side.quo(2)) #the label is in the center of the modules  
						if (distance > @module_side.quo(2))
							#segments are horizontal or vertical
							if (edges[i].start.position.x == edges[i].end.position.x) #vertical
								if edges[i].start.position.x < point.x #the edge is on the left
									#Look for left neighbor
									left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side, p.key.y, 0))  
									if !orange_labels.get_node left_neighbor
										separated = false
									end
								elsif edges[i].start.position.x > point.x #the edge is on the right
									#Look for right neighbor
									right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y, 0))
									if !orange_labels.get_node right_neighbor
										separated = false
									end
								end								
							elsif (edges[i].start.position.y == edges[i].end.position.y) #horizontal
								if edges[i].start.position.y < point.y #the edge is down the point
									#Look for bottom neighbor
									bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @module_side, 0))
									if !orange_labels.get_node bottom_neighbor
										separated = false
									end
								elsif edges[i].start.position.y > point.y #the edge is up the point
									#Look for top neighbor
									top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @module_side, 0))
									if !orange_labels.get_node top_neighbor
										separated = false
									end
								end	
							end
						end
					end
				end
				i += 1
			end
		end
			
		if separated
			features[2] = 1
		end
		#Fourth (condition): are the modules separated enough between them?
		#To do this, for each orange label...
		#If it does not have a x-neighbor, see if there is a xx-neighbor. In that case, it is wrong
		
		orange_labels.reset_iterator
		separated_modules = true
		while ((p = orange_labels.get_next) && separated_modules)
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @module_side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @module_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side, p.key.y, 0))
			
			number_of_neighbors = 0
			if !orange_labels.get_node top_neighbor
				top_top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @module_side*2, 0))
				if orange_labels.get_node top_top_neighbor
					separated_modules = false
				end
			end
			if !orange_labels.get_node right_neighbor
				right_right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side*2, p.key.y, 0))
				if orange_labels.get_node right_right_neighbor
					separated_modules = false
				end
			end
			if !orange_labels.get_node bottom_neighbor
				bottom_bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @module_side*2, 0))
				if orange_labels.get_node bottom_bottom_neighbor
					separated_modules = false
				end
			end
			if !orange_labels.get_node left_neighbor
				left_left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side * 2, p.key.y, 0))
				if orange_labels.get_node left_left_neighbor
					separated_modules = false
				end
			end
		end
		
		if separated_modules
			features[3] = 1
		end
		
		#Fifth (condition): are there between six and then modules?
		if ((orange_labels.size >= 6) && (orange_labels.size <= 10))
			features[4] = 1
		end
		
		#Sixth (condition): Are the modules at a proper distance of the distributor?
		proper_distance = true
		orange_labels.reset_iterator
		while ((p = orange_labels.get_next) && proper_distance)
			distance = p.key.point.distance distributor_label.point
			if ((distance > 5.m) || (distance < (1.2).m))
				proper_distance = false
			end
		end
		if proper_distance
			features[5] = 1
		end
		
		return features
	end

	
	
	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	#Concretely, it removes scales
	def get_actions(state, get_features = true, print = false)
		actions = Array.new
		
		orange_labels = state.shape.p["Layer0"].get_node(Label.new("Green")).list
		
		orange_labels.reset_iterator
		while (p = orange_labels.get_next)
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @module_side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @module_side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @module_side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @module_side, p.key.y, 0))
			
			bottom_left_corner = OrderedPoint.new(Point.new(p.key.x - @module_side.quo(2), p.key.y - @module_side.quo(2), 0))
			
			if (!(orange_labels.get_node top_neighbor))

				triple = Array.new(3)
				triple[0] = 1 #rule to apply
				triple[1] = [0, -1, bottom_left_corner.x + @module_side, 1, 0, bottom_left_corner.y] #transformation to apply
				if get_features
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
				end

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			if (!(orange_labels.get_node right_neighbor))

				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [1, 0, bottom_left_corner.x, 0, 1, bottom_left_corner.y]
				if get_features
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
				end

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			if (!(orange_labels.get_node bottom_neighbor))

				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [0, 1, bottom_left_corner.x, -1, 0, bottom_left_corner.y + @module_side]
				if get_features
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
				end

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			if (!(orange_labels.get_node left_neighbor))
				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [-1, 0, bottom_left_corner.x + @module_side, 0, 1, bottom_left_corner.y]
				if get_features
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
				end

				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
		end

		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)

		next_features = Array.new
		actions = get_actions(state)
		actions.each {|a|
			next_features.push a[2]
		}

		return next_features.shuffle
	end

	
	def is_final_state?(state)
		false

	end
	
	def number_of_features
		return 6
	end
	
end

class SeedBathProblem
	
	attr_accessor :contour_face
	
	def initialize(contour_face, side)
		@side = side
		@contour_face = contour_face
		@module_side = (1.8).m #larger side of the module
	end
	
	def get_reward(state, is_final_step)
		reward  = 0
		
		blue_label = state.shape.p["Layer0"].get_node(Label.new("Blue")).list.first.key	
		intersection_labels = state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		orange_labels = state.shape.p["Layer0"].get_node(Label.new("Green")).list
		distributor_label = state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		features = get_features_of_grid(blue_label, intersection_labels, orange_labels, distributor_label)
						
		features.each_with_index {|f, i|

			s = f
			reward += s
		}

		
		return reward
	end
	
	def get_features_of_grid(blue_label, intersection_labels, orange_labels, distributor_label, print = false)
		added_blue = blue_label
		features = Array.new(number_of_features, 0)
		
		edges = Array.new
		face = nil
		@contour_face.entities.each {|e|
			if e.kind_of? Sketchup::Edge
				edges.push e
			elsif e.kind_of? Sketchup::Face
				face = e
			end
		}
		
		#First feature: the module is not overlapping with the kitchen modules
		orange_labels.reset_iterator
		not_overlapping_kitchen = true
		while ((p = orange_labels.get_next) && not_overlapping_kitchen)
			distance = p.key.point.distance added_blue.point
			if distance < 3.m
				not_overlapping_kitchen = false
			end
		end
		if not_overlapping_kitchen
			features[0] = 1
		end
		
		
		#Second feature: the module is at a proper distance of the distributor
		distance = added_blue.point.distance distributor_label.point
		#Conversion to meters...
		aux_distance = distance * 3.93.m * 0.0254.m  
		#distance = distance * 3.93
		proper_distance = true
		if (distance > 6.m) || (distance < 2.m)
			proper_distance = false
		end
		
		if print
			#UI.messagebox(aux_distance)
		end
		
		if proper_distance
			features[1] = 1
		end
		
		#The third feature is 1 if the added module is separated enough from the walls
		separated = true
		point = added_blue.point
		i = 0
		while (i < edges.size && separated)
			distance = point_edge_distance(point, edges[i])
			is_projected = is_projected?(point, edges[i])
			if is_projected
				if ((distance == (0.55).m) || (distance == (1.1).m ) || (distance == (0.1).m))
					separated = false
				end
			end
			i += 1
		end
		if separated
			features[2] = 1
		end
		
		return features
	end
	
	def point_edge_distance(point, edge)
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			distance = point.distance_to_line(edge.line)
		else
			distance_start = point.distance(edge.start.position)
			distance_end = point.distance(edge.end.position)
			distance = distance_end
			if distance_start < distance_end
				distance = distance_start
			end
		end
		return distance
	end
	
	def is_projected?(point, edge)
		result = false
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			result = true
		end
		return result
	end

	def get_features(state_action, print = false)
		a = state_action.action
		
		
		rule = Shade.project.execution.grammar.search_rule_by_id(a.rule_id)
		beta_blue = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new("Blue")).list.first.key

		added_blue = beta_blue.clone
		added_blue.transform(a.transformation)
		
		beta_intersections = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		added_intersections = beta_intersections.clone
		added_intersections.reset_iterator
		while (p = added_intersections.get_next)
			p.key.transform(a.transformation)
		end
		
		if print 
			transformed_blue_point = added_blue.clone
			transformed_blue_point.point.transform! Constants::AXIOM_T
			Sketchup.active_model.entities.add_cpoint transformed_blue_point.point
		end
		
		intersection_labels = state_action.state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		intersection_labels_aux = intersection_labels.clone
		added_intersections.reset_iterator
		while (p = added_intersections.get_next)
			intersection_labels_aux.insert_node(LinearLinkedListNode.new(p.key, nil, nil))
		end
		
		orange_labels =state_action.state.shape.p["Layer0"].get_node(Label.new("Green")).list
		
		distributor_label = state_action.state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		
		features = get_features_of_grid(added_blue, intersection_labels_aux, orange_labels, distributor_label, print)

		return features
	end

	
	
	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	#Concretely, it removes scales
	def get_actions(state, print = false)
		actions = Array.new
		
		white_labels = state.shape.p["Layer0"].get_node(Label.new("White")).list
		black_labels = state.shape.p["Layer0"].get_node(Label.new("Black")).list
				
		white_labels.reset_iterator
		while (p = white_labels.get_next)
			top_neighbor = OrderedPoint.new(Geom::Point3d.new(p.key.x, p.key.y + @side, 0))
			right_neighbor = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side, p.key.y, 0))
			
			if white_labels.get_node top_neighbor
				black_left = OrderedPoint.new(Geom::Point3d.new(p.key.x - @side.quo(2), p.key.y + @side.quo(2), 0))
				black_right = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y + @side.quo(2), 0))
				if black_labels.get_node black_right
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [1, 0, p.key.x, 0, 1, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple	
					
					#Second possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [1, 0, p.key.x, 0, -1, p.key.y + @side] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple	
				end
				if black_labels.get_node black_left
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [-1, 0, p.key.x, 0, 1, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
					
					#Second possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [-1, 0, p.key.x , 0, -1, p.key.y + @side] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
				end
			end
				
			if white_labels.get_node right_neighbor
				black_top = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y + @side.quo(2), 0))
				black_bottom = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y - @side.quo(2), 0))
				if black_labels.get_node black_top
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, 1, p.key.x, 1, 0, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
					
					#Second possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, -1, p.key.x + @side, 1, 0, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
				end
				if black_labels.get_node black_bottom
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, 1, p.key.x, -1, 0, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
					
					#Second possibility					
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, -1, p.key.x + @side, -1, 0, p.key.y ] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
				end				
			end
		end
		
		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)
		next_features = Array.new
		actions = get_actions(state)
		actions.each {|a|
			next_features.push a[2]
		}
		return next_features
	end
	
	
	def is_final_state?(state)
		false

	end
	
	def number_of_features
		return 3
	end
end
class BathProblem
	
	attr_accessor :contour_face
	
	def initialize(contour_face, side)
		@side = side
		@contour_face = contour_face
		@module_side = (1.8).m #larger side of the module
	end
	
	def get_reward(state, is_final_step)
		reward  = 0
		
		blue_labels = state.shape.p["Layer0"].get_node(Label.new("Blue")).list
		intersection_labels = state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		orange_labels = state.shape.p["Layer0"].get_node(Label.new("Green")).list
		distributor_label = state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		features = get_features_of_grid(blue_labels, intersection_labels, orange_labels, distributor_label)
						
		features.each_with_index {|f, i|

			s = f
			reward += s
		}

		
		return reward
	end
	
	def get_features_of_grid(blue_labels, intersection_labels, orange_labels, distributor_label, print = false)
		features = Array.new(number_of_features, 0)
		
		edges = Array.new
		face = nil
		@contour_face.entities.each {|e|
			if e.kind_of? Sketchup::Edge
				edges.push e
			elsif e.kind_of? Sketchup::Face
				face = e
			end
		}
		
		
		#First feature: the modules are not overlapping with the kitchen modules
		orange_labels.reset_iterator
		not_overlapping_kitchen = true
		while ((p = orange_labels.get_next) && not_overlapping_kitchen)
			blue_labels.reset_iterator
			while ((q = blue_labels.get_next) && not_overlapping_kitchen)
				distance = p.key.point.distance q.key.point
				if distance < 3.m
					not_overlapping_kitchen = false
				end
			end
		end
		if not_overlapping_kitchen
			features[0] = 1
		end
		
	
		proper_distance = true
		blue_labels.reset_iterator
		while ((p = blue_labels.get_next) && proper_distance)
			#Second feature: the modules are at a proper distance of the distributor
			distance = p.key.point.distance distributor_label.point

			if (distance > 6.m) || (distance < 2.m)
				proper_distance = false
			end
		end
		
		
		if proper_distance
			features[1] = 1
		end
		
		#The third feature is 1 if the modules are separated enough from the walls
		separated = true
		blue_labels.reset_iterator
		i = 0
		while ((p = blue_labels.get_next) && separated)
			while (i < edges.size && separated)
				distance = point_edge_distance(p.key.point, edges[i])
				is_projected = is_projected?(p.key.point, edges[i])
				if is_projected
					if ((distance < (0.45).m) || (distance == (1.1).m) || (distance == (0.55).m) || (distance == (0.1).m))
						separated = false
					end
				end
				i += 1
			end
		end
		if separated
			features[2] = 1
		end
		
		#The fourth feature is 1 if there is between 2 and 3 modules
		if ((blue_labels.size >= 2) && (blue_labels.size <= 3))
			features[3] = 1
		end
		
		return features
	end
	
	def point_edge_distance(point, edge)
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			distance = point.distance_to_line(edge.line)
		else
			distance_start = point.distance(edge.start.position)
			distance_end = point.distance(edge.end.position)
			distance = distance_end
			if distance_start < distance_end
				distance = distance_start
			end
		end
		return distance
	end
	
	def is_projected?(point, edge)
		result = false
		projected_point = OrderedPoint.new(point.project_to_line(edge.line))
		segment = Segment.new(OrderedPoint.new(edge.start.position), OrderedPoint.new(edge.end.position))
		if segment.coincident? projected_point
			result = true
		end
		return result
	end

	def get_features(state_action, print = false)
		#The first feature is the distance w.r.t. the distributor
		a = state_action.action
		
		
		rule = Shade.project.execution.grammar.search_rule_by_id(a.rule_id)
		beta_blue = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new("Blue")).list.first.key

		added_blue = beta_blue.clone
		added_blue.transform(a.transformation)
		
		beta_intersections = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		added_intersections = beta_intersections.clone
		added_intersections.reset_iterator
		while (p = added_intersections.get_next)
			p.key.transform(a.transformation)
		end
		
		if print 
			transformed_blue_point = added_blue.clone
			transformed_blue_point.point.transform! Constants::AXIOM_T
			Sketchup.active_model.entities.add_cpoint transformed_blue_point.point
		end
		
		blue_labels = state_action.state.shape.p["Layer0"].get_node(Label.new("Blue")).list
		blue_labels_aux = blue_labels.clone
		blue_labels_aux.insert_node(LinearLinkedListNode.new(added_blue, nil, nil))
		
		intersection_labels = state_action.state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		intersection_labels_aux = intersection_labels.clone
		added_intersections.reset_iterator
		while (p = added_intersections.get_next)
			intersection_labels_aux.insert_node(LinearLinkedListNode.new(p.key, nil, nil))
		end
		
		orange_labels =state_action.state.shape.p["Layer0"].get_node(Label.new("Green")).list
		
		distributor_label = state_action.state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		
		features = get_features_of_grid(blue_labels_aux, intersection_labels_aux, orange_labels, distributor_label, print)

		return features
	end

	
	
	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	#Concretely, it removes scales
	def get_actions(state, print = false)
		actions = Array.new
		
		b_actions = Shade.project.execution.brothers(state.shape)
		
		b_actions.each { |a|
			triple = Array.new(3)
			triple[0] = a[0]
			triple[1] = a[1]
			s_a = StateAction.new(state, Action.new(a[0], a[1]))
			triple[2] = get_features(s_a)
			
			#Now, we add the triple just in case the action has not been taken before
			if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
				actions.push triple
			end
			
		}
		
		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)
		next_features = Array.new
		actions = get_actions(state)
		actions.each {|a|
			next_features.push a[2]
		}
		return next_features
	end
	
	
	def is_final_state?(state)

		return false
	end
	
	def number_of_features
		return 4
	end
end

class NonEspecializedSpacesProblem
	def initialize(side)
		@side = side
	end
	
	def get_reward(state, is_final_step)
		reward  = 0
		
		gray_labels = state.shape.p["Layer0"].get_node(Label.new("DeepSkyBlue")).list
		intersection_labels = state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		blue_labels = state.shape.p["Layer0"].get_node(Label.new("Yellow")).list
		orange_labels = state.shape.p["Layer0"].get_node(Label.new("Green")).list
		distributor_label = state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		features = get_features_of_grid(state, gray_labels, blue_labels, orange_labels, intersection_labels, distributor_label)
						
		features.each_with_index {|f, i|

			s = f
			reward += s
		}
		
		return reward
	end

	def get_features(state_action, print = false)
		features = Array.new(number_of_features,0)
		
		#The first feature is the distance w.r.t. the distributor
		a = state_action.action
		
		rule = Shade.project.execution.grammar.search_rule_by_id(a.rule_id)
		beta_gray = rule.beta.p["Layer0"].get_node(Label.new("DeepSkyBlue")).list.first.key

		added_gray = beta_gray.clone
		added_gray.transform(a.transformation)
		
		gray_labels = state_action.state.shape.p["Layer0"].get_node(Label.new("DeepSkyBlue"))
		gray_labels_aux = LinearLinkedList.new
		if gray_labels
			gray_labels_aux = gray_labels.list.clone
		end
		gray_labels_aux.insert_node(LinearLinkedListNode.new(added_gray, nil, nil))
		
		blue_labels = state_action.state.shape.p["Layer0"].get_node(Label.new("Yellow")).list
		orange_labels = state_action.state.shape.p["Layer0"].get_node(Label.new("Green")).list
		
		intersection_labels =state_action.state.shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		
		distributor_label = state_action.state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		
		features = get_features_of_grid(state_action.state, gray_labels_aux, blue_labels, orange_labels, intersection_labels, distributor_label)

		return features
	end
	
	def get_features_of_grid(state, gray_labels, blue_labels, orange_labels, intersection_labels, distributor_label)
		
		features = Array.new(number_of_features, 0)
		
		#First feature: we can inscribe a circle of 3 meters of diameter in every non-especialized space
		gray_labels.reset_iterator
		circle = true
		
		while ((p = gray_labels.get_next) && circle)
			#Distance w.r.t. intersection labels
			intersection_labels.reset_iterator
			while ((q = intersection_labels.get_next) && circle)
				distance = p.key.point.distance q.key.point
				if distance < (1.5).m #Radius of 1.5 meters
					circle = false
				end
			end
			
			#Distance w.r.t distributor
			#if circle
			#	distance = p.key.point.distance distributor_label.point
			#	if distance < 15 #Radius of 1.5 meters
			#		circle = false
			#	end
			#end
		end
		
		if circle
			features[0] = 1
		end
		
		#Second feature: there is a space near the bathroom
		
		near_bathroom = false
		l_bathroom = nil
		gray_labels.reset_iterator
		while ((p = gray_labels.get_next) && !near_bathroom)
			blue_labels.reset_iterator
			while ((q = blue_labels.get_next) && !near_bathroom)
				distance = p.key.point.distance q.key.point
				if distance < (4.5).m
					near_bathroom = true
					l_bathroom = p
				end
			end
		end
		
		if near_bathroom
			features[1] = 1
		end
		
		#Third feature: there is a space near the kitchen
		
		near_kitchen = false
		l_kitchen = nil
		gray_labels.reset_iterator
		while ((p = gray_labels.get_next) && !near_kitchen)
			orange_labels.reset_iterator
			while ((q = orange_labels.get_next) && !near_kitchen)
				distance = p.key.point.distance q.key.point
				if distance < (4.5).m
					near_kitchen = true
					l_kitchen = p
				end
			end
		end
		
		if near_kitchen
			features[2] = 1
		end
		
		#Fourth feature: the spaces are separated enough between them
		separated = true
		if (l_bathroom && l_kitchen)
			distance = l_bathroom.key.point.distance l_kitchen.key.point
			#puts distance
			if distance < 3.m
				separated = false
			end
		end
		
		if separated 
			features[3] = 1
		end
		
		#Fifth feature: proper distance to the distributor
		proper_distance = true
		gray_labels.reset_iterator
		while ((p = gray_labels.get_next) && proper_distance)
			#Third feature: the modules are at a proper distance of the distributor
			distance = p.key.point.distance distributor_label.point

			if (distance > 6.m) || (distance < 2.m)
				proper_distance = false
			end
		end
		
		
		if proper_distance
			features[4] = 1
		end
		
		#Sixth feature: if there is only one label, then there is space for the other
		if !(l_bathroom && l_kitchen)
			if l_bathroom
				possible_labels = get_possible_labels(state.shape, l_bathroom)
				possible_labels.reset_iterator
				while ((p = possible_labels.get_next) && !l_kitchen)
					orange_labels.reset_iterator
					while ((q = orange_labels.get_next) && !l_kitchen)
						distance = p.key.point.distance q.key.point
						if distance < (4.5).m
							distance = l_bathroom.key.point.distance q.key.point
							#puts distance
							if distance > 3.m
								l_kitchen = q
							end
						end
					end
					
				end
			elsif l_kitchen
				possible_labels = get_possible_labels(state.shape, l_kitchen)
				possible_labels.reset_iterator
				while ((p = possible_labels.get_next) && !l_bathroom)
					blue_labels.reset_iterator
					while ((q = blue_labels.get_next) && !l_bathroom)
						distance = p.key.point.distance q.key.point
						if distance < (4.5).m
							distance = q.key.point.distance l_kitchen.key.point
							#puts distance
							if distance > 3.m
								l_bathroom = q
							end
						end
					end
				end
			end
			if (l_bathroom && l_kitchen) 
				features[5] = 1
			end
		elsif (l_bathroom && l_kitchen)
			features[5] = 1
		end
		
		return features
		
	end
	
	def get_possible_labels(shape, ne_label)
		
		possible_labels = LinearLinkedList.new
		
		intersection_labels = shape.p["Layer0"].get_node(Label.new(Constants::INTERSECTION_LABEL)).list
		
		black_labels = shape.p["Layer0"].get_node(Label.new("Black")).list
		black_labels_aux = black_labels.clone
		
		black_labels_aux.delete_node(ne_label.key)
		
		while (p = black_labels_aux.get_next)
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @side, p.key.y, 0))
			
			ok = true
			
			if !black_labels_aux.get_node top_neighbor
				ok = false
			end
			if !black_labels_aux.get_node right_neighbor
				ok = false
			end
			if !black_labels_aux.get_node bottom_neighbor
				ok = false
			end
			if !black_labels_aux.get_node left_neighbor
				ok = false
			end
			
			if ok #The 4 neighbors are present
				
				#Distance w.r.t. intersection labels
				circle = true
				intersection_labels.reset_iterator
				while ((q = intersection_labels.get_next) && circle)
					distance = p.key.point.distance q.key.point
					if distance < (1.5).m #Radius of 1.5 meters
						circle = false
					end
				end
				
				if circle
					possible_labels.insert_node p.clone
				end
				
			end
		end
		
		return possible_labels
		
	end

	

	
	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	def get_actions(state, get_features = true, print = false)
		actions = Array.new

		black_labels = state.shape.p["Layer0"].get_node(Label.new("Black")).list
		black_labels.reset_iterator
		while (p = black_labels.get_next)
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + @side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + @side, p.key.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - @side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - @side, p.key.y, 0))
			
			ok = true
			
			if !black_labels.get_node top_neighbor
				ok = false
			end

			if !black_labels.get_node right_neighbor
				ok = false
			end

			if !black_labels.get_node bottom_neighbor
				ok = false
			end

			if !black_labels.get_node left_neighbor
				ok = false
			end

			
			if ok
				triple = Array.new(3)
				triple[0] = 1
				triple[1] = [1, 0, p.key.x, 0, 1, p.key.y]
				if get_features
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
				end
				
				#Now, we add the triple just in case the action has not been taken before
				if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
					actions.push triple
				end
			end
			
		end

		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)
		next_features = Array.new
		actions = get_actions(state)
		actions.each {|a|
			next_features.push a[2]
		}
		return next_features
	end
	
	
	def is_final_state?(state)
		
		return false

	end
	
	def number_of_features
		return 6
	end
	
end





class EntranceProblem
	
	def initialize(side)
		@side = side
	end
	
	def get_reward(state, is_final_step)
		reward  = 0
		
		orange_labels =state.shape.p["Layer0"].get_node(Label.new("Green")).list
		brown_label = state.shape.p["Layer0"].get_node(Label.new("Brown")).list.first.key
		distributor_label = state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		blue_labels = state.shape.p["Layer0"].get_node(Label.new("Yellow")).list
		features = get_features_of_grid(brown_label, orange_labels, distributor_label, blue_labels)
						
		features.each_with_index {|f, i|

			s = f
			reward += s
		}

		
		return reward
	end
	
	def get_features_of_grid(brown_label, orange_labels, distributor_label, blue_labels, print = false)
		added_brown = brown_label
		features = Array.new(number_of_features, 0)
		
		
		#The first feature is 1 if the entrance is separated enough from all the kitchen modules
		orange_labels.reset_iterator
		far_enough = true
		while ((p = orange_labels.get_next) && far_enough)
			
			distance = p.key.point.distance brown_label.point
			if distance < 1.m
				far_enough = false
			end
		end
		if far_enough
			features[0] = 1
		end
		
		#The second feature is 1 if the entrance is close enough to some kitchen module
		orange_labels.reset_iterator
		close_enough = false
		while ((p = orange_labels.get_next) && !close_enough)
			
			distance = p.key.point.distance brown_label.point
			if distance < 2.m
				close_enough = true
			end
		end
		
		if close_enough
			features[1] = 1
		end
		
		#The third feature is 1 if the entrance is far enough from the bathroom modules 
		blue_labels.reset_iterator
		far_enough_bath = true
		while ((p = blue_labels.get_next) && far_enough_bath)
			
			distance = p.key.point.distance brown_label.point
			if distance < 3.m
				far_enough_bath = false
			end
		end
		if far_enough_bath
			features[2] = 1
		end
		
		#The fourth feature is 1 if the entrance is close enough to the distributor
		close_enough_distributor = false
		distance = distributor_label.point.distance brown_label.point
		if distance < 4.m
			close_enough_distributor = true
		end
		if close_enough_distributor
			features[3] = 1
		end
		
		return features
	end

	def get_features(state_action, print = false)
		#The first feature is the distance w.r.t. the distributor
		a = state_action.action
		
		
		rule = Shade.project.execution.grammar.search_rule_by_id(a.rule_id)
		beta_brown = rule.beta_minus_alpha.p["Layer0"].get_node(Label.new("Brown")).list.first.key

		added_brown = beta_brown.clone
		added_brown.transform(a.transformation)
		
		if print
			transformed_brown_point = added_brown.clone
			transformed_brown_point.point.transform! Constants::AXIOM_T
			Sketchup.active_model.entities.add_cpoint transformed_brown_point.point
		end
		
		orange_labels = state_action.state.shape.p["Layer0"].get_node(Label.new("Green")).list
		distributor_label = state_action.state.shape.p["Layer0"].get_node(Label.new("RosyBrown")).list.first.key
		blue_labels = state_action.state.shape.p["Layer0"].get_node(Label.new("Yellow")).list
		
		features = get_features_of_grid(added_brown, orange_labels, distributor_label, blue_labels, print)
	
		

		return features
	end
	
#def get_actions_general(state, print = false)
#    actions = Array.new
#    
#    b_actions = Shade.project.execution.brothers(state.shape)
#    
#    b_actions.each { |a|
#      triple = Array.new(3)
#      triple[0] = a[0]
#      triple[1] = a[1]
#      s_a = StateAction.new(state, Action.new(a[0], a[1]))
#      triple[2] = get_features(s_a)
#      
#      puts"TRIPLE general #{triple[1][0]} #{triple[1][1]} #{triple[1][2]} #{triple[1][3]} #{triple[1][4]} #{triple[1][5]}"
#      
#      #Now, we add the triple just in case the action has not been taken before
#      if !Shade.project.execution.execution_history.include? [triple[0], triple[1]]
#        actions.push triple
#      end
#      
#    }
#    
#    return actions
#  end

	#Returns an array of triples [rule_id, transformation, features].
	#This method returns applicable actions. but not every applicable action is returned. That is, this method is correct but not complete.
	#Concretely, it removes scales
	def get_actions(state, print = false)
		actions = Array.new
		
		white_labels = state.shape.p["Layer0"].get_node(Label.new("White")).list
		black_labels = state.shape.p["Layer0"].get_node(Label.new("Black")).list
				
		white_labels.reset_iterator
		while (p = white_labels.get_next)
			top_neighbor = OrderedPoint.new(Geom::Point3d.new(p.key.x, p.key.y + @side, 0))
			right_neighbor = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side, p.key.y, 0))
			
			if white_labels.get_node top_neighbor
				black_left = OrderedPoint.new(Geom::Point3d.new(p.key.x - @side.quo(2), p.key.y + @side.quo(2), 0))
				black_right = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y + @side.quo(2), 0))
				if black_labels.get_node black_right
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [1, 0, p.key.x, 0, 1, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple	
					#puts"TRIPLE ad_hoc #{triple[1][0]} #{triple[1][1]} #{triple[1][2]} #{triple[1][3]} #{triple[1][4]} #{triple[1][5]} "
				end
				if black_labels.get_node black_left
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [-1, 0, p.key.x, 0, 1, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
					#puts"TRIPLE ad_hoc #{triple[1][0]} #{triple[1][1]} #{triple[1][2]} #{triple[1][3]} #{triple[1][4]} #{triple[1][5]}"
				end
			end
				
			if white_labels.get_node right_neighbor
				black_top = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y + @side.quo(2), 0))
				black_bottom = OrderedPoint.new(Geom::Point3d.new(p.key.x + @side.quo(2), p.key.y - @side.quo(2), 0))
				if black_labels.get_node black_top
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, 1, p.key.x, 1, 0, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
					#puts"TRIPLE ad_hoc #{triple[1][0]} #{triple[1][1]} #{triple[1][2]} #{triple[1][3]} #{triple[1][4]} #{triple[1][5]}"
				end
				if black_labels.get_node black_bottom
					#First possibility
					triple = Array.new(3)
					triple[0] = 1 #rule to apply
					triple[1] = [0, 1, p.key.x, -1, 0, p.key.y] #transformation to apply
					triple[2] = get_features(StateAction.new(state, Action.new(triple[0], triple[1])))
					
					#Now, we add the triple	
					actions.push triple
					#puts"TRIPLE ad_hoc #{triple[1][0]} #{triple[1][1]} #{triple[1][2]} #{triple[1][3]} #{triple[1][4]} #{triple[1][5]}"
				end				
			end
		end
		
		return actions.shuffle
	end

	#Returns an array of arrays, containing the features for the next possible actions
	def get_next_features(state)
		next_features = Array.new
    #action2 = get_actions_general(state)
		actions = get_actions(state)
		
		actions.each {|a|
			next_features.push a[2]
		}
		return next_features
	end
	
	
	def is_final_state?(state)
		return false

	end
	
	def number_of_features
		return 4
	end
end

#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#Class that represents a state for a reinforcement learning problem
class State
  attr_accessor :shape
  
  def initialize(shape)
    @shape = shape
  end
  
  def ==(other_state)
    result = false
    if other_state.kind_of? State
      result = (@shape == other_state.shape)
    end
    return result
  end
  
  def clone
    return State.new(@shape.clone)
  end
  
  def eql?(other_state)
    result = false
    if other_state.kind_of? State
      result = (@shape == other_state.shape)
    end
    return result
  end
  
  def hash
    return @shape.hash
  end
end

#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#Class that represents an action for a reinforcement learning problem
class Action
  attr_accessor :rule_id
  attr_accessor :transformation
  
  def initialize(rule_id, transformation)
    @rule_id = rule_id
    @transformation = transformation
  end
  
  def ==(other_action)
    result = false
    if other_action.kind_of? Action
      result = ((@rule_id == other_action.rule_id) && (@transformation == other_action.transformation))
    end
    return result
  end
  
  def clone
    return Action.new(@rule_id, @transformation.clone)
  end
  
  def eql?(other_action)
    result = false
    if other_action.kind_of? Action
      result = ((@rule_id == other_action.rule_id) && (@transformation == other_action.transformation))
    end
    return result
  end
  
  def hash
    return [@rule_id, @transformation.hash].hash
  end
end

#Author:: Manuela Ruiz  (mailto:mruiz@lcc.uma.es)
#Class that represents a state-action pair for a reinforcement learning problem
class StateAction
  attr_accessor :state
  attr_accessor :action
  attr_accessor :alternatives

  def initialize(state, action)
    @state = state
    @action = action
    @alternatives = nil
  end

  def ==(other_state_action)
    result = false
    if other_state_action.kind_of? StateAction
      result = ((@state == other_state_action.state) && (@action == other_state_action.action))
    end
    return result
  end
  
  def eql?(other_state_action)
    result = false
    if other_state_action.kind_of? StateAction
      result = ((@state == other_state_action.state) && (@action == other_state_action.action))
    end
    return result
  end
  
  def hash
    return [@state.hash, @action.hash].hash
  end
end


#This method is used by "execute_with_general_policy"
def get_value(linear_coefs, features)
	size = linear_coefs.length
	result = 0
	i = 0
	while (i < size)
		result += (linear_coefs[i] * features[i])
		i+=1
	end
	return result
end

#Executes the specified number of rules following the given general policy
#This method has to be inside the class "Execution"
#def execute_with_general_policy(n_rules, linear_coefs, problem_module)
#	reset
#	final_state = false
#	continue = true
#	while (@execution_history.size < n_rules) && !final_state && continue #while the number of steps is less than the specified...
#		state = State.new(@current_shape)
#		final_state = problem_module.is_final_state?(state)
#		
#		if !final_state
#		
#			#Array of triples [rule, transformation, features]
#			alternatives = problem_module.get_actions(state)
#			
#			applied = false
#			while !applied && continue
#				#Obtain the action for which the value is maximum
#				selected_pos = nil
#				max_value = nil
#				max_features = nil
#				state_action = nil
#				alternatives_aux = alternatives.clone
#				while !alternatives_aux.empty?
#					i = rand(alternatives_aux.size)
#					a = alternatives_aux[i]
#					alternatives_aux.delete_at(i)
#					s_a = StateAction.new(state, Action.new(a[0], a[1]))
#					features = a[2]
#					
#					value = get_value(linear_coefs, features)
#					
#					if max_value
#						if value > max_value
#							max_value = value
#							state_action = s_a
#							max_features = features
#							selected_pos = i
#						end
#					else
#						selected_pos = i
#						max_value = value
#						state_action = s_a
#						max_features = features
#					end
#				end
#				
#				if state_action
#					applied = Shade.project.execution.apply_rule(state_action.action.rule_id, state_action.action.transformation)
#				end
#			
#				if !applied && !alternatives.empty?
#					alternatives.delete_at(selected_pos)
#				elsif !applied
#					continue = false
#				end
#			end
#
#		end
#	end
#end

#This method generates a scheme inside the specified directory
def montaner_script(directory)
	project = Shade.project
	execution = Shade.project.execution
	execution.reset
	

	
	#Read grammars and plot...
	walls_grammar_path = "#{directory}walls.gr2"
	if walls_grammar_path
		
		#PHASE 1. Load walls grammar
		execution.grammar.load(walls_grammar_path)
		
    
		
		#Load policy and problem
		walls_policy_path = "#{directory}walls-policy.pol"
		linear_coefs = Array.new
		i = 0
		side = 1.m
		File.open(walls_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = WallsCompacityProblem.new(side)
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end
		
		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(45, Shade.policy, Shade.problem_module)  
		
		#PHASE 2. We need only the external walls, not the internal ones
		corners = execution.current_shape.p["Layer0"].get_node(Label.new("White")).list
		external_corners = LinearLinkedList.new
		
  
		
		#Then, for every point, we count the number of neighbors
		corners.reset_iterator
		while (p = corners.get_next)
			number_of_neighbors = 0
			top_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y + side, 0))
			top_right_neighbor = OrderedPoint.new(Point.new(p.key.x + side, p.key.y + side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.key.x + side, p.key.y, 0))
			bottom_right_neighbor = OrderedPoint.new(Point.new(p.key.x + side, p.key.y - side, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.key.x, p.key.y - side, 0))
			bottom_left_neighbor = OrderedPoint.new(Point.new(p.key.x - side, p.key.y - side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.key.x - side, p.key.y, 0))
			top_left_neighbor = OrderedPoint.new(Point.new(p.key.x - side, p.key.y + side, 0))
			if corners.get_node top_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node top_right_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node right_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node bottom_right_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node bottom_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node bottom_left_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node left_neighbor
				number_of_neighbors += 1
			end
			if corners.get_node top_left_neighbor
				number_of_neighbors += 1
			end
			if number_of_neighbors < 8 #If it is an external white label, then we add it to the list of external corners
				external_corners.insert_node(p.clone)
			end
		end
		
 
		
		#Then, we order the corners counter clock wise
		sorted_external_corners = Array.new
		aux_external_corners = external_corners.clone
		p = external_corners.first.key
		while (p)
			top_neighbor = OrderedPoint.new(Point.new(p.x, p.y + side, 0))
			right_neighbor = OrderedPoint.new(Point.new(p.x + side, p.y, 0))
			bottom_neighbor = OrderedPoint.new(Point.new(p.x, p.y - side, 0))
			left_neighbor = OrderedPoint.new(Point.new(p.x - side, p.y, 0))
			  
#      puts"punto = #{top_neighbor.point}"
#      puts"lista = "
#      aux_external_corners.reset_iterator
#      while pun = aux_external_corners.get_next
#        puts"#{pun.key.point}"
#      end
      
			if aux_external_corners.get_node top_neighbor
				p = top_neighbor.clone
				sorted_external_corners.push top_neighbor.point
				aux_external_corners.delete_node top_neighbor
        
			elsif aux_external_corners.get_node right_neighbor
				p = right_neighbor.clone
				sorted_external_corners.push right_neighbor.point
				aux_external_corners.delete_node right_neighbor
        
			elsif aux_external_corners.get_node bottom_neighbor
				p = bottom_neighbor.clone
				sorted_external_corners.push bottom_neighbor.point
				aux_external_corners.delete_node bottom_neighbor
        
			elsif aux_external_corners.get_node left_neighbor
				p = left_neighbor.clone
				sorted_external_corners.push left_neighbor.point
				aux_external_corners.delete_node left_neighbor
        
			else
				p = nil
			end
		end
  
		#puts"sorted_external_corners #{sorted_external_corners}"
		
		walls_axiom = execution.current_shape.clone
		
		#Update the labels of the wall axiom (remove internal white labels)
		walls_axiom_corners = walls_axiom.p["Layer0"].get_node(Label.new("White")).list
		corners.reset_iterator
		while (p = corners.get_next)
			if !external_corners.get_node p.key
				#Then remove it from walls_axiom_corners
				removing = walls_axiom_corners.delete_node p.key
			end
		end
		walls_axiom.p["Layer0"].get_node(Label.new("White")).list = walls_axiom_corners
		
		#Update the segments of the wall axiom
		walls_axiom.s["Layer0"] = BalancedBinaryTree.new
		i = 0
		while i < (sorted_external_corners.size - 1)
			segment = Segment.new(OrderedPoint.new(sorted_external_corners[i]), OrderedPoint.new(sorted_external_corners[i+1]))
			segment_list = LinearLinkedList.new

			node = BalancedBinaryTreeNode.new(Constants::BALANCED, nil, nil, segment.line_descriptor, segment_list)
			
			inserted_node = walls_axiom.s["Layer0"].insert_node(node) #Insert the node corresponding to the line descriptor of the segment

			#We create an auxiliar list filled with the new segment to add, in order to make the union and obtain the maximal lines
			new_segment_list = LinearLinkedList.new
			segment_node = LinearLinkedListNode.new(segment.clone, nil, nil)
			new_segment_list.insert_node(segment_node)
			
			walls_axiom.op_rel(inserted_node.list,  new_segment_list, Constants::UNION, Constants::SEGMENTS)
			i += 1
		end


		
		#Add last segment
		segment = Segment.new(OrderedPoint.new(sorted_external_corners[sorted_external_corners.size-1]), OrderedPoint.new(sorted_external_corners[0]))
		segment_list = LinearLinkedList.new

		node = BalancedBinaryTreeNode.new(Constants::BALANCED, nil, nil, segment.line_descriptor, segment_list)
		
		inserted_node = walls_axiom.s["Layer0"].insert_node(node) #Insert the node corresponding to the line descriptor of the segment

		#We create an auxiliar list filled with the new segment to add, in order to make the union and obtain the maximal lines
		new_segment_list = LinearLinkedList.new
		segment_node = LinearLinkedListNode.new(segment.clone, nil, nil)
		new_segment_list.insert_node(segment_node)
		
		walls_axiom.op_rel(inserted_node.list,  new_segment_list, Constants::UNION, Constants::SEGMENTS)
			
		#Make face group with the contour
		group_contour_face = Sketchup.active_model.entities.add_group
		group_contour_face.entities.add_face sorted_external_corners

		#PHASE 3. Load distributor grammar
		distributor_grammar_path = "#{directory}distributor.gr2"
		execution.grammar.load(distributor_grammar_path)
		#Load the axiom
		execution.grammar.axiom = walls_axiom
		execution.reset
		#Sketchup.active_model.active_view.refresh
		execution.apply_rule_random()
		#Save the axiom
		distributor_axiom = execution.current_shape.clone
		
		#PHASE 4. Load seed kitchen grammar
		kitchen_grammar_path = "#{directory}seed-kitchen.gr2"
		execution.grammar.load(kitchen_grammar_path)
		#Load the axiom
		execution.grammar.axiom = distributor_axiom
		execution.reset


		
		#Load seed kitchen policy
		seed_kitchen_policy_path = "#{directory}seed-kitchen-policy.pol"
		linear_coefs = Array.new
		i = 0
		File.open(seed_kitchen_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = SeedKitchenProblem.new(group_contour_face, side)
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end
		
		


		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(1, Shade.policy, Shade.problem_module)  
		#Save the axiom
		seed_kitchen_axiom = execution.current_shape.clone
		
		#PHASE 5. Load kitchen grammar
		kitchen_grammar_path = "#{directory}kitchen.gr2"
		execution.grammar.load(kitchen_grammar_path)
		#Load the axiom
		execution.grammar.axiom = seed_kitchen_axiom
		execution.reset
		#Load kitchen policy
		kitchen_policy_path = "#{directory}kitchen-policy.pol"
		linear_coefs = Array.new
		i = 0
		File.open(kitchen_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = KitchenProblem.new(group_contour_face, side, 46)  
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end
		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(5, Shade.policy, Shade.problem_module)  
		#Save the axiom
		kitchen_axiom = execution.current_shape.clone


		
		#PHASE 6. Load seed bath grammar
		seed_bath_grammar_path = "#{directory}seed-bath.gr2"
		execution.grammar.load(seed_bath_grammar_path)
		#Load the axiom
		execution.grammar.axiom = kitchen_axiom
		execution.reset
		#Load seed kitchen policy
		seed_bath_policy_path = "#{directory}seed-bath-policy.pol"
		linear_coefs = Array.new
		i = 0
		File.open(seed_bath_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = SeedBathProblem.new(group_contour_face, side)
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end
		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(1, Shade.policy, Shade.problem_module)
		#Save the axiom
		seed_bath_axiom = execution.current_shape.clone


		
		#PHASE 7. Load bath grammar
		bath_grammar_path = "#{directory}bath.gr2"
		execution.grammar.load(bath_grammar_path)
		#Load the axiom
		execution.grammar.axiom = seed_bath_axiom
		execution.reset
		#Load bath policy
		bath_policy_path = "#{directory}bath-policy.pol"
		linear_coefs = Array.new
		i = 0
		File.open(bath_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = BathProblem.new(group_contour_face, side)
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end
		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(1, Shade.policy, Shade.problem_module)
		#Save the axiom
		bath_axiom = execution.current_shape.clone
		
		#PHASE 11a. Load kitchen furniture grammar
    kitchen_furniture_grammar_path = "#{directory}kitchen-furniture.gr2"
    execution.grammar.load(kitchen_furniture_grammar_path)
    #Load the axiom
    execution.grammar.axiom = bath_axiom
    execution.reset
    #Execute the steps for this grammar, using the policy
    execution.apply_rule(1)
    execution.apply_rule(2)
    #Save the axiom
    
    
        
    kitchen_furniture_axiom = execution.current_shape.clone
    #PHASE 10c. Load walls grammar (bath)
    bath_walls_grammar_path = "#{directory}bath-walls.gr2"
    execution.grammar.load(bath_walls_grammar_path)
    #Load the axiom
    execution.grammar.axiom = kitchen_furniture_axiom
    execution.reset
    execution.execute_until_end
#    execution.apply_rule(1)
#    execution.apply_rule(2)
#    execution.apply_rule(3)
#    execution.apply_rule(4)
    
    
    walls_bath_axiom = execution.current_shape.clone
    #PHASE 11b. Load bath furniture grammar
    bath_furniture_grammar_path = "#{directory}bath-furniture.gr2"
    execution.grammar.load(bath_furniture_grammar_path)
    #Load the axiom
    execution.grammar.axiom = walls_bath_axiom
    execution.reset
    #Execute the steps for this grammar, using the policy
    execution.apply_rule(2)
    execution.apply_rule(1)
    #Save the axiom
    bath_furniture_axiom = execution.current_shape.clone
    
    #PHASE 12. Load erase bath walls grammar
    erase_bath_walls_grammar_path = "#{directory}erase-bath-walls.gr2"
    execution.grammar.load(erase_bath_walls_grammar_path)
    #Load the axiom
    execution.grammar.axiom = bath_furniture_axiom
    execution.reset
    #Execute the steps for this grammar, using the policy
    execution.execute_until_end
		
    
    bath_walls_erased_axiom = execution.current_shape.clone


		
		#PHASE 8. Load non-especialized grammar
		non_especialized_grammar_path = "#{directory}non-especialized.gr2"
		execution.grammar.load(non_especialized_grammar_path)
		#Load the axiom
		execution.grammar.axiom = bath_walls_erased_axiom
		execution.reset
		#Load non-especialized policy
		non_especialized_policy_path = "#{directory}non-especialized-policy.pol"
		linear_coefs = Array.new
		i = 0
		File.open(non_especialized_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = NonEspecializedSpacesProblem.new(side)
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end

		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(2, Shade.policy, Shade.problem_module)
		
		
		#Save the axiom
		non_especialized_axiom = execution.current_shape.clone

		
				
		#PHASE 9. Load entrance grammar
		#puts("Adding entrance")
		entrance_grammar_path = "#{directory}entrance.gr2"
		execution.grammar.load(entrance_grammar_path)
		#Load the axiom
		execution.grammar.axiom = non_especialized_axiom
		execution.reset
		#Load non-especialized policy
		entrance_policy_path = "#{directory}entrance-policy.pol"
		linear_coefs = Array.new
		i = 0
		File.open(entrance_policy_path, 'r') do |f|
			problem_module_name = f.gets.strip
			problem_module = EntranceProblem.new(side)
			while line = f.gets
				linear_coefs[i] = line.to_f
				i += 1
			end
			Shade.problem_module = problem_module
			Shade.policy = linear_coefs
		end

		#Execute the steps for this grammar, using the policy
		execution.execute_with_general_policy(1, Shade.policy, Shade.problem_module)
		
		#Save the axiom
		entrance_axiom = execution.current_shape.clone	
		
		

		
    
		
    
    #PHASE 13. Load flat door grammar
    flat_door_grammar_path = "#{directory}flat-door.gr2"
    execution.grammar.load(flat_door_grammar_path)
    #Load the axiom
    execution.grammar.axiom = entrance_axiom
    execution.reset
    #Execute the steps for this grammar, using the policy
    execution.execute_until_end
    
    
    
    
    
#    #Execute the steps for this grammar, using the policy
#    execution.execute_until_end

#    #Save the axiom
#    #axiom_10c = execution.current_shape.clone
    
    
    
#    current_axiom = execution.current_shape.clone
#    #PHASE 10a. Load walls grammar (room)
#    room_walls_grammar_path = "#{directory}room-walls.gr2"
#    execution.grammar.load(room_walls_grammar_path)
#    #Load the axiom
#    execution.grammar.axiom = current_axiom
#    execution.reset
#    #Execute the steps for this grammar, using the policy
#    execution.execute_until_end
#    #Save the axiom
#    #axiom_10a = execution.current_shape.clone
    
    
		
    current_axiom = execution.current_shape.clone
		#PHASE 10a. Load walls grammar (room)
		room_walls_grammar_path = "#{directory}room-walls.gr2"
		execution.grammar.load(room_walls_grammar_path)
		#Load the axiom
		execution.grammar.axiom = current_axiom
		execution.reset
    Shade.project.execution.add_constraint(NoScalesConstraint.new)
    Shade.project.refresh(true)
		#Execute the steps for this grammar, using the policy
		execution.execute_until_end
		#Save the axiom
		axiom_10a = execution.current_shape.clone
		
		Shade.project.execution.delete_constraint(Constants::NO_SCALES_CONSTRAINT_NAME)
		
#		#PHASE 10b. Load walls grammar (kitchen)
#		kitchen_walls_grammar_path = "#{directory}kitchen-walls.gr2"
#		execution.grammar.load(kitchen_walls_grammar_path)
#		#Load the axiom
#		execution.grammar.axiom = axiom_10a
#		execution.reset
#		#Execute the steps for this grammar, using the policy
#		execution.execute_until_end
#		#Save the axiom
#		axiom_10b = execution.current_shape.clone
		
		
		if false
		#PHASE 13. Erase all labels except grays/reds, rosybrowns and browns
		execution.current_shape.p["Layer0"].delete_node(Label.new("Black"))
		execution.current_shape.p["Layer0"].delete_node(Label.new("White"))
		execution.current_shape.p["Layer0"].delete_node(Label.new("Blue"))
		execution.current_shape.p["Layer0"].delete_node(Label.new("Yellow"))
		execution.current_shape.p["Layer0"].delete_node(Label.new("Green"))
				
      end
      
    group_contour_face.erase!  
    
      
    #Delete rules
    size = execution.grammar.rules.size
    i = 0
    while i < size
      execution.grammar.remove_rule(size-i-1)
      i += 1
    end

    

    Sketchup.active_model.close_active    
    execution.show_labels = true
    execution.hide_black = true

    
    Shade.project.refresh(true)
			
		
	end
end




#This method calls "montaner script" in order to generate several schemes
def m(number_of_plans, path_to_save_to, montaner_path)
	i = 0

	while i < number_of_plans
		
    path_to_save_to_txt = "#{path_to_save_to}plan#{i}.txt"
    Shade.design_current_path=(path_to_save_to_txt)
    
		t0 = Time.now
		montaner_script(montaner_path)
		t1 = Time.now
		
		Shade.project.execution.current_shape.save(path_to_save_to_txt)
		
		File.open("#{path_to_save_to}time#{i}.txt", 'w') do |f|
			f.write "#{t1 - t0}"
		end
		
		i+= 1
	end

UI.messagebox("Hecho")
end

