/*
* This file is part of MazeSolver.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (c) 2014 MazeSolver
* Sergio M. Afonso Fumero <theSkatrak@gmail.com>
* Kevin I. Robayna Hernández <kevinirobaynahdez@gmail.com>
*/
/**
* @file RulePredicate.java
* @date 31/10/2014
*/
package es.ull.mazesolver.agent.rules;
import es.ull.mazesolver.agent.SARulesAgent;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.AndContext;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.DirectionContext;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.OrContext;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.ParensContext;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.SingleTermContext;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.SituationContext;
import es.ull.mazesolver.agent.rules.parser.SituationActionParser.TermContext;
import es.ull.mazesolver.maze.MazeCell;
import es.ull.mazesolver.util.Direction;
/**
* Representa una situación o predicado dentro de una regla de situación-acción.
*/
public abstract class RulePredicate implements Cloneable {
protected boolean m_negated = false;
/**
* Distintos conectores de reglas que soporta el lenguaje.
*/
private static enum RuleConnector {
OR, AND;
}
/**
* Construye un predicado a partir de una "situación" del árbol de parseo.
*
* @param ctx
* Nodo del árbol de parseo con un predicado o situación que se
* quiere procesar.
* @return Predicado creado a partir del árbol.
*/
public static RulePredicate createFromTree (SituationContext ctx) {
// Lo que hay... (v_v)
if (ctx instanceof OrContext)
return createFromTree((OrContext) ctx);
if (ctx instanceof AndContext)
return createFromTree((AndContext) ctx);
if (ctx instanceof ParensContext)
return createFromTree((ParensContext) ctx);
if (ctx instanceof SingleTermContext)
return createFromTree((SingleTermContext) ctx);
return null;
}
private static RulePredicate createFromTree (OrContext ctx) {
return new ComplexRulePredicate(createFromTree(ctx.situation(0)),
createFromTree(ctx.situation(1)), RuleConnector.OR);
}
private static RulePredicate createFromTree (AndContext ctx) {
return new ComplexRulePredicate(createFromTree(ctx.situation(0)),
createFromTree(ctx.situation(1)), RuleConnector.AND);
}
private static RulePredicate createFromTree (ParensContext ctx) {
RulePredicate pred = createFromTree(ctx.situation());
if (ctx.NOT() != null)
pred.negate();
return pred;
}
private static RulePredicate createFromTree (SingleTermContext ctx) {
return SimpleRulePredicate.createFromTree(ctx.term());
}
/**
* Invierte el resultado de la regla.
*/
public void negate () {
m_negated = !m_negated;
}
/**
* Evalúa la regla para el agente indicado e indica si se cumple o no.
*
* @param ag
* Agente sobre el que se quiere evaluar el predicado.
* @return Si la situación representada se da para el agente indicado.
*/
public abstract boolean evaluate (SARulesAgent ag);
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public abstract Object clone ();
/**
* Subclase que gestiona una regla sin conectores. Es decir, un término de la
* gramática: "term".
*/
private static class SimpleRulePredicate extends RulePredicate {
private Direction m_direction;
private MazeCell.Vision m_vision;
private boolean m_visited_status;
/**
* Construye un término a partir del árbol de parseo generado.
*
* @param term_ctx
* Contexto que hace referencia al término que se quiere convertir
* a regla simple.
* @return Regla simple que representa el término.
*/
public static SimpleRulePredicate createFromTree (TermContext term_ctx) {
DirectionContext ctx = term_ctx.direction();
// Extraemos la dirección
Direction dir;
if (ctx.UP() != null)
dir = Direction.UP;
else if (ctx.DOWN() != null)
dir = Direction.DOWN;
else if (ctx.LEFT() != null)
dir = Direction.LEFT;
else
// RIGHT
dir = Direction.RIGHT;
// Extraemos el estado de la celda
MazeCell.Vision vision = null;
if (term_ctx.FREE() != null)
vision = MazeCell.Vision.EMPTY;
else if (term_ctx.WALL() != null)
vision = MazeCell.Vision.WALL;
else if (term_ctx.AGENT() != null)
vision = MazeCell.Vision.AGENT;
else if (term_ctx.OFFLIMITS() != null)
vision = MazeCell.Vision.OFFLIMITS;
// Creamos la regla y la negamos si es su caso
SimpleRulePredicate pred;
if (vision == null)
pred = new SimpleRulePredicate(dir);
else
pred = new SimpleRulePredicate(dir, vision);
if (term_ctx.NOT() != null)
pred.negate();
return pred;
}
/**
* Crea un predicado que hace referencia a que en la dirección indicada se
* tiene una visión específica.
*
* @param dir
* Dirección a la que hace referencia el término.
* @param st
* Estado de la celda.
*/
public SimpleRulePredicate (Direction dir, MazeCell.Vision vision) {
m_direction = dir;
m_vision = vision;
}
/**
* Crea un predicado que hace referencia a que la dirección indicada ha sido
* visitada.
*
* @param dir
* Dirección a la que hace referencia el término.
*/
public SimpleRulePredicate (Direction dir) {
m_direction = dir;
m_visited_status = true;
}
/*
* (non-Javadoc)
*
* @see agent.rules.RulePredicate#evaluate(agent.Agent)
*/
@Override
public boolean evaluate (SARulesAgent ag) {
boolean result = false;
if (m_visited_status)
result = ag.hasVisited(m_direction);
else {
MazeCell.Vision vision = ag.look(m_direction);
result = vision == m_vision;
}
return result ^ m_negated;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public Object clone () {
SimpleRulePredicate pred = new SimpleRulePredicate(m_direction, m_vision);
pred.m_negated = m_negated;
pred.m_visited_status = m_visited_status;
return pred;
}
}
/**
* Regla que gestiona la unión de 2 reglas usando los operadores definidos.
*/
private static class ComplexRulePredicate extends RulePredicate {
private RulePredicate m_p1, m_p2;
private RuleConnector m_connector;
/**
* Crea un nuevo predicado compuesto.
*
* @param p1
* Regla izquierda.
* @param p2
* Regla derecha.
* @param con
* Conector entre las reglas.
*/
public ComplexRulePredicate (RulePredicate p1, RulePredicate p2, RuleConnector con) {
m_p1 = p1;
m_p2 = p2;
m_connector = con;
}
/*
* (non-Javadoc)
*
* @see agent.rules.RulePredicate#evaluate(agent.Agent)
*/
@Override
public boolean evaluate (SARulesAgent ag) {
boolean result = false;
switch (m_connector) {
case OR:
result = m_p1.evaluate(ag) || m_p2.evaluate(ag);
break;
case AND:
result = m_p1.evaluate(ag) && m_p2.evaluate(ag);
break;
}
return result ^ m_negated;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public Object clone () {
ComplexRulePredicate pred =
new ComplexRulePredicate((RulePredicate) m_p1.clone(), (RulePredicate) m_p2.clone(),
m_connector);
pred.m_negated = m_negated;
return pred;
}
}
}