/*
This file is part of Fantom.
Fantom 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.
Fantom 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 Fantom. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.matfyz.aai.fantom.clients;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import cz.matfyz.aai.fantom.client.Agent;
import cz.matfyz.aai.fantom.client.ClientRunner;
import cz.matfyz.aai.fantom.game.Actor;
import cz.matfyz.aai.fantom.game.Graph;
import cz.matfyz.aai.fantom.game.Graph.Node;
import cz.matfyz.aai.fantom.message.ClientType;
import cz.matfyz.aai.fantom.message.MessageMoveBase.ActorMove;
public class RandomAgent implements Agent {
public static final String CLIENT_NAME = "RandomAgent";
private Random random = new Random(0);
private ClientType clientType;
private Graph game;
private boolean lessRandom;
enum Mode {
RANDOM,
CAREFULL, // If this is a phantom, do not go next to detectives. If this is a detective, move next to a phantom.
OPPORTUNIST // If this a detective and there is a phantom around, catch it. If this is a phantom, do not commit a suicide.
}
@Override
public void end(ClientType winner) {
if(winner == clientType)
System.err.println("I've won!!");
else
System.err.println("I've lost :(");
}
@Override
public ClientType getClientType() {
return clientType;
}
public ClientType getOpponentType() {
return getClientType().equals(ClientType.PHANTOM) ? ClientType.DETECTIVE : ClientType.PHANTOM;
}
@Override
public String getName() {
return CLIENT_NAME + " - " + clientType.toString();
}
@Override
public void initialize() {
}
@Override
public ActorMove[] move() {
System.err.println("It is my turn now.");
List<Actor> actors = game.getActors(getClientType());
List<Actor> opponents = game.getActors(getOpponentType());
Set<Node> usedNodes = new HashSet<Node>(); // used by actors of this client
Set<Node> dirtyNodes = new HashSet<Node>(); // reachable in one step by one of the opponent actors
Set<Node> opponentsNodes = new HashSet<Node>(); // occupied by one of the opponent actors
for(Actor actor : actors) {
if(actor.getCurrentPosition() != null)
usedNodes.add(actor.getCurrentPosition());
}
for(Actor opponent : opponents) {
if(opponent.getCurrentPosition() != null) {
opponentsNodes.add(opponent.getCurrentPosition());
}
for(ActorMove m : opponent.getLegalMoves(game)) {
dirtyNodes.add(m.getTargetNode());
}
}
Mode[] consideredModes = (this.lessRandom ? new Mode[] {Mode.OPPORTUNIST, Mode.CAREFULL, Mode.RANDOM} : new Mode[] {Mode.OPPORTUNIST, Mode.RANDOM});
if(this.lessRandom) {
if(getClientType().equals(ClientType.DETECTIVE)) {
// 1. Catch him, if you can.
// 2. Block him / go after him.
// 3. Move randomly.
consideredModes = new Mode[] {Mode.OPPORTUNIST, Mode.CAREFULL, Mode.RANDOM};
} else {
// 1. Keep safe.
// 2. Do not commit a suicide.
// 3. Move randomly.
consideredModes = new Mode[] {Mode.CAREFULL, Mode.OPPORTUNIST, Mode.RANDOM};
}
} else {
consideredModes = new Mode[] {Mode.OPPORTUNIST, Mode.RANDOM};
}
List<ActorMove> moves = new ArrayList<ActorMove>();
for(Actor actor : actors) {
String nodeId = actor.getCurrentPosition() == null ? "null" : actor.getCurrentPosition().getId();
System.err.printf("Actor %s is at node %s, looking for a new position\n", actor.getId(), nodeId);
List<ActorMove> available = actor.getLegalMoves(game);
List<ActorMove> consideredMoves = new ArrayList<ActorMove>(available.size());
for(Mode mode : consideredModes) {
for(ActorMove m : available) {
Node moveTarget = m.getTargetNode();
if(usedNodes.contains(moveTarget) && !moveTarget.equals(actor.getCurrentPosition()))
{
continue; //cannot go there
}
System.err.println("Available move to: " + moveTarget.getId());
if(m.getTransportType() != null) {
System.err.println(" by: " + m.getTransportType().getName());
}
switch(mode) {
case RANDOM:
consideredMoves.add(m);
break;
case CAREFULL:
if( (getClientType().equals(ClientType.DETECTIVE) && dirtyNodes.contains(moveTarget))
||
(getClientType().equals(ClientType.PHANTOM) && !dirtyNodes.contains(moveTarget) && !opponentsNodes.contains(moveTarget)) ) {
consideredMoves.add(m);
}
break;
case OPPORTUNIST:
if( (getClientType().equals(ClientType.DETECTIVE) && opponentsNodes.contains(moveTarget))
||
(getClientType().equals(ClientType.PHANTOM) && !opponentsNodes.contains(moveTarget))) {
consideredMoves.add(m);
}
break;
}
}
if(!consideredMoves.isEmpty()) {
break;
}
}
if(consideredMoves.size() == 0) {
System.err.printf("Actor %s is not going anywhere\n", actor.getId());
continue;
}
ActorMove move = consideredMoves.get(random.nextInt(consideredMoves.size()));
moves.add(move);
if(actor.getCurrentPosition() != null) {
usedNodes.remove(actor.getCurrentPosition());
}
usedNodes.add(move.getTargetNode());
System.err.printf("Actor %s is going to node %s\n", actor.getId(), move.getTargetNode().getId());
}
System.err.println("My turn is over.");
return moves.toArray(new ActorMove[moves.size()]);
}
public ActorMove[] place() {
return move();
}
@Override
public void quit() {
}
@Override
public void start(Graph graph) {
this.game = graph;
System.err.println("Starting a new game");
}
@Override
public void update(ActorMove[] moves) {
/*Properties[] state = game.serialize();
for(Properties record : state) {
String ln = Parser.encodeProperties(record);
System.err.println(ln);
}
System.err.println();*/
}
public RandomAgent(ClientType type) {
this(type, false);
}
public RandomAgent(ClientType type, boolean lessRandom) {
this.clientType = type;
this.lessRandom = lessRandom;
}
public static void main(String[] args) throws Exception {
ClientType type = ClientType.valueOf(args[0]);
boolean lessRandom = args.length > 1 && (args[1].equals("-l") || args[1].equals("--less"));
RandomAgent agent = new RandomAgent(type, lessRandom);
ClientRunner runner = new ClientRunner(agent);
runner.run();
}
}