de.gtrefs.ai.ludo.model.Board.java Source code

Java tutorial

Introduction

Here is the source code for de.gtrefs.ai.ludo.model.Board.java

Source

/*
 * Copyright (C) 2010 Gregor Trefs, Dominique Ritze
 *
 * 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/>.
 */
package de.gtrefs.ai.ludo.model;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import de.gtrefs.ai.ludo.model.Game.Color;

/**
 * Represents the board of the ludo game.
 * <p>
 * It consists  * further enables the {@link de.gtrefs.ai.ludo.model.Game Game} to introduce
 * new players to the board. After introduction, a player has a path and pawns,
 * which then can be used by the {@link de.gtrefs.ai.ludo.model.Player Player}
 * to play Ludo.
 * 
 * @author gtrefs
 */
public class Board {

    private static final int NUMBER_OF_BOARD_FIELDS = 36;
    private static final int NUMBER_OF_BOARD_FIELDS_PER_CORNER = 9;

    private Map<Game.Color, List<StartField>> startFieldsByColor;
    private Map<Game.Color, BeginField> beginFieldsByColor;
    private Map<Game.Color, List<EndField>> endFieldsByColor;
    private Map<Game.Color, List<Field>> fieldsSortedByColor;
    private List<Field> boardFields;
    private Map<Game.Color, List<Pawn>> pawnsByColor;
    private Map<Game.Color, Player> playersByColor;

    public Board() {
        playersByColor = Maps.newEnumMap(Game.Color.class);
        buildBoard();
    }

    private void buildBoard() {
        startFieldsByColor = buildFieldsByType(StartField.class);
        endFieldsByColor = buildFieldsByType(EndField.class);
        beginFieldsByColor = buildBeginFields();
        fieldsSortedByColor = Maps.newEnumMap(Game.Color.class);
        boardFields = Lists.newArrayList();
        buildFieldsSortedByColor();
        createPawnsPerColor();
    }

    private void createPawnsPerColor() {
        pawnsByColor = Arrays.stream(Game.Color.values()).collect(Collectors.toMap(color -> color,
                color -> Stream.generate(Pawn::new).limit(4).collect(Collectors.toList())));
    }

    private Map<Color, BeginField> buildBeginFields() {
        return Arrays.stream(Game.Color.values())
                .collect(Collectors.toMap(color -> color, color -> new BeginField()));
    }

    private void buildFieldsSortedByColor() {
        buildBoardFieldsInterleavedByBeginFields();
        sortBoardFieldsSpecificToEachColor();
    }

    private void buildBoardFieldsInterleavedByBeginFields() {
        int colorIndex = 0;
        for (int i = 0; i < NUMBER_OF_BOARD_FIELDS; i++) {
            if (i % NUMBER_OF_BOARD_FIELDS_PER_CORNER == 0) {
                boardFields.add(
                        beginFieldsByColor.get(Game.Color.values()[colorIndex++ % Game.Color.values().length]));
            }
            boardFields.add(new BoardField());
        }
    }

    private void sortBoardFieldsSpecificToEachColor() {
        int offset = 0;
        for (Game.Color color : Game.Color.values()) {
            List<Field> listSpecificToColor = Lists.newArrayList();
            IntStream.range(offset, offset + boardFields.size())
                    .forEach(i -> listSpecificToColor.add(boardFields.get(i % boardFields.size())));
            fieldsSortedByColor.put(color, listSpecificToColor);
            offset += (NUMBER_OF_BOARD_FIELDS_PER_CORNER + 1);
        }
    }

    private <T> Map<Game.Color, List<T>> buildFieldsByType(Class<T> clazz) {
        return Arrays.stream(Game.Color.values()).collect(Collectors.toMap(color -> color,
                color -> Stream.generate(generate(clazz)).limit(4).collect(Collectors.toList())));
    }

    private <T> Supplier<T> generate(Class<T> clazz) {
        return () -> {
            try {
                return clazz.newInstance();
            } catch (Exception e) {
                throw Throwables.propagate(e);
            }
        };
    }

    /**
     * Returns the pawns of a specific color.
     * @param color color of the pawns
     * @return the pawns of the provided color
     */
    public List<Pawn> getPawnsByColor(Game.Color color) {
        return pawnsByColor.get(color);
    }

    /**
     * Registers a player to the board. If the color was previously chosen by
     * another player or the player's color property is null, a
     * {@link de.uni_mannheim.informatik.ai.ludo.exceptions.ColorException
     * ColorException} is thrown. After introduction, the player has a path,
     * pawns and is able to play the game.
     * 
     * @param player
     *            Player which wants to be introduced to this board.
     * @throws ColorException
     *             if another player was previously introduced with the same
     *             color or the the player's color property is null
     */
    public void introducePlayer(Player player) {
        Game.Color playerColor = Optional.ofNullable(player.getColor()).orElseThrow(IllegalArgumentException::new);

        if (playersByColor.get(playerColor) != null) {
            throw new IllegalArgumentException(
                    String.format("Player %s uses same color as another player.", player.getName()));
        }

        createAndAddPath(player, playerColor);
        addPawns(player, playerColor);
        placePawnsOnStartField(playerColor);
        playersByColor.put(playerColor, player);
    }

    private void createAndAddPath(Player owner, Game.Color color) {
        Path playerPath = new Path(fieldsSortedByColor.get(color), startFieldsByColor.get(color),
                endFieldsByColor.get(color));
        owner.setPath(playerPath);
        playerPath.setOwner(owner);
    }

    private void addPawns(Player owner, Game.Color playerColor) {
        List<Pawn> colorPawns = getPawnsByColor(playerColor);
        colorPawns.forEach(pawn -> pawn.setOwner(owner));
        owner.setPawns(colorPawns);
    }

    /**
     * Returns the player with the specific color.
     * @param color of the player
     * @return Player instance with the provided color
     */
    public Player getPlayerByColor(Game.Color color) {
        return playersByColor.get(color);
    }

    /**
     * Sets all pawns of the participating players back on the start fields.
     */
    public void reset() {
        clearBoardFields();
        playersByColor.keySet().forEach(playerColor -> {
            clearStartAndEndFieldsOfColorFromPawns(playerColor);
            placePawnsOnStartField(playerColor);
        });
    }

    private void clearBoardFields() {
        boardFields.forEach(f -> f.takePawnFromField());
    }

    private void clearStartAndEndFieldsOfColorFromPawns(Game.Color color) {
        clearStartFields(color);
        clearEndFields(color);
    }

    private void clearEndFields(Game.Color color) {
        endFieldsByColor.get(color).forEach(e -> e.takePawnFromField());
    }

    private void clearStartFields(Game.Color color) {
        startFieldsByColor.get(color).forEach(s -> s.takePawnFromField());
    }

    private void placePawnsOnStartField(Game.Color color) {
        List<Pawn> pawns = pawnsByColor.get(color);
        List<StartField> startFields = startFieldsByColor.get(color);
        IntStream.range(0, 4).forEach(i -> startFields.get(i).placePawnOnField(pawns.get(i)));
    }
}