If thread-safe, any chances to make more concurrent - java

The class AnagramGameDefault simulates an anagram game.
The submitScore() should recalculate the positions, the one with highest score has position 1, there can be several players on the same position.
The getLeaderBoard() fetches the entry for a user plus two above and two below.
The concerns I have :
I tested the code for multiple threads and I guess it's working but I would like to know if there are some race conditions or failure in sharing state in the code
I have used quite a stringent mutually exclusive locking by using 'synchronized'. I don't think this can be avoided as submitScore() and getLeaderBoard() rely heavily on sorting and correct positions of score but is there a possibility ? I read a bit about ReentrantLock but it's more suitable where there are multiple reads and lesser writes, in this case, even the reads need calculations.
public enum AnagramGameDefault{
INSTANCE;
private Map<String, Entry> leaderBoardUserEntryMap;
{
leaderBoardUserEntryMap = new LinkedHashMap<>();
}
public int calculateScore(String word, String anagram) {
if (word == null || anagram == null) {
throw new NullPointerException("Both, word and anagram, must be non-null");
}
char[] wordArray = word.trim().toLowerCase().toCharArray();
char[] anagramArray = anagram.trim().toLowerCase().toCharArray();
int[] alphabetCountArray = new int[26];
int reference = 'a';
for (int i = 0; i < wordArray.length; i++) {
if (!Character.isWhitespace(wordArray[i])) {
alphabetCountArray[wordArray[i] - reference]++;
}
}
for (int i = 0; i < anagramArray.length; i++) {
if (!Character.isWhitespace(anagramArray[i])) {
alphabetCountArray[anagramArray[i] - reference]--;
}
}
for (int i = 0; i < 26; i++)
if (alphabetCountArray[i] != 0)
return 0;
return word.length();
}
public void submitScore(String uid, int score) {
Entry newEntry = new Entry(uid, score);
sortLeaderBoard(newEntry);
}
private void sortLeaderBoard(Entry newEntry) {
synchronized (leaderBoardUserEntryMap) {
leaderBoardUserEntryMap.put(newEntry.getUid(), newEntry);
// System.out.println("Sorting for " + newEntry);
List<Map.Entry<String, Entry>> list = leaderBoardUserEntryMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Collections.reverseOrder())).collect(Collectors.toList());
leaderBoardUserEntryMap.clear();
int position = 0;
int previousPosition = 0;
int currentPosition = 0;
for (Map.Entry<String, Entry> entry : list) {
currentPosition = entry.getValue().getScore();
if (!(currentPosition == previousPosition))
position++;
entry.getValue().setPosition(position);
leaderBoardUserEntryMap.put(entry.getKey(), entry.getValue());
previousPosition = currentPosition;
}
}
}
public List<Entry> getLeaderBoard(String uid) {
final int maxEntriesAroundAnEntry = 2;
if (!leaderBoardUserEntryMap.containsKey(uid))
return Collections.emptyList();
Entry userEntry = null;
final List<Entry> leaderBoard = new ArrayList<>();
List<Entry> lowerEntries = null;
List<Entry> higherEntries = null;
synchronized (leaderBoardUserEntryMap) {
printBoard();
userEntry = leaderBoardUserEntryMap.get(uid);
int userPosition = userEntry.getPosition();
int upperPosition = userPosition - maxEntriesAroundAnEntry;
int lowerPosition = userPosition + maxEntriesAroundAnEntry;
// Higher entries
higherEntries = leaderBoardUserEntryMap.values().stream()
.filter(entry -> (entry.getPosition() < userPosition && entry.getPosition() >= upperPosition))
.map(entry -> new Entry(entry.getUid(), entry.getScore(), entry.getPosition()))
.collect(Collectors.toList());
// Lower entries
lowerEntries = leaderBoardUserEntryMap.values().stream()
.filter(entry -> (entry.getPosition() > userPosition && entry.getPosition() <= lowerPosition))
.map(entry -> new Entry(entry.getUid(), entry.getScore(), entry.getPosition()))
.collect(Collectors.toList());
userEntry = new Entry(userEntry.getUid(), userEntry.getScore(), userEntry.getPosition());
// }
if (higherEntries != null && !higherEntries.isEmpty()) {
if (higherEntries.size() >= maxEntriesAroundAnEntry) {
higherEntries = higherEntries.subList(higherEntries.size() - maxEntriesAroundAnEntry,
higherEntries.size());
}
leaderBoard.addAll(higherEntries);
}
leaderBoard.add(userEntry);
if (lowerEntries != null && !lowerEntries.isEmpty()) {
if (lowerEntries.size() >= maxEntriesAroundAnEntry) {
lowerEntries = lowerEntries.subList(0, maxEntriesAroundAnEntry);
}
leaderBoard.addAll(lowerEntries);
}
}
return leaderBoard;
}
public void printBoard() {
System.out.println("---------Start : Current leader board---------");
leaderBoardUserEntryMap.forEach((key, value) -> {
System.out.println("BOARD ENTRY : " + key + " : " + value);
});
System.out.println("---------End : Current leader board---------");
}
}
The Entry POJO :
public class Entry implements Comparable<Entry> {
private String uid;
private int score;
private int position;
public Entry(String uid, int score) {
this.uid = uid;
this.score = score;
}
public Entry(String uid, int score, int position) {
this.uid = uid;
this.score = score;
this.position = position;
}
public Entry() {
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + score;
result = prime * result + ((uid == null) ? 0 : uid.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entry other = (Entry) obj;
if (score != other.score)
return false;
if (uid == null) {
if (other.uid != null)
return false;
} else if (!uid.equals(other.uid))
return false;
return true;
}
#Override
public String toString() {
return "Entry [uid=" + uid + ", score=" + score + ", position=" + position + "]";
}
#Override
public int compareTo(Entry o) {
// TODO Auto-generated method stub
if (o == null)
return -1;
return Integer.compare(score, o.getScore());
}
}
The tester class :
public class AnagramGameDefaultDemo {
public static void main(String[] args) {
if (args == null || args.length < 1) {
System.out.println("Enter testing approach - 1 for single threaded, 2 for multi-threaded");
return;
}
switch (args[0]) {
case "1": {
new AnagramGameDefaultDemo().testSingleThreaded();
break;
}
case "2": {
new AnagramGameDefaultDemo().testMultithreaded();
break;
}
default: {
System.out.println("Enter proper option(1 or 2)");
break;
}
}
}
private void testMultithreaded() {
Map<String, String> stringAnagramMap = new HashMap<>();
CountDownLatch countDownLatchOne = new CountDownLatch(1);
stringAnagramMap.put("raw", "war");
stringAnagramMap.put("raw", "wars");
AnagramGamePlayer jake = new AnagramGamePlayer("jake", stringAnagramMap, countDownLatchOne);
new Thread(jake, "jake").start();
stringAnagramMap.clear();
stringAnagramMap.put("tool", "loot");
AnagramGamePlayer ace = new AnagramGamePlayer("ace", stringAnagramMap, countDownLatchOne);
new Thread(ace, "ace").start();
stringAnagramMap.clear();
stringAnagramMap.put("William Shakespeare", "I am a weakish speller");
AnagramGamePlayer max = new AnagramGamePlayer("max", stringAnagramMap, countDownLatchOne);
new Thread(max, "max").start();
stringAnagramMap.clear();
stringAnagramMap.put("School master", "The classroom");
AnagramGamePlayer tBone = new AnagramGamePlayer("tBone", stringAnagramMap, countDownLatchOne);
new Thread(tBone, "tBone").start();
stringAnagramMap.clear();
countDownLatchOne.countDown();
CountDownLatch countDownLatchTwo = new CountDownLatch(1);
stringAnagramMap.put("Punishments", "Nine Thumps");
AnagramGamePlayer razor = new AnagramGamePlayer("razor", stringAnagramMap, countDownLatchTwo);
new Thread(razor, "razor").start();
stringAnagramMap.clear();
stringAnagramMap.put("Dormitory", "Dirty Room");
AnagramGamePlayer chip = new AnagramGamePlayer("chip", stringAnagramMap, countDownLatchTwo);
new Thread(chip, "chip").start();
stringAnagramMap.clear();
countDownLatchTwo.countDown();
CountDownLatch countDownLatchThree = new CountDownLatch(1);
stringAnagramMap.put("Mother in law", "Hitler woman");
AnagramGamePlayer dale = new AnagramGamePlayer("dale", stringAnagramMap, countDownLatchThree);
new Thread(dale, "dale").start();
countDownLatchThree.countDown();
stringAnagramMap.clear();
}
private final class AnagramGamePlayer implements Runnable {
private Map<String, String> stringAnagramMap = new HashMap<>();
private String uid;
private CountDownLatch countDownLatch;
public AnagramGamePlayer(String uid, Map<String, String> stringAnagramMap, CountDownLatch countDownLatch) {
this.stringAnagramMap.putAll(stringAnagramMap);
this.uid = uid;
this.countDownLatch = countDownLatch;
}
#Override
public void run() {
AnagramGameDefault anagramGameDefault = AnagramGameDefault.INSTANCE;
try {
countDownLatch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Player " + uid + " started playing with " + stringAnagramMap);
stringAnagramMap.entrySet().forEach(entry -> {
anagramGameDefault.submitScore(uid,
anagramGameDefault.calculateScore(entry.getKey(), entry.getValue()));
printLeaderBoard(uid, anagramGameDefault.getLeaderBoard(uid));
});
System.out.println("Player " + uid + " completed playing");
}
}
private void testSingleThreaded() {
AnagramGameDefault anagramGameDefault = AnagramGameDefault.INSTANCE;
anagramGameDefault.submitScore("Jake", 3);
anagramGameDefault.submitScore("Ace", 7);
anagramGameDefault.submitScore("Max", 1);
anagramGameDefault.submitScore("T-Bone", 14);
anagramGameDefault.submitScore("Razor", 6);
anagramGameDefault.submitScore("Razor", 7);
anagramGameDefault.submitScore("He-Man", 4);
anagramGameDefault.submitScore("Men-at-Arms", 8);
anagramGameDefault.submitScore("BattleCat", 3);
anagramGameDefault.submitScore("Jake", 2);
anagramGameDefault.submitScore("BattleCat", 3);
anagramGameDefault.printBoard();
anagramGameDefault.submitScore("Men-at-Arms", 21);
anagramGameDefault.submitScore("Orko", 20);
anagramGameDefault.submitScore("Jake", 4);
anagramGameDefault.printBoard();
System.out.println();
printLeaderBoard("user5", anagramGameDefault.getLeaderBoard("user5"));
System.out.println();
printLeaderBoard("user4", anagramGameDefault.getLeaderBoard("user4"));
System.out.println();
printLeaderBoard("user15", anagramGameDefault.getLeaderBoard("user15"));
System.out.println();
List<Entry> entries = anagramGameDefault.getLeaderBoard("user1");
printLeaderBoard("user1", entries);
System.out.println("Changing state of the received entries");
entries.forEach(entry -> {
entry.setPosition(1);
entry.setScore(0);
});
anagramGameDefault.printBoard();
printLeaderBoard("user1", anagramGameDefault.getLeaderBoard("user1"));
}
private static void printLeaderBoard(String user, List<Entry> leaderBoard) {
if (user == null || leaderBoard.isEmpty()) {
System.out.println("Either user " + user + " doesn't exist or leader board is empty " + leaderBoard);
}
System.out.println("**********Printing leader board for " + user);
leaderBoard.forEach(System.out::println);
System.out.println("**********");
}
}

It seems the only shared state you have in the whole thing is leaderBoardUserEntryMap. You synchronize on it when updating in sortLeaderBoard. In getLeaderBoard for some reason you don't yet synchronize on it when checking if (!leaderBoardUserEntryMap.containsKey(uid)). That's minor, but you should do it as well. Later, you synchronize on it when constructing the leader board.
From this point of view your synchronization seems adequate.
What I find a bit problematic is that your Entry is mutable and stores position. This makes your update operation more problematic. You have to re-sort and re-set positions on every update. And you're locking all other update or even read operations. I'd avoid mutable objects in multithreaded code.
I'd use a SortedSet instead and let the implementation handle sorting. To find out the position of the element you'd just do set.headSet(element).size() + 1. So no need to store position at all.
I initially wanted to suggest using concurrent collection implementations like ConcurrentHashSet which would allow "full concurrency of retrievals and adjustable expected concurrency for updates". Basically, retrievals could be non-blocking, only updates were.
However, this won't help much as your "retrieval" logic (creating the leader board around target entry) is not so simple and involves several reads. So I think it's better not use concurrent collections but instead actually synchronize on the collection and make updates and retrievals as compact as possible. If you give up on the idea of having position in Entry then update is a trivial add. Then you'll only need to read entries around the entry as fast as possible (within the synchronized block). This should be quite fast with tree sets.

Related

How can I create a Java algorithm that takes any number of players and pair them up any number of times uniquely?

I am looking to create an algorithm in Java that can take any number of "players" and group them up a specified number of times each. However, two pairs cannot be the same. So, if we are supplied 9 players (dubbed 0, 1, 2, etc) by the user and each player should be paired 3 times, that means that this algorithm needs to be able to generate a list of pairs where each player is paired 3 times.
So 4 players being paired two times could be: {{0, 1}, {2, 3}, {0, 2}, {1, 3}}.
Obviously, it can be impossible in some scenarios (like 4 players being uniquely paired 20 times), but I have input restrictions to combat that.
{0, 1} and {1, 0} are equal pairs. The order of the numbers does not matter, they are not unique.
The preferable way for input is just given two numbers (number of players, number of pairs per players) and the preferable way for the output to be given is in a two dimensional array of integers (each player being dubbed by an integer), like I gave an example of.
Does anyone have any ideas on how to do this? Pseudo-code, actual code, any ideas are welcome. Thanks!
I think your question is valid and interesting to solve in code.
This is why I coded that whole thing.
There's one downside to my solution, or rather: the problem.
In certain situations, some players can have many matches between them, while others have little. So in the end, some players might not get matched properly.
In this case, you'd need a mathematical trick, or a backtracking algorithm, that steps back on parts of the solution and tries (brute-forces) other combinations. My algorithm has neither, but it indicates Exceptions and validity.
Also check the comments in the code.
package snippet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
public class BadPairingStuff6 {
static class Player {
public final int mID;
private final BadPairingStuff6 mParentLogic;
public int mMatches;
public Player(final int pID, final BadPairingStuff6 pBadPairingStuff5) {
mID = pID;
mParentLogic = pBadPairingStuff5;
}
#Override public int hashCode() {
return mID;
}
#Override public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final Player other = (Player) obj;
if (mID != other.mID) return false;
return true;
}
#Override public String toString() {
return "Player[" + mID + "]";
}
public void incMatches() {
++mMatches;
}
public int getMatches() {
return mMatches;
}
public boolean canPlayAnotherMatch() {
return getMatches() < mParentLogic.mPairingsAllowed;
}
}
static class Pairing {
public final Player mPlayer1;
public final Player mPlayer2;
public Pairing(final Player pPlayer1, final Player pPlayer2) {
if (pPlayer1.mID < pPlayer2.mID) {
mPlayer1 = pPlayer1;
mPlayer2 = pPlayer2;
} else {
mPlayer1 = pPlayer2;
mPlayer2 = pPlayer1;
}
}
#Override public String toString() {
return mPlayer1 + "+" + mPlayer2;
}
#Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + mPlayer1.mID;
result = prime * result + mPlayer2.mID;
return result;
}
#Override public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final Pairing other = (Pairing) obj;
if (mPlayer1 != other.mPlayer1) return false;
if (mPlayer2 != other.mPlayer2) return false;
return true;
}
}
static class PartnerMap {
private final HashMap<Player, ArrayList<Player>> mMap = new HashMap<>();
public PartnerMap(final Iterable<Player> pPlayers) {
for (final Player player : pPlayers) {
final ArrayList<Player> partners = new ArrayList<>();
for (final Player partner : pPlayers) {
if (player != partner) partners.add(partner);
}
mMap.put(player, partners);
}
}
public Player getPartner(final Player pPlayer) {
final ArrayList<Player> possiblePartners = mMap.get(pPlayer);
if (possiblePartners.size() < 1) throw new NotEnoughPartnersException(pPlayer);
return possiblePartners.get((int) (Math.random() * possiblePartners.size()));
}
public void removePartners(final Player pPlayer, final Player pPartner) {
System.out.println("\t\tBadPairingStuff5.PartnerMap.removePartners(" + pPlayer + ", " + pPartner + ")");
System.out.println("\t\t\tRemoving for " + pPlayer);
System.out.println("\t\t\t\tBEFORE: " + toString(mMap.get(pPlayer)));
mMap.get(pPlayer).remove(pPartner);
System.out.println("\t\t\t\tAFTER: " + toString(mMap.get(pPlayer)));
System.out.println("\t\t\tRemoving for " + pPartner);
System.out.println("\t\t\t\tBEFORE: " + toString(mMap.get(pPartner)));
mMap.get(pPartner).remove(pPlayer);
System.out.println("\t\t\t\tAFTER: " + toString(mMap.get(pPartner)));
}
static String toString(final Iterable<Player> pPlayers) {
final StringBuilder sb = new StringBuilder();
sb.append("[");
for (final Player player : pPlayers) {
sb.append(player.mID + " ");
}
sb.append("]");
return sb.toString();
}
public void removePlayerCompletely(final Player pPlayer) {
System.out.println("\t\t\tBadPairingStuff5.PartnerMap.removePlayerCompletely(" + pPlayer + ")");
for (final ArrayList<Player> partnerMap : mMap.values()) {
partnerMap.remove(pPlayer);
}
mMap.get(pPlayer).clear();
}
public void print() {
System.out.println("Partner Map");
for (final Entry<Player, ArrayList<Player>> e : mMap.entrySet()) {
System.out.println("\t" + e.getKey());
for (final Player v : e.getValue()) {
System.out.println("\t\t" + v);
}
}
}
}
public static class NotEnoughPartnersException extends IllegalStateException {
private static final long serialVersionUID = -7249807214069096317L;
private final Player mPlayer;
public NotEnoughPartnersException(final Player pPlayer) {
super("Not enough partners available for " + pPlayer + "!");
mPlayer = pPlayer;
}
public Player getPlayer() {
return mPlayer;
}
}
static class PairingResult {
public final ArrayList<Pairing> mCreatedPairings;
public final ArrayList<Exception> mExceptions;
public PairingResult(final ArrayList<Pairing> pCreatedPairings, final ArrayList<Exception> pExceptions) {
mCreatedPairings = pCreatedPairings;
mExceptions = pExceptions;
}
public boolean isValid() {
return mExceptions.size() < 1;
}
}
public static void main(final String[] args) {
final int players = 10;
final int pairingsAllowed = 4;
final PairingResult result = new BadPairingStuff6(players, pairingsAllowed).createPairings();
System.out.println("All pairings:");
final HashMap<Long, Long> playCounter = new HashMap<>();
for (final Pairing p : result.mCreatedPairings) {
System.out.println("\t" + p);
{
final Long oldCount = playCounter.get(Long.valueOf(p.mPlayer1.mID));
playCounter.put(Long.valueOf(p.mPlayer1.mID), Long.valueOf(oldCount == null ? 1 : (oldCount.longValue() + 1)));
}
{
final Long oldCount = playCounter.get(Long.valueOf(p.mPlayer2.mID));
playCounter.put(Long.valueOf(p.mPlayer2.mID), Long.valueOf(oldCount == null ? 1 : (oldCount.longValue() + 1)));
}
}
System.out.println("Pairings per Player: ");
for (final Entry<Long, Long> e : playCounter.entrySet()) {
System.out.println("\t" + e.getKey() + " -> " + e.getValue());
}
System.out.println("Exceptions:");
System.out.flush();
sleep();
for (final Exception e : result.mExceptions) {
e.printStackTrace();
}
System.err.flush();
sleep();
System.out.println("Valid result: " + result.isValid());
System.out.println("All done.");
}
/*
* OBJECT
*/
final int mPairingsAllowed;
private final ArrayList<Player> mPlayers = new ArrayList<>();
public BadPairingStuff6(final int pPlayersCount, final int pPairingsAllowed) {
mPairingsAllowed = pPairingsAllowed;
// create players
for (int i = 0; i < pPlayersCount; i++) {
mPlayers.add(new Player(i, this));
}
}
public PairingResult createPairings() {
final ArrayList<Pairing> createdPairings = new ArrayList<>();
final ArrayList<Exception> exceptions = new ArrayList<>();
final PartnerMap possiblePairings = new PartnerMap(mPlayers);
final HashSet<Player> playersToHandle = new HashSet<>(mPlayers);
while (!playersToHandle.isEmpty()) {
final ArrayList<Player> removePlayersPerRound = new ArrayList<>();
for (final Player player : playersToHandle) {
if (!player.canPlayAnotherMatch()) {
possiblePairings.removePlayerCompletely(player);
removePlayersPerRound.add(player);
continue;
}
try {
System.out.println("Creating matches for " + player + " (" + player.getMatches() + ")");
final Player partner = possiblePairings.getPartner(player);
if (!partner.canPlayAnotherMatch()) continue;
final Pairing newPairing = new Pairing(player, partner);
if (createdPairings.contains(newPairing)) System.out.println("WARNING! Double hit for " + newPairing);
createdPairings.add(newPairing);
possiblePairings.removePartners(player, partner);
player.incMatches();
partner.incMatches();
System.out.println("\tMatched with " + partner);
if (!partner.canPlayAnotherMatch()) {
possiblePairings.removePlayerCompletely(partner);
removePlayersPerRound.add(partner);
}
} catch (final NotEnoughPartnersException e) {
// the flushes and sleeps are only a cheap shot to keep System.out and System.err outputs in somewhat chronological order.
// this is for proof/debug/answer only, and should NOT be used in production!
System.out.flush();
sleep();
e.printStackTrace();
// throw e; // if you want to abort early
removePlayersPerRound.add(e.getPlayer());
exceptions.add(e);
System.err.flush();
sleep();
}
}
playersToHandle.removeAll(removePlayersPerRound);
}
possiblePairings.print();
return new PairingResult(createdPairings, exceptions);
}
// the sleeps are only a cheap shot to keep System.out and System.err outputs in somewhat chronological order.
// this is for proof/answer only, and should NOT be used in production
static void sleep(final long pMilliSec) {
try {
Thread.sleep(pMilliSec);
} catch (final InterruptedException e1) { /* */ }
}
static void sleep() {
sleep(100);
}
}
I use lots of inner static classes. This is for demonstration purposes only.
If you want to actually use those classes, put each of them into its separate file (remove the "static class", and add a "public class" where it's missing).
Also note that this complexity is needed for random assignments. If the algorithm could always churn out the same combinations, it would be about 1/10th of the code.

basic planet wars ai issues

I am programming a very basic bot for planet wars in java and I cant seem to find the errors in my code. I am receiving a few different error messages but the main issue for me is the error: class, interface, or enum expected. Ive checked my brackets about a thousand times. Any help would be appreciated. Here's my bot code:
import java.util.List;
import java.util.Random;
import shared.Planet;
import shared.PlanetWars;
public class MyNewBot {
public static void doTurn(PlanetWars pw) {
// (1) If we currently have a fleet in flight, then do nothing until
// it arrives.
if (pw.myFleets().size() >= 10) {
return;
}
// (2) Pick one of my planets based on the number of ships
Planet source = null;
int largestForce = 0;
for (Planet p : pw.myPlanets()){
int force = pw.numShips();
if( force > largestForce){
largestForce = force;
source = p;
}
}
// (3) Pick a target planet at random.
Planet dest = null;
int highestGrowthRate = 0;
int shortestDistance = 9999;
for (Planet p = pw.notMyPlanets()){
int growthRate = pw.growthRate();
if( growthRate > highestGrowthRate){
highestGrowthRate = growthRate;
dest = p;
}else if (growthRate == highestGrowthRate){
int distance = pw.distance(source,p);
if (distance < shortestDistance){
shortestDistance = distance;
dest = p;
}
}
}
// (4) Send half the ships from source to destination.
if (source != null && dest != null) {
int numShips = source.numShips() / 2;
pw.issueOrder(source, dest, numShips);
}
}
// Ignore the main method unless you know what you're doing.
// Refer to the doTurn function to code your bot.
public static void main(String[] args) {
String line = "";
String message = "";
int c;
try {
while ((c = System.in.read()) >= 0) {
switch (c) {
case '\n':
if (line.equals("go")) {
PlanetWars pw = new PlanetWars(message);
doTurn(pw);
pw.finishTurn();
message = "";
} else {
message += line + "\n";
}
line = "";
break;
default:
line += (char) c;
break;
}
}
} catch (Exception e) {
// Owned.
}
}
}
and the supporting class files:
package shared;
public class Planet implements Cloneable {
private int planetID;
private int owner;
private int numShips;
private int growthRate;
private double x, y;
public Planet(int planetID, int owner, int numShips, int growthRate,
double x, double y) {
this.planetID = planetID;
this.owner = owner;
this.numShips = numShips;
this.growthRate = growthRate;
this.x = x;
this.y = y;
}
public int planetID() {
return planetID;
}
public int owner() {
return owner;
}
public int numShips() {
return numShips;
}
public int growthRate() {
return growthRate;
}
public double x() {
return x;
}
public double y() {
return y;
}
public void owner(int newOwner) {
this.owner = newOwner;
}
public void numShips(int newNumShips) {
this.numShips = newNumShips;
}
public void addShips(int amount) {
numShips += amount;
}
public void removeShips(int amount) {
numShips -= amount;
}
private Planet(Planet _p) {
planetID = _p.planetID;
owner = _p.owner;
numShips = _p.numShips;
growthRate = _p.growthRate;
x = _p.x;
y = _p.y;
}
public Object clone() {
return new Planet(this);
}
}
package shared;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class PlanetWars {
// Constructs a PlanetWars object instance, given a string containing a
// description of a game state.
public PlanetWars(String gameStateString) {
planets = new ArrayList<Planet>();
fleets = new ArrayList<Fleet>();
parseGameState(gameStateString);
}
// Returns the number of planets. Planets are numbered starting with 0.
public int numPlanets() {
return planets.size();
}
// Returns the planet with the given planet_id. There are NumPlanets()
// planets. They are numbered starting at 0.
public Planet getPlanet(int planetID) {
return planets.get(planetID);
}
// Returns the number of fleets.
public int numFleets() {
return fleets.size();
}
// Returns the fleet with the given fleet_id. Fleets are numbered starting
// with 0. There are NumFleets() fleets. fleet_id's are not consistent from
// one turn to the next.
public Fleet getFleet(int fleetID) {
return fleets.get(fleetID);
}
// Returns a list of all the planets.
public List<Planet> planets() {
return planets;
}
// Return a list of all the planets owned by the current player. By
// convention, the current player is always player number 1.
public List<Planet> myPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() == 1) {
r.add(p);
}
}
return r;
}
// Return a list of all neutral planets.
public List<Planet> neutralPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() == 0) {
r.add(p);
}
}
return r;
}
// Return a list of all the planets owned by rival players. This excludes
// planets owned by the current player, as well as neutral planets.
public List<Planet> enemyPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() >= 2) {
r.add(p);
}
}
return r;
}
// Return a list of all the planets that are not owned by the current
// player. This includes all enemy planets and neutral planets.
public List<Planet> notMyPlanets() {
List<Planet> r = new ArrayList<Planet>();
for (Planet p : planets) {
if (p.owner() != 1) {
r.add(p);
}
}
return r;
}
// Return a list of all the fleets.
public List<Fleet> fleets() {
List<Fleet> r = new ArrayList<Fleet>();
for (Fleet f : fleets) {
r.add(f);
}
return r;
}
// Return a list of all the fleets owned by the current player.
public List<Fleet> myFleets() {
List<Fleet> r = new ArrayList<Fleet>();
for (Fleet f : fleets) {
if (f.owner() == 1) {
r.add(f);
}
}
return r;
}
// Return a list of all the fleets owned by enemy players.
public List<Fleet> enemyFleets() {
List<Fleet> r = new ArrayList<Fleet>();
for (Fleet f : fleets) {
if (f.owner() != 1) {
r.add(f);
}
}
return r;
}
// Returns the distance between two planets, rounded up to the next highest
// integer. This is the number of discrete time steps it takes to get
// between the two planets.
public int distance(int sourcePlanet, int destinationPlanet) {
Planet source = planets.get(sourcePlanet);
Planet destination = planets.get(destinationPlanet);
double dx = source.x() - destination.x();
double dy = source.y() - destination.y();
return (int) Math.ceil(Math.sqrt(dx * dx + dy * dy));
}
// Returns the distance between two planets, rounded up to the next highest
// integer. This is the number of discrete time steps it takes to get
// between the two planets.
public int distance(Planet source, Planet destination) {
double dx = source.x() - destination.x();
double dy = source.y() - destination.y();
return (int) Math.ceil(Math.sqrt(dx * dx + dy * dy));
}
// Sends an order to the game engine. An order is composed of a source
// planet number, a destination planet number, and a number of ships. A
// few things to keep in mind:
// * you can issue many orders per turn if you like.
// * the planets are numbered starting at zero, not one.
// * you must own the source planet. If you break this rule, the game
// engine kicks your bot out of the game instantly.
// * you can't move more ships than are currently on the source planet.
// * the ships will take a few turns to reach their destination. Travel
// is not instant. See the Distance() function for more info.
public void issueOrder(int sourcePlanet, int destinationPlanet, int
numShips) {
System.out.println("" + sourcePlanet + " " + destinationPlanet + " "
+ numShips);
System.out.flush();
}
// Sends an order to the game engine. An order is composed of a source
// planet number, a destination planet number, and a number of ships. A
// few things to keep in mind:
// * you can issue many orders per turn if you like.
// * the planets are numbered starting at zero, not one.
// * you must own the source planet. If you break this rule, the game
// engine kicks your bot out of the game instantly.
// * you can't move more ships than are currently on the source planet.
// * the ships will take a few turns to reach their destination. Travel
// is not instant. See the Distance() function for more info.
public void issueOrder(Planet source, Planet dest, int numShips) {
System.out.println("" + source.planetID() + " " + dest.planetID() + " "
+ numShips);
System.out.flush();
}
// Sends the game engine a message to let it know that we're done sending
// orders. This signifies the end of our turn.
public void finishTurn() {
System.out.println("go");
System.out.flush();
}
// Returns true if the named player owns at least one planet or fleet.
// Otherwise, the player is deemed to be dead and false is returned.
public boolean isAlive(int playerID) {
for (Planet p : planets) {
if (p.owner() == playerID) {
return true;
}
}
for (Fleet f : fleets) {
if (f.owner() == playerID) {
return true;
}
}
return false;
}
// If the game is not yet over (ie: at least two players have planets or
// fleets remaining), returns -1. If the game is over (ie: only one player
// is left) then that player's number is returned. If there are no
// remaining players, then the game is a draw and 0 is returned.
public int winner() {
Set<Integer> remainingPlayers = new TreeSet<Integer>();
for (Planet p : planets) {
remainingPlayers.add(p.owner());
}
for (Fleet f : fleets) {
remainingPlayers.add(f.owner());
}
switch (remainingPlayers.size()) {
case 0:
return 0;
case 1:
return ((Integer) remainingPlayers.toArray()[0]).intValue();
default:
return -1;
}
}
// Returns the number of ships that the current player has, either located
// on planets or in flight.
public int numShips(int playerID) {
int numShips = 0;
for (Planet p : planets) {
if (p.owner() == playerID) {
numShips += p.numShips();
}
}
for (Fleet f : fleets) {
if (f.owner() == playerID) {
numShips += f.numShips();
}
}
return numShips;
}
// Returns the production of the given player.
public int production(int playerID) {
int prod = 0;
for (Planet p : planets) {
if (p.owner() == playerID) {
prod += p.growthRate();
}
}
return prod;
}
// Parses a game state from a string. On success, returns 1. On failure,
// returns 0.
private int parseGameState(String s) {
planets.clear();
fleets.clear();
int planetID = 0;
String[] lines = s.split("\n");
for (int i = 0; i < lines.length; ++i) {
String line = lines[i];
int commentBegin = line.indexOf('#');
if (commentBegin >= 0) {
line = line.substring(0, commentBegin);
}
if (line.trim().length() == 0) {
continue;
}
String[] tokens = line.split(" ");
if (tokens.length == 0) {
continue;
}
if (tokens[0].equals("P")) {
if (tokens.length != 6) {
return 0;
}
double x = Double.parseDouble(tokens[1]);
double y = Double.parseDouble(tokens[2]);
int owner = Integer.parseInt(tokens[3]);
int numShips = Integer.parseInt(tokens[4]);
int growthRate = Integer.parseInt(tokens[5]);
Planet p = new Planet(planetID++, owner, numShips, growthRate,
x, y);
planets.add(p);
} else if (tokens[0].equals("F")) {
if (tokens.length != 7) {
return 0;
}
int owner = Integer.parseInt(tokens[1]);
int numShips = Integer.parseInt(tokens[2]);
int source = Integer.parseInt(tokens[3]);
int destination = Integer.parseInt(tokens[4]);
int totalTripLength = Integer.parseInt(tokens[5]);
int turnsRemaining = Integer.parseInt(tokens[6]);
Fleet f = new Fleet(owner, numShips, source, destination,
totalTripLength, turnsRemaining);
fleets.add(f);
} else {
return 0;
}
}
return 1;
}
// Store all the planets and fleets. OMG we wouldn't wanna lose all the
// planets and fleets, would we!?
private ArrayList<Planet> planets;
private ArrayList<Fleet> fleets;
}
package shared;
public class Fleet implements Comparable<Fleet>, Cloneable {
private int owner;
private int numShips;
private int sourcePlanet;
private int destinationPlanet;
private int totalTripLength;
private int turnsRemaining;
public Fleet(int owner, int numShips, int sourcePlanet,
int destinationPlanet, int totalTripLength, int turnsRemaining) {
this.owner = owner;
this.numShips = numShips;
this.sourcePlanet = sourcePlanet;
this.destinationPlanet = destinationPlanet;
this.totalTripLength = totalTripLength;
this.turnsRemaining = turnsRemaining;
}
public Fleet(int owner, int numShips) {
this.owner = owner;
this.numShips = numShips;
this.sourcePlanet = -1;
this.destinationPlanet = -1;
this.totalTripLength = -1;
this.turnsRemaining = -1;
}
public int owner() {
return owner;
}
public int numShips() {
return numShips;
}
public int sourcePlanet() {
return sourcePlanet;
}
public int destinationPlanet() {
return destinationPlanet;
}
public int totalTripLength() {
return totalTripLength;
}
public int turnsRemaining() {
return turnsRemaining;
}
public void removeShips(int amount) {
numShips -= amount;
}
// Subtracts one turn remaining. Call this function to make the fleet get
// one turn closer to its destination.
public void TimeStep() {
if (turnsRemaining > 0) {
--turnsRemaining;
} else {
turnsRemaining = 0;
}
}
#Override
public int compareTo(Fleet f) {
return this.numShips - f.numShips;
}
private Fleet(Fleet _f) {
owner = _f.owner;
numShips = _f.numShips;
sourcePlanet = _f.sourcePlanet;
destinationPlanet = _f.destinationPlanet;
totalTripLength = _f.totalTripLength;
turnsRemaining = _f.turnsRemaining;
}
public Object clone() {
return new Fleet(this);
}
}
for (Planet p = pw.notMyPlanets()){ should be for (Planet p : pw.notMyPlanets()){.
You've not posted the Fleet class, so as it is the code won't compile for me. However, the above is the only other error I could see.

Compare RDD Objects - Apache Spark

I'm fairly new into the apache spark technology and I'm having some problems while trying to analyze data I'm pulling from my files.
I have big list of genes information, and I'm pulling that information to a RDD, so far so good.
JavaRDD<Gene> inputfile = sc.textFile(logFile).map(
new Function<String, Gene>() {
#Override
public Gene call(String line) throws Exception {
String[] values = line.split("\t");
Gene gen = null;
//We are only interested in genes;
if( values.length > 2 && values[2].equalsIgnoreCase("gene") && !line.contains("#")){
String[] infoGene = values[8].split(";");
String geneId = StringUtils.substringBetween(infoGene[0], "\"");
String geneType = StringUtils.substringBetween(infoGene[2], "\"");
String geneName = StringUtils.substringBetween(infoGene[4], "\"");
gen = new Gene(geneName,values[3],values[4]);
return gen;
}
return gen;
}
}
).filter(new Function<Gene, Boolean>() {
#Override
public Boolean call(Gene gene) throws Exception {
if(gene == null)
return false;
else
return true;
}
});
The Gene class:
public class Gene implements Serializable{
String firstBp;
String lastBp;
String name;
public Gene(String name, String firstBp, String lastBp) {
this.name = name;
this.firstBp = firstBp;
this.lastBp = lastBp;
}
public String getFirstBp() {
return firstBp;
}
public String getLastBp() {
return lastBp;
}
public String getName() {
return name;
}
public String toString(){
return name + " " + firstBp + " " + lastBp;
}}
The problem starts here, I need to analyze if 2 Genes overlay, and for that I've made this simple utility function:
public static Boolean isOverlay(Gene gene1, Gene gene2){
int gene1First = Integer.parseInt(gene1.getFirstBp());
int gene1Last = Integer.parseInt(gene1.getLastBp());
int gene2First = Integer.parseInt(gene2.getFirstBp());
int gene2Last = Integer.parseInt(gene2.getLastBp());
if(gene2First >= gene1First && gene2First <= gene1Last) // FirstBp - Gene2 inside
return true;
else if (gene2Last >= gene1First && gene2Last <= gene1Last) // LastBP - Gene2 inside
return true;
else if (gene1First >= gene2First && gene1First <= gene2Last) // FirstBp - Gene1 inside
return true;
else if (gene1Last >= gene2First && gene1Last <= gene2Last) // LastBP - Gene1 inside
return true;
else
return false;
}
Now what I'm doing and I think is wrong is transforming the RDD Object into a list by doing:
List<Gene> genesList = inputfile.collect();
And iterate over that list to check if there are overlays and save to the file the results which is taking ages because I'm not using spark.
List<OverlayPair> overlayPairList= new ArrayList<OverlayPair>();
List<String> visitedGenes = new ArrayList<String>();
for (Gene gene1 : genesList){
for (Gene gene2 : genesList) {
if (gene1.getName().equalsIgnoreCase(gene2.getName()) || visitedGenes.contains(gene2.getName())) {
continue;
}
if (isOverlay(gene1, gene2))
overlayPairList.add(new OverlayPair(gene1.getName(), gene2.getName()));
}
visitedGenes.add(gene1.getName());
}
JavaRDD<OverlayPair> overlayFile = sc.parallelize(overlayPairList);
//Export the results to the file
String outputDirectory = "/Users/joaoalmeida/Desktop/Dissertacao/sol/data/mitocondrias/feup-pp/project/data/output/overlays";
overlayFile.coalesce(1).saveAsTextFile(outputDirectory);
The Overlay pair is basically an object with the 2 genes name.
Is there anyway to do this 2nd part while taking advantage of spark? Because the time complexity of those 2 for's its to big for the amount of data I currently have.
Yes, there is, you have to use RDD.cartesian function to get all the pairs and then you can basically apply the function you wrote.

Android - Loop and filter on List?

I have a List of data like this :
I need to get first and last records are same :
And my model is :
public class Modeltest {
private String lat;
private String lng;
private String date;
private String firstTime;
private String lasttime;
private String counts;
private String userCode;
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
.......
.....
.....
}
I can getting first and last :
List<Unprocessed_DistanceTime_D> listCDM = QDB.DistanceSelect_D();
int count = 1;
boolean flag = true;
int index;
for (int i = 0; i < listCDM.size() - 1; i++) {
if (listCDM.get(count).getDate().equalsIgnoreCase(listCDM.get(i).getDate()) &&
listCDM.get(count).getLat().equalsIgnoreCase(listCDM.get(i).getLat()) &&
listCDM.get(count).getLng().equalsIgnoreCase(listCDM.get(i).getLng()) &&
listCDM.get(count).getCounts().equalsIgnoreCase(listCDM.get(i).getCounts())) {
if (flag){
index = i;
flag = false;
}
}else {
index = i;
flag = true;
}
count++;
}
}
But my problem is here. How I can add these in another list and add single records in it ?
I get the first and last record then add in another list (I wrote the model above) .
I should fill my list here :
if (flag){
index = i;
///HERE
flag = false;
}
}else {
index = i;
///HERE
flag = true;
}
Here's a brute force method that first groups all the entries by a locally defined Identity and than merge those groups into a single Modeltest object.
There is probably a better way to do this though, since this disregards the fact that the input data is sorted.
List<Unprocessed_DistanceTime_D> list = ...;
class Identity {
private final String lat;
private final String lng;
private final String date;
private final String counts;
public Identity(Unprocessed_DistanceTime_D model) {
this.lat = model.getLat();
this.lng = model.getLng();
this.date = model.getDate();
this.counts = model.getCounts();
}
#Override
public int hashCode() {
int code = 0;
code ^= lat.hashCode();
code ^= lng.hashCode();
code ^= date.hashCode();
code ^= counts.hashCode();
return code;
}
#Override
public boolean equals(Object other) {
if(other == null)
return false;
if(!(other instanceof Identity))
return false;
Identity io = (Identity) other;
return lat.equalsIgnoreCase(io.lat)
&& lng.equalsIgnoreCase(io.lng)
&& date.equalsIgnoreCase(io.date)
&& counts.equalsIgnoreCase(io.counts);
}
}
List<Modeltest> models = list.stream()
.collect(Collectors.groupingBy(Identity::new))
.values().stream()
.map(group -> { // Convert groups into single Modeltest
if(group.size() == 1) { // Case for single entries
Unprocessed_DistanceTime_D e = group.get(0);
return new Modeltest(e.getLat(), e.getLng(), e.getDate(), e.getTime(),
e.getTime(), e.getCounts(), e.getUserCode());
}
// Case for more entries
group.sort(Comparator.comparing(Unprocessed_DistanceTime_D::getTime));
Unprocessed_DistanceTime_D first = group.get(0);
Unprocessed_DistanceTime_D last = group.get(group.size() - 1);
return new Modeltest(first.getLat(), first.getLng(), first.getDate(),
first.getTime(), last.getTime(), first.getCounts(), first.getUserCode());
})
.collect(Collectors.toList());
Here’s an idea for an algorithm. You can probably modify to your needs and fill in the details.
List<Unprocessed_DistanceTime_D> newListCDM = new ArrayList<>();
if (! listCDM.isEmpty()) {
Unprocessed_DistanceTime_D firstInGroup = listCDM.get(0);
Unprocessed_DistanceTime_D lastInGroup = firstInGroup;
for (int i = 1; i < listCDM.size() - 1; i++) {
Unprocessed_DistanceTime_D current = listCDM.get(i);
if (inSameGroup(firstInGroup, current)) { // current belongs to the same group
lastInGroup = current;
} else { // new group
// add old group to new list
newListCDM.add(firstInGroup);
if (lastInGroup != firstInGroup) {
newListCDM.add(lastInGroup);
}
}
}
// add last group to new list
newListCDM.add(firstInGroup);
if (lastInGroup != firstInGroup) {
newListCDM.add(lastInGroup);
}
}

