/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package monopoly.model.game;
import external.HTMLColors;
import java.awt.Color;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import monopoly.model.events.GameModelEvent;
import monopoly.model.events.IGameModelListener;
import monopoly.model.game.Dice.DiceScore;
import monopoly.model.gamefield.CompanyCell;
import monopoly.model.gamefield.EmptyCell;
import monopoly.model.gamefield.GameField;
import monopoly.model.gamefield.GameFieldCellBase;
import monopoly.model.gamefield.GiftCell;
import monopoly.model.gamefield.PenaltyCell;
import monopoly.model.personality.Bank;
import monopoly.model.personality.ILandOwner;
import monopoly.model.personality.ILandSeller;
import monopoly.model.personality.Player;
import monopoly.model.resource.ILand;
/**
* Определяет модель игры.
* @author Роман
*/
public final class GameModel {
/**
* Игровое поле.
*/
private final GameField _field;
/**
* Игровые кости.
*/
private final Dice _dice;
/**
* Банк.
*/
private final Bank _bank;
/**
* Стартовая ячейка игры.
*/
private GameFieldCellBase _startCell;
/**
* Игроки, расположенные в порядке их игровой очереди.
*/
private Queue<Player> _playersQueue;
/**
* Доступные цвета для игроков.
*/
private List<Color> _availableColors;
/**
* Получить текущего игрока и перейти к следующему.
* @return текущий игрок.
*/
private Player nextPlayer() {
if (_playersQueue.isEmpty()) {
return null;
}
Player p = _playersQueue.poll();
_playersQueue.offer(p);
return p;
}
/**
* Закончить игру для данного игрока.
* @param p игрок.
*/
private void finishGamePlayer(Player p) {
_bank.doBankrupt(p);
_field.removePlayer(p);
_playersQueue.remove(p);
GameModelEvent event = new GameModelEvent(this, p);
firePlayerFinishedGame(event);
}
/**
* Проверить на возможность окончания игры.
*/
private void identifyGameOver() {
if (_playersQueue.size() <= 1) {
GameModelEvent event = new GameModelEvent(this, _playersQueue.peek());
fireGameFinished(event);
}
}
/**
* Слушатели действий модели игры.
*/
private final List<IGameModelListener> _listeners =
new ArrayList<IGameModelListener>();
/**
* Запустить событие - игрок бросил игровые кости.
* @param e аргументы события.
*/
protected void firePlayerDroppedDice(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerDroppedDice(e);
}
}
/**
* Запустить событие - игрок переместился на игровом поле.
* @param e аргументы события.
*/
protected void firePlayerShiftedOnField(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerShiftedOnField(e);
}
}
/**
* Запустить событие - игрок начал выполнять действие.
* @param e аргументы события.
*/
protected void firePlayerStartedDoAction(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerStartedDoAction(e);
}
}
/**
* Запустить событие - игрок получил подарок.
* @param e аргументы события.
*/
protected void firePlayerReceivedGift(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerReceivedGift(e);
}
}
/**
* Запустить событие - игрок был оштрафован.
* @param e аргументы события.
*/
protected void firePlayerReceivedPenalty(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerReceivedPenalty(e);
}
}
/**
* Запустить событие - у земельного участка сменился владелец.
* @param e аргументы события.
*/
protected void fireLandChangedOwner(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gameLandChangedOwner(e);
}
}
/**
* Запустить событие - у игрока была конфискована земельная собственность.
* @param e аргументы события.
*/
protected void firePlayerLandsConfiscated(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerLandsConfiscated(e);
}
}
/**
* Запустить событие - игрок приобрел земельную собственность.
* @param e аргументы события.
*/
protected void firePlayerBoughtLand(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerBoughtLand(e);
}
}
/**
* Запустить событие - игрок уплатил ренту.
* @param e аргументы события.
*/
protected void firePlayerPaidRent(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerPaidRent(e);
}
}
/**
* Запустить событие - игрок закончил игру(банкрот).
* @param e аргументы события.
*/
protected void firePlayerFinishedGame(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gamePlayerFinishedGame(e);
}
}
/**
* Запустить событие - игра начата.
* @param e аргументы события.
*/
protected void fireGameStarted(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gameStarted(e);
}
}
/**
* Запустить событие - игра закончина и выявлен победитель.
* @param e аргументы события.
*/
protected void fireGameFinished(GameModelEvent e) {
for (IGameModelListener listener : _listeners) {
listener.gameFinished(e);
}
}
/**
* Добавить нового слушателя.
* @param listener слушатель.
*/
public void addGameModelListener(IGameModelListener listener) {
_listeners.add(listener);
}
/**
* Удалить указанного слушателя.
* @param listener слушатель.
*/
public void removeGameModelListener(IGameModelListener listener) {
_listeners.remove(listener);
}
/**
* Получить стартовую ячейку на игровом поле.
* @return ячейка.
*/
public GameFieldCellBase startCell() {
return _startCell;
}
/**
* Получить игровое поле.
* @return игровое поле.
*/
public GameField field() {
return _field;
}
/**
* Получить игроков.
* @return список игроки.
*/
public List<Player> players() {
return _field.players();
}
/**
* Получить банк.
* @return банк.
*/
public Bank bank() {
return _bank;
}
/**
* Получить игровые кости.
* @return игровые кости.
*/
public Dice dice() {
return _dice;
}
/**
* Начать игру.
* @param playerCount количество игроков.
*/
public void start(int playerCount) {
_field.clear();
_field.addCell(new EmptyCell());
_field.addCell(new CompanyCell(
"Bacardi", 16000, (int) (16000 * 0.6), 3500));
_field.addCell(new PenaltyCell());
_field.addCell(new CompanyCell(
"Smirnoff", 16000, (int) (16000 * 0.6), 2500));
_field.addCell(new PenaltyCell());
_field.addCell(new CompanyCell(
"Absolut Vodka", 16000, (int) (16000 * 0.6), 4000));
_field.addCell(new GiftCell());
_field.addCell(new CompanyCell(
"Microsoft", 88000, (int) (88000 * 0.6), 38000));
_field.addCell(new CompanyCell(
"Marlboro", 20000, (int) (20000 * 0.6), 1500));
_field.addCell(new EmptyCell());
_field.addCell(new CompanyCell(
"Kent", 20000, (int) (20000 * 0.6), 1500));
_field.addCell(new CompanyCell(
"Parlament", 20000, (int) (20000 * 0.6), 2000));
_field.addCell(new CompanyCell(
"Nike", 28000, (int) (28000 * 0.6), 4000));
_field.addCell(new CompanyCell(
"Adidas", 28000, (int) (28000 * 0.6), 6300));
_field.addCell(new CompanyCell(
"Puma", 28000, (int) (28000 * 0.6), 4900));
_field.addCell(new GiftCell());
_field.addCell(new CompanyCell(
"IBM", 50000, (int) (50000 * 0.6), 15900));
_field.addCell(new CompanyCell(
"Scania", 35000, (int) (35000 * 0.6), 10000));
_field.addCell(new EmptyCell());
_field.addCell(new CompanyCell(
"Man", 40000, (int) (40000 * 0.6), 12000));
_field.addCell(new GiftCell());
_field.addCell(new CompanyCell(
"Nokia", 48000, (int) (48000 * 0.6), 16000));
_field.addCell(new CompanyCell(
"Samsung", 48000, (int) (48000 * 0.6), 17000));
_field.addCell(new CompanyCell(
"Panasonic", 48000, (int) (48000 * 0.6), 17000));
_field.addCell(new CompanyCell(
"Apple", 90000, (int) (90000 * 0.6), 40000));
_field.addCell(new CompanyCell(
"Beeline", 52000, (int) (52000 * 0.6), 25000));
_field.addCell(new CompanyCell(
"Megafon", 52000, (int) (52000 * 0.6), 27000));
_field.addCell(new PenaltyCell());
_field.addCell(new CompanyCell(
"Gucci", 64000, (int) (64000 * 0.6), 29900));
_field.addCell(new CompanyCell(
"Cannel", 65000, (int) (65000 * 0.6), 28000));
_field.addCell(new PenaltyCell());
_field.addCell(new CompanyCell(
"Dell", 68000, (int) (68000 * 0.6), 30000));
_field.addCell(new GiftCell());
_field.addCell(new CompanyCell(
"Pepsi", 80000, (int) (80000 * 0.6), 36000));
_field.addCell(new PenaltyCell());
_field.addCell(new CompanyCell(
"Coca-cola", 85000, (int) (85000 * 0.6), 38100));
List<GameFieldCellBase> cells = _field.cells();
for (int i = 0; i < cells.size() - 1; i++) {
cells.get(i).setNext(cells.get(i + 1));
}
cells.get(cells.size() - 1).setNext(cells.get(0));
_startCell = cells.get(0);
for (GameFieldCellBase c : cells) {
if (c instanceof CompanyCell) {
_bank.addLand((CompanyCell) c);
}
}
for (int i = 0; i < playerCount; i++) {
_field.addPlayer(_startCell,
new Player("Игрок " + (i + 1),
_availableColors.get(i), 150000));
}
_playersQueue = new ArrayDeque(_field.players());
GameModelEvent event = new GameModelEvent(this);
this.fireGameStarted(event);
}
/**
* Задать новую игру.
*/
public GameModel() {
_dice = new Dice();
_bank = new Bank();
_field = new GameField();
_availableColors = new ArrayList<Color>();
_availableColors.add(HTMLColors.red);
_availableColors.add(HTMLColors.blue);
_availableColors.add(HTMLColors.green);
_availableColors.add(HTMLColors.gray);
_availableColors.add(HTMLColors.yellow);
_availableColors.add(HTMLColors.orange);
_availableColors.add(HTMLColors.black);
_availableColors.add(HTMLColors.purple);
_availableColors.add(HTMLColors.lime);
_availableColors.add(HTMLColors.olive);
start(0);
}
/**
* Выполнить очередной ход игры.
* Свой ход делает следующий по очереди игрок. Игрок перемешается по ячейкам
* игрового поля, в соответсвии с количеством очков выпавших на костях.
* После того как игрок дойдет до целевой ячейки, он совершает действие
* согласно игровой логике этой ячейки.
*/
public void makeNextMove() {
Player p = nextPlayer();
if (p == null) {
return;
}
DiceScore diceScore = p.dropDice(_dice);
GameModelEvent event = new GameModelEvent(this, p, diceScore);
firePlayerDroppedDice(event);
GameFieldCellBase oldPosition = p.position();
p.shiftOnField(diceScore.score());
GameFieldCellBase newPosition = p.position();
event = new GameModelEvent(this, p, oldPosition, newPosition);
firePlayerShiftedOnField(event);
event = new GameModelEvent(this, p);
firePlayerStartedDoAction(event);
}
/**
* Сделать игроку подарок в указанном размере в виде денежной суммы.
* @param p игрок.
* @param gift подарок в виде денежной суммы.
*/
public void makePlayerGift(Player p, int gift) {
if (_bank.giveMoney(p, gift)) {
GameModelEvent event = new GameModelEvent(this, p, gift);
firePlayerReceivedGift(event);
}
}
/**
* Оштрафовать игрока на указанную сумму.
* @param p игрок.
* @param penalty штраф в виде денежной суммы.
*/
public void makePlayerPenalty(Player p, int penalty) {
if (_bank.takeAwayMoney(p, penalty) == false) {
List<ILand> confiscated = new ArrayList<ILand>();
ILand lastLand = _bank.confiscateLand(p);
while (lastLand != null) {
GameModelEvent event = new GameModelEvent(this, lastLand,
p, _bank);
fireLandChangedOwner(event);
confiscated.add(lastLand);
if (_bank.takeAwayMoney(p, penalty)) {
break;
}
lastLand = _bank.confiscateLand(p);
}
if (confiscated.isEmpty() == false) {
GameModelEvent event = new GameModelEvent(this, p, confiscated);
firePlayerLandsConfiscated(event);
}
if (lastLand == null) {
finishGamePlayer(p);
} else {
GameModelEvent event = new GameModelEvent(this, p, penalty);
firePlayerReceivedPenalty(event);
}
} else {
GameModelEvent event = new GameModelEvent(this, p, penalty);
firePlayerReceivedPenalty(event);
}
identifyGameOver();
}
/**
* Заставить игрока заплатить арендную плату (ренту) за земельный участок.
* @param p игрок.
* @param land земельный участок.
*/
public void makePlayerPayRent(Player p, ILand land) {
if (land.owner() == _bank || land.owner() == p) {
return;
}
if (p.payRent(land) == false) {
List<ILand> confiscated = new ArrayList<ILand>();
ILand lastLand = _bank.confiscateLand(p);
while (lastLand != null) {
GameModelEvent event = new GameModelEvent(this, lastLand,
p, _bank);
fireLandChangedOwner(event);
confiscated.add(lastLand);
if (p.payRent(land)) {
break;
}
lastLand = _bank.confiscateLand(p);
}
if (confiscated.isEmpty() == false) {
GameModelEvent event = new GameModelEvent(this, p, confiscated);
firePlayerLandsConfiscated(event);
}
if (lastLand == null) {
finishGamePlayer(p);
} else {
GameModelEvent event = new GameModelEvent(this, p, land);
firePlayerPaidRent(event);
}
} else {
GameModelEvent event = new GameModelEvent(this, p, land);
firePlayerPaidRent(event);
}
identifyGameOver();
}
/**
* Приобрести земельный участок за указанную цену игроку.
* @param p игрок.
* @param land покупаемый земельный участок.
* @param amount сумма сделки.
*/
public void makePlayerBuyLand(Player p, ILand land, int amount) {
ILandOwner owner = land.owner();
if (owner instanceof ILandSeller) {
ILandSeller seller = (ILandSeller) owner;
if (p.buyLand(seller, amount, land)) {
GameModelEvent event = new GameModelEvent(this, land, seller, p);
fireLandChangedOwner(event);
event = new GameModelEvent(this, p, land, amount);
firePlayerBoughtLand(event);
}
}
}
}