Package entities.Map

Source Code of entities.Map.FieldMap

/**
* The map for battleship.
*
* User: Pascal
* Version: 1.3.1
* Date: 13.05.13
*
* Changes:
* 0.1 (07.03.13)
*  - First implementation.
*  - Implement initialization of local variables.
* 1.0 (15.04.13)
*  - Implement ship setting
*  - Implement random ship setting
* 1.1 (16.04.13)
*  - Implement BombField() function.
* 1.2 (17.04.13)
*  - Refactor methods.
*  - Add helper functions for console output and the ai.
* 1.3 (18.04.13)
*  - Implement removing of ships. 'UnSetShip()'
* 1.3.1 (13.05.2013)
*  - BugFix map size. If I initialize the size at the beginning of a class at the declaration
*    I became problems with the setting, because every time I want to get the size I get only
*    the default size (10x10).
*/
package entities.Map;

import entities.EntityBase;
import entities.ship.Ship;
import entities.ship.ShipState;
import entities.ship.ShipType;
import game.Options;
import other.Const;
import other.Randomizer;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
* The map for battleship.
*
* @author Pascal
* @version 1.3.1
*/
public class FieldMap extends EntityBase
{
    public List<List<Field>> map;
    public List<Ship> ships;
    public Point MapSize;
    String bombState = "";
    boolean hasHit = false;
    Integer moves;
    Point hitPoint;
    Ship lastSunkenShip;

    /**
     * Initializes the map data.
     */
    @Override
    public void Initialize()
    {
        Options.ReadOptionsToProperties();
        MapSize = Options.MapSize;
        MapSize.setLocation(MapSize.x + 2, MapSize.y + 2);

        moves = 0;
        // Initialize the map
        map = new ArrayList<List<Field>>();
        for (int i = 0; i < MapSize.x; i++)
        {
            map.add(new ArrayList<Field>());
            for (int j = 0; j < MapSize.y; j++)
            {
                map.get(i).add(new Field());
            }
        }

        /**
         * I use 12 fields each row, because the borders have FieldState.Coast
         * and on this fields you can place nothing, so in the game it's like
         * you're playing on a 10x10 map.
         */
        for (int i = 0; i < map.size(); i++)
        {
            for (int j = 0; j < map.size(); j++)
            {
                if (i == 0 || i == map.size()-1)
                { map.get(i).get(j).State = FieldState.Coast; }
                else if (j == 0 || j == map.size()-1)
                { map.get(i).get(j).State = FieldState.Coast; }
                else
                {
                    // Initialize set the state automatically to FieldState.Nothing.
                    map.get(i).get(j).Initialize();
                }
            }
        }

        ships = new ArrayList<Ship>();
        // Initialize ships without position.
        ships.add(new Ship(ShipType.Battleship, 5));
        ships.add(new Ship(ShipType.Cruiser, 4));
        ships.add(new Ship(ShipType.Cruiser, 4));
        ships.add(new Ship(ShipType.Destroyer, 3));
        ships.add(new Ship(ShipType.Destroyer, 3));
        ships.add(new Ship(ShipType.Destroyer, 3));
        ships.add(new Ship(ShipType.Submarine, 2));
        ships.add(new Ship(ShipType.Submarine, 2));
        ships.add(new Ship(ShipType.Submarine, 2));

        if (Randomizer.nextInt(10) == 8)
            ships.add(new Ship(ShipType.YellowSubmarine, 2));
        else
            ships.add(new Ship(ShipType.Submarine, 2));

        if (Const.DEBUG)
        {
            for (Ship ship : ships)
                System.out.printf(ship.Type.toString() + " - " + ship.Length + " - " + ship.Position + "\n");
        }
    }

    /**
     * Update the entity object.
     */
    @Override
    public void Update()
    {

    }

    /**
     * Translate the map into a list of characters which can be printed
     * out on the console
     *
     * @return Returns a list of characters with the map data.
     */
    public List<List<Character>> MapAsCharList(boolean hide)
    {
        List<List<Character>> ret = new ArrayList<List<Character>>();
        // Get the basic chars from the map
        for (int i = 0; i < map.size(); i++)
        {
            ret.add(new ArrayList<Character>());
            for (int t = 0; t < map.get(i).size(); t++)
            {
                ret.get(i).add(map.get(i).get(t).FieldAsChar(hide));
            }
        }

        // Overlay the map chars with the ships.
        for (Ship ship : ships)
        {
            for (int i = 0; i < ship.Length; i++)
            {
                if (ship.Vertical)
                    ret.get(ship.Position.x+i).set(ship.Position.y, ship.Parts.get(i).StateAsChar(hide));
                else
                    ret.get(ship.Position.x).set(ship.Position.y+i, ship.Parts.get(i).StateAsChar(hide));
            }
        }

        return ret;
    }

