package main;
import de.uniba.wiai.lspi.chord.com.Node;
import de.uniba.wiai.lspi.chord.data.ID;
import java.math.BigInteger;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GameLogic {
// constants for config
private static final int S = 10; // number of ships
static final int I = 100; // number of mySectors
private static final int WAITING_TIME_CHORD_JOIN = 5000;
private static final int MIDDLE = 2;
private static final ID BIGGEST_ID = new ID(BigInteger.valueOf(2).pow(160).subtract(BigInteger.ONE).toByteArray());
// package private
ID myID;
ID[] mySectors = new ID[I];
final boolean[] ships = new boolean[I];
private static Chord chord = null;
GameLogic getChordClient() {
return this;
}
/**
* initialises the game
*
* @param args
* @throws InterruptedException might be called by Thread.sleep
*/
public static void main(String[] args) throws InterruptedException {
GameLogic cc = new GameLogic();
chord = new Chord(cc);
chord.init();
// sleep prevents calling "loadPropertyFile()" at the same time.
Thread.sleep(100);
cc.startGame();
}
/**
* starts up the actual game
*/
private void startGame() {
Scanner scanner = new Scanner(System.in);
// start the game after s was typed in
String input;
do {
System.out.print("type \"s\" to begin: ");
input = scanner.next();
} while (!input.equals("s"));
scanner.close();
// waits 5 sec to make sure others have joined chord
try {
Thread.sleep(WAITING_TIME_CHORD_JOIN);
} catch (InterruptedException ex) {
Logger.getLogger(GameLogic.class.getName()).log(Level.SEVERE, null, ex);
}
myID = chord.getChordImpl().getID();
mySectors = calculateSectors(chord.getChordImpl().getPredecessorID(), myID);
setShips();
// adds us to the unicePlayer sectors
chord.getMyNotifyCallback().uniquePlayers.add(myID);
// add the fingertables to
Set<Node> fingerSet = new HashSet<>(chord.getChordImpl().getFingerTable());
for (Node n : fingerSet) {
chord.getMyNotifyCallback().uniquePlayers.add(n.getNodeID());
}
Collections.sort(chord.getMyNotifyCallback().uniquePlayers);
// we start the game if we have the BIGGESTID
if (chord.getChordImpl().getPredecessorID().compareTo(chord.getChordImpl().getID()) > 0) {
System.out.println("I start!");
chord.getMyNotifyCallback().calculateUniquePlayersSectors();
chord.getMyNotifyCallback().calculateShootableSectors();
shoot();
}
}
/**
* Calculates the mySectors between the predecessor and our id and splits
* this into I Sectors. Also handles the case if the predecessor has a
* bigger id than we do.
*
* @param from the first id, thinking circle clockwise
* @param to the second id,
* @return array of BigInteger
*/
ID[] calculateSectors(ID from, ID to) {
ID[] result = new ID[I];
ID distance;
// predecessorID might be bigger than our ID, due to Chord circle
if (from.compareTo(to) < 0) {
distance = to.subtract(from);
} else {
distance = BIGGEST_ID.subtract(from).add(to);
}
ID step = distance.divide(I);
for (int i = 0; i < I; i++) {
// (from + 1 + (i * step)) % biggestID
result[i] = from.add(1).add(step.multiply(i)).mod(BIGGEST_ID);
// System.out.println("sector " + (i + 1) + ": " + result[i]);
}
return result;
}
/**
* Places S ships in I mySectors
*/
private void setShips() {
Random rnd = new Random();
int random;
for (int i = 0; i < S; i++) {
do {
random = rnd.nextInt(I);
} while (ships[random] == true);
ships[random] = true;
}
}
/**
* handles the shooting of our enemies
*/
void shoot() {
System.out.println();
Random rnd = new Random();
List<ID> shootableSectors = chord.getMyNotifyCallback().shootableSectors;
int sectorNumber = rnd.nextInt(shootableSectors.size());
ID target = shootableSectors.get(sectorNumber);
// doesn't work
// ID targetNext = calculateNextSector(target);
// ID distance;
//
// if (target.compareTo(targetNext) < 0) {
// distance = targetNext.subtract(target).divide(MIDDLE);
// } else {
// distance = BIGGEST_ID.subtract(target).add(targetNext).divide(MIDDLE);
// }
// ID middleOfSector = target.add(distance).mod(BIGGEST_ID);
ID middleOfSector = target.add(10).mod(BIGGEST_ID);
System.out.println("shooting at: " + target.toBigInteger());
RetrieveThread retrieve = new RetrieveThread(chord.getChordImpl(), middleOfSector);
retrieve.start();
}
/**
* calculates the next sector for an ID. This is needed to be able to shoot in the middle of a
* sector.
*
* @param sector
* @return
*/
ID calculateNextSector(ID sector) {
List<ID> uniquePlayers = chord.getMyNotifyCallback().uniquePlayers;
for (int i = 0; i < uniquePlayers.size(); i++) {
ID[] uniquePlayersSectors = chord.getMyNotifyCallback().uniquePlayersSectors.get(uniquePlayers.get(i));
int sectorNumber = isInSector(sector, uniquePlayersSectors);
System.out.println("Sector nr: " + sectorNumber);
if (sectorNumber != -1) {
if (sectorNumber < uniquePlayersSectors.length - 1) {
// next sector of the same player
return uniquePlayersSectors[i + 1];
} else if (i < uniquePlayers.size() - 1) {
// first sector of the next player
return uniquePlayers.get(i + 1);
} else {
// return the first sector of the first player
return uniquePlayers.get(0);
}
}
}
// should not happen
System.out.println("ERROR: next Sector is null");
return null;
}
/**
* Checks if the target is inside the Sector boundaries.
*
* @param target target ID
* @param sector Array of IDs
* @return
*/
int isInSector(ID target, ID[] sector) {
if (!target.isInInterval(sector[0], sector[sector.length - 1])) {
return -1;
}
for (int i = 0; i < sector.length - 1; i++) {
if (target.compareTo(sector[i]) >= 0 && target.compareTo(sector[i + 1]) < 0) {
return i;
}
}
if (target.compareTo(sector[sector.length - 1]) >= 0 && target.compareTo(findNextPlayer(target)) < 0) {
return sector.length - 1;
}
return -1;
}
/**
* returns the ID of the next player
*
* @param target
* @return
*/
public ID findNextPlayer(ID target) {
List<ID> uniquePlayers = chord.getMyNotifyCallback().uniquePlayers;
Collections.sort(uniquePlayers);
for (int i = 0; i < uniquePlayers.size() - 1; i++) {
if (target.isInInterval(uniquePlayers.get(i), uniquePlayers.get(i + 1))) {
return uniquePlayers.get(i + 1);
}
}
return uniquePlayers.get(0);
}
}