net.windward.Windwardopolis2.Framework.java Source code

Java tutorial

Introduction

Here is the source code for net.windward.Windwardopolis2.Framework.java

Source

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE"
 * As long as you retain this notice you can do whatever you want with this
 * stuff. If you meet an employee from Windward some day, and you think this
 * stuff is worth it, you can buy them a beer in return. Windward Studios
 * ----------------------------------------------------------------------------
 */

package net.windward.Windwardopolis2;

import net.windward.Windwardopolis2.AI.MyPlayerBrain;
import net.windward.Windwardopolis2.AI.PlayerAIBase;
import net.windward.Windwardopolis2.api.*;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.awt.*;
import java.util.Iterator;

import org.apache.log4j.*;

public class Framework implements IPlayerCallback {
    private TcpClient tcpClient;
    private MyPlayerBrain brain;
    //    private String ipAddress = "127.0.0.1";
    //    private String ipAddress = "k9-14.cs.purdue.edu";
    private String ipAddress = "127.0.0.1";

    private String myGuid;

    // we play a card and remove it from our hand. But at the same time the server is sending us a status with our
    // hand as it sees it. So we ignore updates to our hand if it's been less than a second and we're not seeing the
    // card we played in the incoming status.
    private PowerUp cardLastPlayed;
    private long cardLastSendTime = System.currentTimeMillis() - 2000;

    // this is used to make sure we don't have multiple threads updating the Player/Passenger lists, sending
    // back multiple orders, etc. This is a lousy way to handle this - but it keeps the example simple and
    // leaves room for easy improvement.
    private int signal;

    private static Logger log = Logger.getLogger(IPlayerCallback.class);

    /**
     * Run the A.I. player. All parameters are optional.
     *
     * @param args I.P. address of server, name
     */
    public static void main(String[] args) throws IOException {
        log.debug("***** Windwardopolis II starting *****");

        Framework framework = new Framework(Arrays.asList(args));
        framework.Run();
    }

    private Framework(java.util.List<String> args) {
        brain = new MyPlayerBrain(args.size() >= 2 ? args.get(1) : null);
        if (args.size() >= 1) {
            ipAddress = args.get(0);
        }
        String msg = String.format("Connecting to server %1$s for user: %2$s", ipAddress, brain.getName());

        System.out.println(msg);
    }