    /**
     * Set the ships randomly over the map.
     */
    public void SetShipsRandomly()
    {
        Integer row, column, vertical;
        int state = 0;
        int stateCount = 0;

        for (Ship ship : ships)
        {
            boolean set = false;
            while (!set)
            {
                row = Randomizer.nextInt(map.size()-1);
                column = Randomizer.nextInt(map.size()-1);
                vertical = Randomizer.nextInt(1);
                boolean isVertical;
                isVertical = vertical != 0;

                set = SetShip(ship, row, column, isVertical);

                // Output if the calculating of positions need more time.
                state++;
                if (state > 5000)
                {
                    state = 0;
                    stateCount++;
                    System.out.println("Calculate ship positions.");
                }

                // If the program cannot set a ship, reset all and begin from new.
                if (stateCount > 2)
                {
                    System.out.printf("I'm sorry but I can't calculate all the ship positions. :(\n");
                    System.out.printf("But I try it again. :)");

                    for (Ship removingShip : ships)
                        UnsetShip(removingShip);

                    SetShipsRandomly();
                }
            }
        }
    }

    /**
     * Set a ship at the given position.
     * @param ship The ship that had to be set.
     * @param row The row place.
     * @param column The column place.
     * @param vertical Set ship vertical or horizontal.
     * @return It's true if the ship can set, otherwise it's false.
     */
    boolean SetShip(Ship ship, int row, int column, boolean vertical)
    {
        boolean canSet = true;
        int tmpRow = row;
        int tmpColumn = column;

        if ((row + ship.Length >= map.size()) ||
                (column + ship.Length >= map.size()))
        {
            return false;
        }

        for (int i = 0; i < ship.Length; i++)
        {
            if (vertical)
                tmpRow = row + i;
            else
                tmpColumn = column + i;

            // Check the places around a ship part, so it do not connect to another ship
            if (checkState(map.get(tmpRow).get(tmpColumn).State) ||
                    (tmpRow == 0 || checkState(map.get(tmpRow-1).get(tmpColumn).State)) ||
                    checkState(map.get(tmpRow+1).get(tmpColumn).State) ||
                    (tmpColumn == 0 || checkState(map.get(tmpRow).get(tmpColumn-1).State)) ||
                    checkState(map.get(tmpRow).get(tmpColumn+1).State))
            {
                canSet = false;
            }
        }

        if (canSet)
        {
            ship.Position = new Point(row, column);
            ship.Vertical = vertical;

            tmpRow = row;
            tmpColumn = column;
            for (int i = 0; i < ship.Length; i++)
            {
                if (vertical)
                    tmpRow = row + i;
                else
                    tmpColumn = column + i;

                map.get(tmpRow).get(tmpColumn).State = FieldState.Occupied;
            }
        }

        return canSet;
    }

    /**
     * Unset a ship
     * @param ship The ship which hat to be unset.
     */
    private void UnsetShip(Ship ship)
    {
        int tmpRow = ship.Position.x;
        int tmpColumn = ship.Position.y;
        for (int i = 0; i < ship.Length; i++)
        {
            if (ship.Vertical)
                tmpRow = ship.Position.x + i;
            else
                tmpColumn = ship.Position.y + i;

            if (tmpRow > -1 && tmpColumn > -1)
                map.get(tmpRow).get(tmpColumn).State = FieldState.Occupied;
        }

        ship.Position = new Point(-1, -1);
        ship.Vertical = false;
    }

    private boolean checkState(FieldState state)
    {
        return !(state == FieldState.Nothing || state == FieldState.Coast);
    }

    /**
     * Bombs a specific Field.
     * @param point The coordinates of the missile.
     * @return Returns a string which describes your success or failure.
     */
    public boolean BombField(Point point)
    {
        return BombField(point.x, point.y);
    }

