package algorithms;
import general.Card;
import general.Range;
import general.Symbol;
import java.util.Random;
import utils.CardUtils;
public class DivAlgorithm extends DealingAlgorithm {
private Card[] royalDeck;
private Card[] nonRoyal;
public DivAlgorithm(int num) {
super(num);
royalDeck = new Card[16];
nonRoyal = new Card[36];
int pos = 0;
int nonPos = 0;
for (int i = 0; i < deck.length; i++) {
if (deck[i].getLetter().isRoyal()) {
royalDeck[pos] = deck[i];
pos++;
} else {
nonRoyal[nonPos] = deck[i];
nonPos++;
}
}
}
public static int[] playersOrder = new int[] { 0, 1, 2, 3 };
public void deal(Card[] cards) {
// deck = new Card[cards.length];
// System.arraycopy(cards, 0, deck, 0, cards.length);
deck = royalDeck;
for (int i = 0; i < num; i++) {
CardUtils.shuffle(deck);
int ans = deal(0, num - 1, 0, 0, 0, 0);
if (ans >= 0)
answers[i] = answers[num - 1];
else
i--; // retry
// answers[i+num/2] = answers[num -2];
//System.err.println(i);
}
printResults();
}
public int deal(int pos, int amount, int pos0, int pos1, int pos2, int pos3) {
CardUtils.shuffle(playersOrder);
// for each card there are 4 options: N,W,S,E
if (pos == this.royalDeck.length && amount < num) // on the last on
{
if (isScoreLegal(true, pos0, pos1, pos2, pos3)) {
System.out.println("Here");
return this.completeHands(allHands, this.nonRoyal, pos0, pos1,
pos2, pos3, amount);
}
return amount;
} else {
int tempAmount = amount;
int player;
for (int i = 0; i < 4; i++) {
player = DivAlgorithm.playersOrder[i];
if (player == 0) {
if (pos0 < 13) // no more then 13 cards
{
allHands[0][pos0] = deck[pos];
if (isScoreLegal(false, pos0 + 1, pos1, pos2, pos3)) {
tempAmount = deal(pos + 1, tempAmount, pos0 + 1,
pos1, pos2, pos3);
}
if (tempAmount >= num)
return tempAmount;
}
} else if (player == 1) {
if (pos1 < 13) // no more then 13 cards
{
allHands[1][pos1] = deck[pos];
if (isScoreLegal(false, pos0, pos1 + 1, pos2, pos3)) {
tempAmount = deal(pos + 1, tempAmount, pos0,
pos1 + 1, pos2, pos3);
}
if (tempAmount >= num)
return tempAmount;
}
} else if (player == 2) {
if (pos2 < 13) // no more then 13 cards
{
allHands[2][pos2] = deck[pos];
if (isScoreLegal(false, pos0, pos1, pos2 + 1, pos3)) {
tempAmount = deal(pos + 1, tempAmount, pos0, pos1,
pos2 + 1, pos3);
}
if (tempAmount >= num)
return tempAmount;
}
} else {
if (pos3 < 13) // no more then 13 cards
{
allHands[3][pos3] = deck[pos];
if (isScoreLegal(false, pos0, pos1, pos2, pos3 + 1)) {
tempAmount = deal(pos + 1, tempAmount, pos0, pos1,
pos2, pos3 + 1);
}
if (tempAmount >= num)
return tempAmount;
}
}
}
return tempAmount;
}
}
private void count(int pos, Card[] royalHands, int[] amounts) {
for (int i = 0; i < pos; i++) {
amounts[royalHands[i].getSymbol().getLocation()]++;
}
}
private static final int[] randomForplayers = new int[] { 0, 1, 2, 3 };
private static final int[] randomForSuites = new int[] { 0, 1, 2, 3 };
private int completeHands(Card[][] royalHands, Card[] rest, int pos0,
int pos1, int pos2, int pos3, int amount) {
Card[][] splited = split(rest);
for (int i = 0; i < 4; i++) {
CardUtils.shuffle(splited[i]);
}
int[][] amounts = new int[4][4];
count(pos0, royalHands[0], amounts[0]);
count(pos1, royalHands[1], amounts[1]);
count(pos2, royalHands[2], amounts[2]);
count(pos3, royalHands[3], amounts[3]);
// check that all the players can have the minimum range of cards
Range[][] newRanges = new Range[4][4];
for (int i = 0; i < 4; i++) {
int cardsNeeded = 0;
for (Symbol symb : Symbol.values()) {
newRanges[i][symb.getLocation()] = new Range(
this.cardLimits[i][symb.getLocation()].getMin()
- amounts[i][symb.getLocation()],
this.cardLimits[i][symb.getLocation()].getMax()
- amounts[i][symb.getLocation()]);
if (newRanges[i][symb.getLocation()].getMax() < 0) // has more
// then the
// maximum
// card
return amount;
cardsNeeded += newRanges[i][symb.getLocation()].getMin();
}
// check that the number of minimum cards required from each player
// is bigger then the card he has
if (cardsNeeded + this.getPos(i, pos0, pos1, pos2, pos3) > 13)
return amount;
}
// check that all the minimum criterion are reachable per suite
for (Symbol symb : Symbol.values()) {
int neededFromSuite = 0;
for (int i = 0; i < 4; i++) {
neededFromSuite += newRanges[i][symb.getLocation()].getMin();
}
if (neededFromSuite > 9) // more then non-royal cards still needed
// by the players
return amount;
}
// if we arrived here than all we need to do is to deal each player the
// minimum from each suite then deal the rest
int[] positions = new int[] { pos0, pos1, pos2, pos3 };
int[] restPositions = new int[] { 0, 0, 0, 0 };
for (int s = 0; s < 4; s++) {
for (int p = 0; p < 4; p++) {
if (newRanges[p][s].getMin() > 0) {
System.arraycopy(splited[s], restPositions[s],
royalHands[p], positions[p], newRanges[p][s]
.getMin());
restPositions[s] += newRanges[p][s].getMin();
positions[p] += newRanges[p][s].getMin();
newRanges[p][s].reduce(newRanges[p][s].getMin());
}
}
}
int playersIndex = randomForplayers.length;
int suitesIndex = randomForSuites.length;
Random rand = new Random(System.currentTimeMillis());
while (playersIndex > 0 || suitesIndex > 0) {
int playerInd = rand.nextInt(playersIndex);
int player = randomForplayers[playerInd];
int suiteInd = rand.nextInt(suitesIndex);
int suite = randomForSuites[suiteInd];
if (newRanges[player][suite].getMax() > 0) {
royalHands[player][positions[player]] = splited[suite][restPositions[suite]];
restPositions[suite]++;
positions[player]++;
newRanges[player][suite].reduce(1);
if (positions[player] == 13) // player is full
{
int temp = randomForplayers[playerInd];
playersIndex--;
randomForplayers[playerInd] = randomForplayers[playersIndex];
randomForplayers[playersIndex] = temp;
}
if (restPositions[suite] == splited[suite].length) // Suite is
// full
{
int temp = randomForSuites[suiteInd];
suitesIndex--;
randomForSuites[suiteInd] = randomForSuites[suitesIndex];
randomForSuites[suitesIndex] = temp;
}
}
}
this.answers[amount] = this.putInMatrix(royalHands);
// this.printMatrix(this.answers[amount]);
return amount + 1;
}
@Override
public void extraConfig(String configLine) {
// TODO Auto-generated method stub
}
}