package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.json.JSONArray;
import org.json.JSONObject;
import card.Card;
import player.BasePlayer;
public class ServerGame extends BaseGame {
ServerSocket server;
public enum PROTOCOL {
VIBE_DUMB
};
List<Card> cards;
long seed;
Random rand;
int movesLeft;
boolean won;
boolean lost;
List<Socket> sockets;
public static void main(String[] args){
ServerGame sg = new ServerGame();
}
public ServerGame() {
establishConnection();
}
protected void establishConnection(){
port = 1337;
sockets = new ArrayList<>();
try {
server = new ServerSocket(port);
while(nrOfPlayers < 2){ //TODO
Socket socket = server.accept();
sockets.add(socket);
JSONObject connectionJson = new JSONObject();
connectionJson.put("id", nrOfPlayers);
sendToClient(CONNECTION_VALID, connectionJson.toString(), socket);
nrOfPlayers++;
System.out.println(nrOfPlayers + " players connected!");
// TODO do this somewhere else
System.out.println("Creating new Socket Listener for #" + (sockets.size()-1));
System.out.println("Socket id: " + socket);
new Thread(new SocketListenerThread(socket)).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
// TODO exit
e.printStackTrace();
}
System.out.println("Initalizing game...");
init();
System.out.println("Sending game to clients");
sendToAll(MOVE_UPDATE, toJson().toString());
}
@Override
protected void init() {
super.init();
seed = 0;
rand = new Random(seed);
movesLeft = -1;
createPlayers();
currentPlayer = 0;
// shuffleCards(); // TODO use this instead of addCards()
addCards();
dealCards();
}
protected void shuffleCards() {
cards = new ArrayList<>();
//TODO add cards
//TODO shuffle
}
// 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;
// AbstractPlayer player = players[selectedPlayer];
// for(int i=0; i<CARDS_PER_PLAYER; ++i){
// 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;
// updateCard(selCardIndex);
// }
// players[currentPlayer].activeCards();
// printMessage("Player " + (currentPlayer+1) + " has finished his move!",
// MSG_TYPES.INFORMATION);
// currentPlayer++;
// if(currentPlayer == N_PLAYERS) currentPlayer = 0;
// players[currentPlayer].deactiveCards();
// resetMoveValues();
// }
protected void receive(Socket socket) {
DataInputStream inStream = null;
byte[] magic = new byte[4];
byte proto = 0;
byte msgType = 0;
byte[] useless = new byte[2];
try {
inStream = new DataInputStream(socket.getInputStream());
inStream.read(magic);
proto = inStream.readByte();
msgType = inStream.readByte();
inStream.read(useless);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO check Protocol
// switch(proto){
// case VIBE_DUMB:
// break;
// }
String msg = null;
JSONObject jo = null;
boolean isValid = true;
boolean wasMove = false;
try {
msg = inStream.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(msg != null) jo = new JSONObject(msg);
// TODO MOVE_DRY
switch(msgType){
case MOVE_PLACE_CARD:
isValid = placeCard(new Card(jo));
wasMove = true;
break;
case MOVE_TRASH_CARD:
isValid = moveCardToTrash(new Card(jo));
wasMove = true;
break;
case MOVE_HINT:
int hintType = jo.getInt("type");
int value = jo.getInt("value");
int player = jo.getInt("player_id");
isValid = giveHint(hintType, value, player);
wasMove = true;
break;
}
if(!isValid) sendToAll(MOVE_INVALID);
if(wasMove){
currentPlayer++;
if(currentPlayer == nrOfPlayers) currentPlayer = 0;
// TODO notify players
if(movesLeft >= 0) movesLeft--;
sendToAll(MOVE_UPDATE, toJson().toString());
}
}
protected Card getRealCard(Card c, int[] index){
Card[] cards = getPlayer(currentPlayer).getCards();
for(int i=0; i<cards.length; ++i){
Card card = cards[i];
if(card.getId() == c.getId()){
if(card.getColorInt() == c.getColorInt() && card.getValue() == c.getValue()){
if(index != null) index[0] = i;
return card;
}
}
}
return null;
}
protected boolean placeCard(Card c) {
int[] index = new int[1];
Card card = getRealCard(c, index);
if(card == null) return false;
int color = card.getColorInt();
int value = card.getValue();
int deckValue = deckCounter[color];
if(deckValue == value){ //place card possible
deckCounter[color]++;
deck[color][value] = card;
if (value + 1 == 5) addHint();
} else { //card too high or too low
addFlash();
moveCardToTrash(card, true);
}
setWonOrLost();
dealCard(index[0], currentPlayer);
return true;
}
protected boolean moveCardToTrash(Card c){
return moveCardToTrash(c, false);
}
protected boolean moveCardToTrash(Card c, boolean receivedFlash) {
int[] index = new int[1];
Card card = getRealCard(c, index);
if(card == null) return false;
// TODO Fix clone removal
if(!receivedFlash) addHint();
trash.add(card);
dealCard(index[0], currentPlayer);
return true;
}
protected boolean giveHint(int type, int value, int playerId){
if(!hintAvailable()) return false;
if(currentPlayer == playerId) return false;
Card[] cards = getPlayer(playerId).getCards();
for(Card c : cards){
boolean is = false;
if(type == HINT_COLOR) is = c.getColorInt() == value;
else if(type == HINT_VALUE) is = c.getValue() == value;
else throw new RuntimeException(); // TODO "vorerst"
c.addCardInfo(type, is, value, currentPlayer);
}
removeHint();
return true;
}
protected void createPlayers() {
players = new BasePlayer[nrOfPlayers];
for(int i=0; i<nrOfPlayers; ++i){
players[i] = new BasePlayer(i, CARDS_PER_PLAYER, "Player " + i);
}
}
protected void dealCards() {
for (int dealtCards =0; dealtCards < CARDS_PER_PLAYER; ++dealtCards) {
for (int i = 0; i < nrOfPlayers; ++i) {
int index = random(cardsInDeck--);
Card card = cards.remove(index);
players[i].setCard(dealtCards, card);
// TODO use this code as soon as the shuffle is implemented
// Card card = getCardFromDeck();
// players[i].setCard(dealtCards, card);
}
}
}
//FIXME no endless do-while...
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) {
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), i));
}
}
private int[] randomPosition(){
int[] p = new int[2];
p[0] = random(5);
p[1] = random(5);
return p;
}
private int random(int max){
return rand.nextInt(max);
}
private void dealCard(int cardPos, int playerID) {
Card card;
if (cardsInDeck > 0) {
int index = random(cardsInDeck--);
card = cards.remove(index);
// TODO Use this code as soon as shuffle is implemented
// card = getCardFromDeck();
} else {
if (movesLeft == -1) movesLeft = nrOfPlayers;
card = Card.DUMMY_CARD;
}
players[playerID].setCard(cardPos, card);
}
void setWonOrLost() {
boolean won = true;
boolean lost = false;
for (int i = 0; i < COLORS; ++i) {
if (deckCounter[i] != 5) {
won = false;
break;
}
}
if (flashs == MAX_FLASHS) {
lost = true;
won = false;
}
if (movesLeft == 0)
lost = true;
if (won){
sendToAll(MOVE_WON);
}
else if (lost){
sendToAll(MOVE_LOST);
}
this.won = won;
this.lost = lost;
}
protected void sendToClient(byte msgType, Socket s){
sendToClient(msgType, null, s);
}
protected void sendToClient(byte msgType, String msg, Socket s){
DataOutputStream os = null;
try {
os = new DataOutputStream(s.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
os.write(MAGIC);
os.write(ServerGame.PROTOCOL.VIBE_DUMB.ordinal());
os.write(msgType);
os.write(new byte[]{ 0, 0 });
if(msg != null) os.writeUTF(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void sendToAll(byte msgType){
sendToAll(msgType, null);
}
protected void sendToAll(byte msgType, String msg){
int i=0;
for(Socket s : sockets){
System.out.println("Sending " + msg + " to socket " + (i++));
sendToClient(msgType, msg, s);
}
}
protected void removeHint() {
hints--;
}
protected void addHint() {
if (hints != MAX_HINTS) {
hints++;
if (hints > MAX_HINTS)
hints = MAX_HINTS;
}
}
protected void addFlash() {
flashs++;
}
@Override
protected void createUI() {
// TODO Auto-generated method stub
}
/**
* Stores the current state of the game in the history
*
* @param json
* the current state as json object
*/
protected void addToHistory(String json) {
history.add(json);
}
protected JSONObject toJson(){
JSONObject root = new JSONObject();
root.put("movesLeft", movesLeft);
root.put("cardsInDeck", cardsInDeck);
root.put("hints", hints);
root.put("flashs", flashs);
root.put("movesLeft", movesLeft);
root.put("movesLeft", movesLeft);
root.put("movesLeft", movesLeft);
root.put("movesLeft", movesLeft);
root.put("movesLeft", movesLeft);
JSONArray trashArray = new JSONArray();
for(Card c : trash){
trashArray.put(c.toJson());
}
root.put("trash", trashArray);
JSONObject deckRow = new JSONObject();
for(int i=0; i<deck.length; ++i){
JSONObject deckCol = new JSONObject();
for(int j=0; j<deck[i].length; ++j){
deckCol.put(String.valueOf(j), deck[i][j]);
}
deckRow.put(String.valueOf(i), deckCol);
}
JSONArray playerArray = new JSONArray();
for(BasePlayer p : players){
playerArray.put(p.toJson());
}
root.put("players", playerArray);
root.put("currentPlayer", currentPlayer);
return root;
}
@Override
protected void createHistory() {
history = new ArrayList<>();
}
}