    /**
     * Bombs a specific Field.
     * @param x The x coordinate of the missile.
     * @param y The y coordinate of the missile.
     * @return Returns a string which describes your success or failure.
     */
    public boolean BombField(int x, int y)
    {
        lastSunkenShip = null;
        hitPoint = new Point(x, y);
        hasHit = false;
        if (Const.DEBUG)
        {
            System.out.printf(x + ";" + y + " - ");
            System.out.printf(map.get(x).get(y).State.toString() + "\n");
        }

        switch (map.get(x).get(y).State)
        {
            case Coast:
                bombState = "You cannot fire at the coast. I don't allow this.";
                return false;
            case Bombed:
                bombState = "This field is already bombed. You cannot do it twice";
                return false;
            case Occupied:
            {
                map.get(x).get(y).State = FieldState.Bombed;
                String shipType = "";
                boolean isSunk = false;

                searchShip:
                for (Ship ship : ships)
                {
                    int tmpX = ship.Position.x, tmpY = ship.Position.y;
                    for (int i = 0; i < ship.Length; i++)
                    {
                        if (tmpX == x && tmpY == y)
                        {
                            ship.Parts.get(i).State = ShipState.Damaged;
                            shipType = ship.Type.name();

                            isSunk = ship.IsSunk();
                            if (isSunk)
                            {
                                ship.Sink();
                                lastSunkenShip = ship;
                            }
                            else
                                ship.State = ShipState.Damaged;

                            break searchShip;
                        }

                        if (Const.DEBUG && ship.State != ShipState.Ok)
                            System.out.println(ship.State + ";" + ship.Type + ";" + isSunk);

                        if (ship.Vertical)
                            tmpX++;
                        else
                            tmpY++;
                    }
                }

                if (isSunk)
                {
                    // Little easter egg. :)
                    if (shipType.equalsIgnoreCase("yellowsubmarine"))
                        bombState = SinkYellowSubmarine();
                    else
                        bombState = "You hit a " + shipType + ". It sunks.";
                    hasHit = true;
                    moves++;
                    return true;
                }
                else
                {
                    bombState = "You hit something.";
                    hasHit = true;
                    moves++;
                    return true;
                }
            }
            default:
            {
                map.get(x).get(y).State = FieldState.Bombed;
                bombState = "There is nothing, search a better target.";
                moves++;
                return true;
            }
        }
    }

    /**
     * Get the state of the <code>BombField()</code> function.
     * @return Returns a string with the state of your missile (if there is nothing or else)
     */
    public String getBombState()
    {
        return bombState;
    }

    /**
     * Returns a boolean value whether a ship was hit or not.
     * @return true = hit a ship; false = miss target
     */
    public boolean getHasHit()
    {
        return hasHit;
    }

    /**
     * Get the las point who hitting a ship
     * @return Return a Point with the target coordinates.
     */
    public Point getHitPoint()
    {
        return hitPoint;
    }

    /**
     * Returns all moves in this map
     * @return Number of moves as integer
     */
    public Integer getMoves()
    {
        return moves;
    }

    /**
     * Returns the last sunken ship or null if in the actually move no ship sunk.
     * @return A ship object.
     */
    public Ship getLastSunkenShip()
    {
        return lastSunkenShip;
    }

    /**
     * If you destroy the yellow submarine you became this.
     * @return Returns a special string for yellow submarine.
     */
    public String SinkYellowSubmarine()
    {
        String out = "You destroy the yellow submarine. Here a little song for you ;D.\n\n";

        out += "In the town where I was born\n";
        out += "Lived a man who sailed to sea\n";
        out += "And he told us of his life\n";
        out += "In the land of submarines\n";
        out += "So we sailed on to the sun\n";
        out += "Till we found a sea of green\n";
        out += "And we lived beneath the waves\n";
        out += "In our yellow submarine\n\n";

        out += "We all live in a yellow submarine\n";
        out += "Yellow submarine, yellow submarine\n";
        out += "We all live in a yellow submarine\n";
        out += "Yellow submarine, yellow submarine\n - The Beatles \n\n";

        return out;
    }

    /**
     * Determines whether all ships are sunk.
     * @return true = all sunk, false = not
     */
    public boolean Defeated()
    {
        boolean ret = true;
        for (Ship ship : ships)
        {
            if (ship.State != ShipState.Sunk)
                ret = false;
        }
        return ret;
    }

    /**
     * Dispose the class and release objects.
     */
    @Override
    public void Dispose()
    {
        map.clear();
        ships.clear();
    }
}
TOP

Related Classes of entities.Map.FieldMap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.