package game;
import player.AbstractPlayer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import org.json.*;
import card.Card;
public abstract class BaseGame {
/*
* COLORS:
* GREEN
* RED
* YELLOW
* WHITE
* BLUE
* (COLORED)
*/
public enum MSG_TYPES {ERROR, WARNING, INFORMATION, QUESTION};
final static int GREEN = 0;
final static int RED = 1;
final static int YELLOW = 2;
final static int WHITE = 3;
final static int BLUE = 4;
//final static int COLORED = 5;
final static int COLORS = 5;
int N_PLAYERS = 2;
static int CARDS_PER_PLAYER;
final static int N_CARDS = 50;
int CARDS_IN_DECK;
final static int MAX_HINTS = 8;
final static int MAX_THUNDERS = 3;
int hints;
int thunders;
ArrayList<Card> cards;
Card[][] deck;
int[] deckCounter;
ArrayList<Card> trash;
AbstractPlayer[] players;
int currentPlayer;
int roundsLeft;
int selectedPlayer;
int selectedCards;
int chosenColor;
int chosenValue;
boolean useColor;
boolean useValue;
boolean placeCard;
boolean trashCard;
boolean won;
boolean lost;
//Options stuff
final File options = new File("options.json");
JSONObject root;
int difficulty;
int fontSize;
//Network stuff
ServerSocket server;
Socket s;
boolean isHost;
public BaseGame(){
init();
}
protected void init(){
loadOptions();
loadFont();
//establishConnection();
CARDS_PER_PLAYER = (N_PLAYERS <= 3) ? 5 : 4;
hints = MAX_HINTS;
thunders = 0;
roundsLeft = -1;
createPlayers();
currentPlayer = 0;
resetMoveValues();
addCards();
CARDS_IN_DECK = cards.size();
createUI();
dealCards();
}
protected void loadOptions(){
try {
JSONTokener tokener = new JSONTokener(options.toURI().toURL().openStream());
root = new JSONObject(tokener);
difficulty = root.getInt("difficulty");
fontSize = root.getInt("fontSize");
isHost = root.getBoolean("host");
if(difficulty < 0) difficulty = 0;
if(fontSize <= 0) fontSize = 20;
} catch (JSONException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void establishConnection(){
try {
if(isHost){
server = new ServerSocket(8765);
printMessage("Your server is running on port 8765", MSG_TYPES.INFORMATION);
s = server.accept();
DataInputStream inStream = new DataInputStream(s.getInputStream());
String str = inStream.readUTF();
System.out.println("Message: " + str);
s.close();
server.close();
} else {
s = new Socket("localhost", 8765);
DataOutputStream outStream = new DataOutputStream(s.getOutputStream());
outStream.writeUTF("Hello");
outStream.flush();
outStream.close();
s.close();
}
} catch(UnknownHostException uhe){
printMessage("Unknown host '???'", MSG_TYPES.ERROR);
} catch (IOException e) {
printMessage(e.getLocalizedMessage(), MSG_TYPES.ERROR);
System.exit(0); //TODO status code
}
}
public void resetMoveValues(){
selectedPlayer = -1;
chosenColor = -1;
chosenValue = -1;
selectedCards = 0;
useColor = useValue = trashCard = placeCard = false;
}
protected void createPlayers(){
players = new AbstractPlayer[N_PLAYERS];
}
private void addCards(){
cards = new ArrayList<>();
deck = new Card[COLORS][5];
deckCounter = new int[5];
for(int i=0; i<5; ++i){
deckCounter[i] = 0;
}
trash = new ArrayList<>();
int[] dist = new int[]{3, 2, 2, 2, 1};
int[][] tmp_cards = new int[][]{
dist.clone(),
dist.clone(),
dist.clone(),
dist.clone(),
dist.clone()
};
for(int i=0; i<N_CARDS; ++i){
//Point p = null;
int[] p = new int[2];
do{
p = randomPosition();
} while(tmp_cards[p[0]][p[1]] == 0);
tmp_cards[p[0]][p[1]]--;
cards.add(new Card(p[0], (p[1] + 1), -1, this));
}
}
boolean checkValidMove(){
if(selectedCards == 0) return false;
if(!hintAvailable() && (useColor || useValue)) return false;
if((trashCard || placeCard) && selectedCards == 1) return true;
int countCards = 0;
for(int i=0; i<CARDS_PER_PLAYER; ++i){
AbstractPlayer p = players[selectedPlayer];
if(useColor){
if(p.getCard(i).getColorInt() == chosenColor) countCards++;
} else if(useValue){
if(p.getCard(i).getValue() == chosenValue) countCards++;
}
}
return (countCards == selectedCards);
}
protected abstract void createUI();
void moveCardToTrash(int index){
trash.add(players[currentPlayer].getCard(index).clone());
updateCards(index);
}
void updateCards(int index){
dealCard(index, currentPlayer);
players[currentPlayer].setCardInfo(index, "");
Card c = players[currentPlayer].getCard(index);
if(c.getValue() == -1){ //dummy card, no more cards
setNoCard(index);
}
}
protected abstract void setNoCard(int index);
private void dealCard(int cardID, int playerID){
Card card;
if(CARDS_IN_DECK > 0){
int index = random(CARDS_IN_DECK--);
card = cards.remove(index);
} else {
if(roundsLeft == -1) roundsLeft = N_PLAYERS;
card = new Card(3, -1, playerID, this);
}
players[playerID].setCard(cardID, card);
}
protected void dealCards(){
int dealtCards = 0;
for(; dealtCards < CARDS_PER_PLAYER; ++dealtCards){
for(int i=0; i<N_PLAYERS; ++i){
int index = random(CARDS_IN_DECK--);
Card card = cards.remove(index);
players[i].setCard(dealtCards, card);
}
}
}
boolean hintAvailable(){
return (hints > 0);
}
void setWonOrLost(){
won = true;
lost = false;
for(int i=0; i<COLORS; ++i){
System.out.println("Deck " + i + ": " + deckCounter[i]);
if(deckCounter[i] != 5){
won = false;
break;
}
}
if(thunders == MAX_THUNDERS){
lost = true;
won = false;
}
if(roundsLeft == 0) lost = true;
if(won) printMessage("You won!", MSG_TYPES.INFORMATION);
else if(lost) printMessage("You lost...", MSG_TYPES.INFORMATION);
}
private int[] randomPosition(){
int[] p = new int[2];
p[0] = random(5);
p[1] = random(5);
return p;
}
private int random(int max){
return (int) (Math.random() * max);
}
public void setSelectedPlayer(int selectedPlayer){
this.selectedPlayer = selectedPlayer;
}
public int getSelectedPlayer(){
return selectedPlayer;
}
public AbstractPlayer getPlayer(int index){
return players[index];
}
public int getCurrentPlayerIndex(){
return currentPlayer;
}
public boolean isTrashCard(){
return trashCard;
}
public boolean isPlaceCard(){
return placeCard;
}
public boolean isUseColor(){
return useColor;
}
public boolean isUseValue(){
return useValue;
}
public int getChosenColor(){
return chosenColor;
}
public void setChosenColor(int chosenColor){
this.chosenColor = chosenColor;
}
public int getChosenValue(){
return chosenValue;
}
public void setChosenValue(int chosenValue){
this.chosenValue = chosenValue;
}
public int getSelectedCards(){
return selectedCards;
}
public void addSelectedCards(){
selectedCards++;
}
public void removeSelectedCards(){
selectedCards--;
}
public int getDifficulty(){
return difficulty;
}
public abstract void loadFont();
public int getFontSize(){
return fontSize;
}
public abstract Object getFont();/*{*/
//return font;
//}
public abstract void printMessage(String msg, MSG_TYPES type);
protected void removeHint(){
hints--;
}
protected void addHint(){
if(hints != MAX_HINTS){
hints++;
if(hints > MAX_HINTS) hints = MAX_HINTS;
}
}
protected void addThunder(){
thunders++;
}
protected void placeCard(Card c, int color, int value){
deckCounter[color]++;
deck[color][value] = c;
if(value+1 == 5) addHint();
}
protected void onNext(){
if(!checkValidMove()){
printMessage("Please select all cards of the selected color/value", MSG_TYPES.ERROR);
return;
}
if(roundsLeft >= 0) roundsLeft--;
int selCardIndex = 0;
for(int i=0; i<CARDS_PER_PLAYER; ++i){
AbstractPlayer player = players[selectedPlayer];
Card card = player.getCard(i);
String from = "(from Player " + currentPlayer + ")";
if(card.isSelected()){
selCardIndex = i;
card.setSelected(false);
if(useColor){
String color = "- " + Card.intColorToText(chosenColor);
player.setCardInfo(i, player.getCardInfo(i) + color + " " + from + "\n");
} else if(useValue){
String value = "- is " + chosenValue;
player.setCardInfo(i, player.getCardInfo(i) + value + " " + from + "\n");
}
} else {
if(useColor){
String color = "- not " + Card.intColorToText(chosenColor);
player.setCardInfo(i, player.getCardInfo(i) + color + " " + from + "\n");
} else if(useValue){
String value = "- is not " + chosenValue;
player.setCardInfo(i, player.getCardInfo(i) + value + " " + from + "\n");
}
}
}
if(useColor || useValue){
removeHint();
} else if(trashCard){
moveCardToTrash(selCardIndex);
addHint();
} else if(placeCard){
Card c = players[currentPlayer].getCard(selCardIndex);
int color = c.getColorInt();
int value = c.getValue();
int deckValue = deckCounter[color] + 1;
if(deckValue == value){ //place card possible
placeCard(c, color, value-1);
} else { //card too high or too low
addThunder();
moveCardToTrash(selCardIndex);
}
setWonOrLost();
if(lost) return;
updateCards(selCardIndex);
}
players[currentPlayer].activeCards();
printMessage("Player " + currentPlayer + " has finished his move!", MSG_TYPES.INFORMATION);
currentPlayer++;
if(currentPlayer == N_PLAYERS) currentPlayer = 0;
players[currentPlayer].deactiveCards();
resetMoveValues();
}
protected void onColor(){
if(!hintAvailable()){
printMessage("No hints left!", MSG_TYPES.ERROR);
return;
}
if(selectedCards > 0){
printMessage("Please deselect all cards first", MSG_TYPES.ERROR);
return;
}
useColor = true;
useValue = false;
placeCard = false;
trashCard = false;}
protected void onValue(){
if(!hintAvailable()){
printMessage("No hints left!", MSG_TYPES.ERROR);
return;
}
if(selectedCards > 0){
printMessage("Please deselect all cards first", MSG_TYPES.ERROR);
return;
}
useValue = true;
useColor = false;
placeCard = false;
trashCard = false;
}
protected void onTrash(){
if(selectedCards > 0){
printMessage("Please deselect all cards first", MSG_TYPES.ERROR);
return;
}
useColor = false;
useValue = false;
placeCard = false;
trashCard = true;
}
protected void onPlace(){
if(selectedCards > 0){
printMessage("Please deselect all cards first", MSG_TYPES.ERROR);
return;
}
useColor = false;
useValue = false;
placeCard = true;
trashCard = false;
}
protected abstract void showTrash();
}