Qt: how do I highlight duplicated items in QListWidget? (qtjambi)

I need to implement a mechanism of highlighting duplicated values. Values are edited through delegate depending on the value type (string - line edit, long and big decimal - spin boxes). Currently, I implemented this feature with help of additional class which stores all values and their counts in two "parallel" lists. And after adding a new value I increase its count number (or decrease when repeated value is removed), but this solution seems to be too bulky. Do you guys have any other ideas on highlighting in setModelData(...) method of QItemDelegate?
/**
* Stores a delegates' existing values
*/
private final class DelegateValuesStorage {
private final List<Object> values = new ArrayList<Object>();
private final List<Integer> counts = new ArrayList<Integer>();
....
//Add value or increase a count if exists
public void add(final Object value) {
if(values.contains(value)) {
final int valueIndex = values.indexOf(value);
final int oldCount = counts.get(valueIndex);
counts.remove(valueIndex);
counts.add(valueIndex, oldCount + 1);
} else {
values.add(value);
counts.add(1);
}
}
....
//Decrease a count or remove value if it doesn't exist anymore
public void decreaseCount(final Object value) {
if(value == null) {
return;
}
final int index = values.indexOf(value);
if(index >= 0) {
final int oldCount = counts.get(index);
if(oldCount >= 2) {
counts.remove(index);
counts.add(index, oldCount - 1);
} else {
values.remove(index);
counts.remove(index);
}
}
}
/**
* Delegate
*/
private class ConcreteDelegate extends QItemDelegate {
private final DelegateValuesStorage values = new DelegateValuesStorage();
...
#Override
public void setModelData(final QWidget editor, final QAbstractItemModel model, final QModelIndex index) {
if(editor instanceof ValEditor) { // ValEditor is an abstraction of line edit and spin box over values' data types
final Object value = ((ValEditor) editor).getValue();
model.setData(index, value, Qt.ItemDataRole.UserRole);
final String newData = (value == null) ? "" : String.valueOf(value);
values.add(newData);
final String oldData = (String) model.data(index, Qt.ItemDataRole.DisplayRole);
values.decreaseCount(oldData);
model.setData(index, newData, Qt.ItemDataRole.DisplayRole);
model.setData(index, new QColor(0, 0, 0), Qt.ItemDataRole.ForegroundRole);
redrawItems(model); // runs through values and colors them red if count >= 2; or black if count == 1
} else {
super.setModelData(editor, model, index);
}
}
}
I usually use maps for those kinds of tasks:
private final class DelegateValuesStorage {
private final Map<Object, Integer> values = new HashMap<Object, Integer>();
....
//Add value or increase a count if exists
public void add(final Object value) {
Integer count = values.get(value);
if (count == null) {
values.put(value, 1);
} else {
values.put(value, count + 1);
}
}
....
//Decrease a count or remove value if it doesn't exist anymore
public void decreaseCount(final Object value) {
if(value == null) {
return;
}
Integer count = values.get(value);
if (count == null) {
// decreasing a "new" value - could be an error too
return;
}
if (count <= 1) {
// remove the value from the map
values.remove(value);
} else {
values.put(value, count - 1);
}
}
}
Highlighting now should be enabled if
values.get(value) > 1
is true.

Categories