    private void Run() throws IOException {
        System.out.println("starting...");

        tcpClient = new TcpClient(this, ipAddress);
        tcpClient.Start();
        ConnectToServer();

        // It's all messages to us now.
        System.out.println("enter \"exit\" to exit program");
        while (true) {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                String line = in.readLine();
                if (line.equals("exit")) {
                    System.out.println("Exiting program...");
                    tcpClient.abort();
                    break;
                }
            } catch (Exception e) {
                System.out.println("ERROR restarting app (Exception: " + e.getMessage() + " )");
                log.error("restarting run(), Exception: " + e.getMessage());
            }

        }
    }

    public final void StatusMessage(String message) {
        System.out.println(message);
    }

    public final void IncomingMessage(String message) throws DocumentException {
        try {
            long startTime = System.currentTimeMillis();
            // get the xml - we assume we always get a valid message from the server.
            SAXReader reader = new SAXReader();
            Document xml = reader.read(new StringReader(message));

            String rootName = xml.getRootElement().getName();

            if (rootName.equals("setup")) {
                System.out.println("Received setup message");
                if (log.isInfoEnabled())
                    log.info("Recieved setup message");

                java.util.ArrayList<Player> players = Player.FromXml(xml.getRootElement().element("players"));
                java.util.ArrayList<Company> companies = Company.FromXml(xml.getRootElement().element("companies"));
                java.util.ArrayList<CoffeeStore> stores = CoffeeStore
                        .FromXml(xml.getRootElement().element("stores"));
                java.util.ArrayList<Passenger> passengers = Passenger
                        .FromXml(xml.getRootElement().element("passengers"), companies);
                java.util.ArrayList<PowerUp> powerups = PowerUp.FromXml(xml.getRootElement().element("powerups"),
                        companies, passengers);

                Map map = new Map(xml.getRootElement().element("map"), companies);
                myGuid = xml.getRootElement().attribute("my-guid").getValue();

                Player me2 = null;
                for (Player plyr : players) {
                    if (myGuid.equals(plyr.getGuid()))
                        me2 = plyr;
                }

                brain.Setup(map, me2, players, companies, stores, passengers, powerups,
                        new PlayerAIBase.PlayerOrdersEvent() {
                            public void invoke(String order, ArrayList<Point> path, ArrayList<Passenger> pickUp) {
                                PlayerOrdersEvent(order, path, pickUp);
                            }
                        }, new PlayerAIBase.PlayerCardEvent() {
                            public void invoke(PlayerAIBase.CARD_ACTION action, PowerUp powerup) {
                                PlayerPowerSend(action, powerup);
                            }
                        });

            } else if (rootName.equals("powerup-status")) {
                // may be here because re-started and got this message before the re-send of setup.
                if (myGuid == null || myGuid.length() == 0)
                    return;

                synchronized (this) {
                    // bad news - we're throwing this message away.
                    if (signal > 0)
                        return;
                    signal++;
                }

                try {
                    // get what was played
                    PlayerAIBase.STATUS puStatus = PlayerAIBase.STATUS
                            .valueOf(xml.getRootElement().attribute("status").getValue());
                    String puGuid = xml.getRootElement().attribute("played-by") != null
                            ? xml.getRootElement().attribute("played-by").getValue()
                            : myGuid;

                    Player plyrPowerUp = null;
                    for (Player plyr : brain.getPlayers()) {
                        if (puGuid.equals(plyr.getGuid()))
                            plyrPowerUp = plyr;
                    }

                    PowerUp cardPlayed = PowerUp.GenerateFlyweight(xml.getRootElement().element("card"),
                            brain.getCompanies(), brain.getPassengers(), brain.getPlayers());

                    if (log.isInfoEnabled())
                        log.info(plyrPowerUp.getName() + " " + puStatus + " on " + cardPlayed);

                    // do we update the card deck?
                    if (cardPlayed.equals(cardLastPlayed)
                            || (System.currentTimeMillis() - cardLastSendTime) > 1000) {
                        // move any not in deck to hand
                        UpdateCards(xml.getRootElement().element("cards-deck").elements("card"),
                                brain.getPowerUpDeck(), brain.getPowerUpHand());
                        // delete any not in drawn
                        UpdateCards(xml.getRootElement().element("cards-hand").elements("card"),
                                brain.getPowerUpHand(), null);
                    }

                    // pass in to play cards.
                    brain.PowerupStatus(puStatus, plyrPowerUp, cardPlayed);
                } finally {
                    synchronized (this) {
                        signal--;
                    }
                }
            } else if (rootName.equals("status")) {
                // may be here because re-started and got this message before the re-send of setup.
                if (net.windward.Windwardopolis2.DotNetToJavaStringHelper.isNullOrEmpty(myGuid)) {
                    return;
                }

                synchronized (this) {
                    if (signal > 0) {
                        // bad news - we're throwing this message away.
                        TRAP.trap();
                        return;
                    }
                    signal++;
                }
                try {

                    PlayerAIBase.STATUS status = PlayerAIBase.STATUS
                            .valueOf(xml.getRootElement().attribute("status").getValue());
                    Attribute attr = xml.getRootElement().attribute("player-guid");
                    String guid = attr != null ? attr.getValue() : myGuid;

                    Player.UpdateFromXml(brain.getCompanies(), brain.getPlayers(), brain.getPassengers(),
                            xml.getRootElement().element("players"));
                    Passenger.UpdateFromXml(brain.getCompanies(), brain.getPlayers(), brain.getPassengers(),
                            xml.getRootElement().element("passengers"));

                    // update my path & pick-up.
                    Player plyrStatus = null;
                    for (Player plyr : brain.getPlayers()) {
                        if (guid.equals(plyr.getGuid()))
                            plyrStatus = plyr;
                    }
                    Element elem = xml.getRootElement().element("path");
                    if (elem != null) {
                        String[] path = elem.getText().split(";", 0);
                        plyrStatus.getLimo().getPath().clear();
                        for (String stepOn : path) {
                            int pos = stepOn.indexOf(',');
                            if (pos > 0)
                                plyrStatus.getLimo().getPath()
                                        .add(new Point(Integer.parseInt(stepOn.substring(0, pos)),
                                                Integer.parseInt(stepOn.substring(pos + 1))));
                        }
                    }

                    elem = xml.getRootElement().element("pick-up");
                    if (elem != null) {
                        String[] names = elem.getText().split(";", 0);
                        plyrStatus.getPickUp().clear();

                        ArrayList<Passenger> newPsngrList = new ArrayList<Passenger>();

                        for (String name : names) {
                            for (Passenger ps : brain.getPassengers()) {
                                if (ps.getName().equals(name)) {
                                    newPsngrList.add(ps);
                                }
                            }

                        }

                        for (Passenger psngrOn : newPsngrList) {
                            plyrStatus.getPickUp().add(psngrOn);
                        }
                    }

                    // pass in to generate new orders
                    brain.GameStatus(status, plyrStatus);
                } finally {
                    synchronized (this) {
                        signal--;
                    }
                }

            }

            else if (xml.getRootElement().getName().equals("exit")) {
                System.out.println("Received exit message");
                if (log.isInfoEnabled()) {
                    log.info("Received exit message");
                }
                System.exit(0);

            } else {
                TRAP.trap();
                String msg = String.format("ERROR: bad message (XML) from server - root node %1$s",
                        xml.getRootElement().getName());
                log.warn(msg);
                //Trace.WriteLine(msg);
            }

            long turnTime = System.currentTimeMillis() - startTime;
            if (turnTime > 800) {
                System.out.println("WARNING - turn took " + turnTime / 1000 + " seconds");

            }
        } catch (RuntimeException ex) {
            System.out.println(String.format("Error on incoming message. Exception: %1$s", ex));
            ex.printStackTrace();
            log.error("Error on incoming message.", ex);
        }
    }

    private void UpdateCards(java.util.List<Element> elements, java.util.List<PowerUp> cardList,
            java.util.List<PowerUp> hand) {

        ArrayList<PowerUp> deck = new ArrayList<PowerUp>();
        Iterator<Element> it = elements.iterator();

        while (it.hasNext()) {
            Element current = it.next();
            deck.add(PowerUp.GenerateFlyweight(current, brain.getCompanies(), brain.getPassengers(),
                    brain.getPlayers()));
        }

        for (int ind = 0; ind < cardList.size();) {
            PowerUp pu = cardList.get(ind);
            if (deck.contains(pu)) {
                int thisCardInd = deck.indexOf(pu);
                pu.setOkToPlay(deck.get(thisCardInd).isOkToPlay());
                deck.remove(pu);
                ind++;
                continue;
            }
            // moving from deck to hand
            if (hand != null)
                hand.add(pu);

            cardList.remove(ind);
        }

        // did some get added back to the deck/hand?
        ArrayList<PowerUp> toAdd = new ArrayList<PowerUp>();
        for (PowerUp p : deck) {
            toAdd.add(new PowerUp(p));
        }
        cardList.addAll(toAdd);
    }

    private void PlayerOrdersEvent(String order, java.util.ArrayList<Point> path,
            java.util.ArrayList<Passenger> pickUp) {
        try {

            // update our info
            if (path.size() > 0) {
                brain.getMe().getLimo().getPath().clear();
                brain.getMe().getLimo().getPath().addAll(path);
            }
            if (pickUp.size() > 0) {
                brain.getMe().getPickUp().clear();
                brain.getMe().getPickUp().addAll(pickUp);
            }
            Document xml = DocumentHelper.createDocument();
            Element elem = DocumentHelper.createElement(order);
            xml.add(elem);
            if (path.size() > 0) {
                StringBuilder buf = new StringBuilder();
                for (Point ptOn : path) {
                    buf.append(String.valueOf(ptOn.x) + ',' + String.valueOf(ptOn.y) + ';');
                }
                Element newElem = DocumentHelper.createElement("path");
                newElem.setText(buf.toString());
                elem.add(newElem);
            }
            if (pickUp.size() > 0) {
                StringBuilder buf = new StringBuilder();
                for (Passenger psngrOn : pickUp) {
                    buf.append(psngrOn.getName() + ';');
                }
                Element newElem = DocumentHelper.createElement("pick-up");
                newElem.setText(buf.toString());
                elem.add(newElem);
            }
            try {
                String toSend = xml.asXML();
                tcpClient.SendMessage(toSend);
            } catch (IOException e) {
                System.out.println("bad sent orders event");
                e.printStackTrace();
            }
        } catch (Exception e) {
            log.error("PlayerOrderEvent( " + order + ", ...) threw Exception: " + e.getMessage());
        }
    }

    private void PlayerPowerSend(PlayerAIBase.CARD_ACTION action, PowerUp powerup) {

        if (log.isInfoEnabled())
            log.info("Request " + action + " " + powerup);

        cardLastPlayed = powerup;
        cardLastSendTime = System.currentTimeMillis();

        Document xml = DocumentHelper.createDocument();
        Element elem = DocumentHelper.createElement("order");
        elem.add(DocumentHelper.createAttribute(elem, "action", action.name()));
        Element elemCard = DocumentHelper.createElement("powerup");
        elemCard.add(DocumentHelper.createAttribute(elemCard, "card", powerup.getCard().name()));

        if (powerup.getCompany() != null)
            elemCard.add(DocumentHelper.createAttribute(elemCard, "company", powerup.getCompany().getName()));
        if (powerup.getPassenger() != null)
            elemCard.add(DocumentHelper.createAttribute(elemCard, "passenger", powerup.getPassenger().getName()));
        if (powerup.getPlayer() != null)
            elemCard.add(DocumentHelper.createAttribute(elemCard, "player", powerup.getPlayer().getName()));

        elem.add(elemCard);
        xml.add(elem);
        try {
            String toSend = xml.asXML();
            tcpClient.SendMessage(toSend);
        } catch (IOException e) {
            System.out.println("bad sent orders event");
            e.printStackTrace();
        }
    }

    public final void ConnectionLost(Exception ex) throws IOException, InterruptedException {

        System.out.println("Lost our connection! Exception: " + ex.getMessage());

        int delay = 500;
        while (true) {
            try {
                if (tcpClient != null) {
                    tcpClient.Close();
                }
                tcpClient = new TcpClient(this, ipAddress);
                tcpClient.Start();

                ConnectToServer();
                System.out.println("Re-connected");

                return;
            } catch (RuntimeException e) {

                System.out.println("Re-connection fails! Exception: " + e.getMessage());
                Thread.sleep(delay);
                delay += 500;
            }
        }
    }

    private void ConnectToServer() throws IOException {
        try {
            Document doc = DocumentHelper.createDocument();
            Element root = DocumentHelper.createElement("join");
            root.addAttribute("name", brain.getName());
            root.addAttribute("school", MyPlayerBrain.SCHOOL);
            root.addAttribute("language", "Java");

            byte[] data = brain.getAvatar();
            if (data != null) {
                Element avatarElement = DocumentHelper.createElement("avatar");
                BASE64Encoder encoder = new BASE64Encoder();
                avatarElement.setText(encoder.encode(data));
                root.add(avatarElement);
            }

            doc.add(root);

            tcpClient.SendMessage(doc.asXML());
        } catch (Exception e) {
            log.warn("ConnectToServer() threw Exception: " + e.getMessage());
        }
    }
}