I have java based application for Texas Holdem Poker. I have to introduce a feature wherein whenever all players except one goes for all in, we have to calculate probability of winning for each player.
This can happen in pre-flop, flop & turn round. As you may know in pre-flop stage all 5 cards have to be chosen, in flop there are already 3 community cards in the table, 2 more cards have to be
chosen, whereas in turn round 1 more cards have to be chosen. Let us assume there are 2 players.
So each of the players have 2 hole cards. So we have to choose 2 cards from deck of 52 -2*2 = 48 cards. By using combinatorics I am able to do that. But in pre-flop stage there are too many combinations, from 48 we have to choose 5 cards which is 48Cr5 = 1712304 combinations. If I do that much computation the game gets stuck. So tried to use ForkJoinPool. I found there are only 2 cores in the machine where the application is deployed. It is not working at all. Is ForkJoinPool suitable for this task or should I go for some other ExecutorService. Here is some of my RecursiveTask code
public class WinnerPercentageTask extends RecursiveTask<List<String>> {
private static int threshold = 50_000;
private List<List<Byte>> combinations;
private int start;
private int end;
private ITexasHoldemGame game;
public WinnerPercentageTask(ITexasHoldemGame game, List<List<Byte>> allCombinations, int start, int end) {
super();
this.game = game;
this.combinations = allCombinations;
this.start = start;
this.end = end;
}
#Override
protected List<String> compute() {
if (end - start < threshold) {
return computeDirectly();
}
else {
int middle = (end + start) / 2;
WinnerPercentageTask subTask1 = new WinnerPercentageTask(game,combinations, start, middle);
WinnerPercentageTask subTask2 = new WinnerPercentageTask(game,combinations, middle, end);
invokeAll(subTask1, subTask2);
List<String> ret = new ArrayList<>();
ret.addAll(subTask1.join());
ret.addAll(subTask1.join());
return ret;
}
}
private List<String> computeDirectly() {
List<Card> communityCards = game.getCommunityCardsDealt();
List<Winner> winners = new ArrayList<>();
List<String> winnersForAllCombinations = new ArrayList<>();
for(List<Byte> combination: combinations.subList(start, end)) {
List<Card> allCommunityCard = new ArrayList<>();
for (Card c : communityCards) {
allCommunityCard.add(new Card(c.getId(), c.getFaceValue(), c.getSuit()));
}
for (Byte b : combination) {
Card fakeCommunityCard = new Card(b);
allCommunityCard.add(fakeCommunityCard);
}
List<PokerHand> playerRankList = calculateHandRank(allCommunityCard);
winners = prepareWinnerList(playerRankList);
winnersForAllCombinations.addAll(
winners.stream()
.map(Winner:: getPlayerId)
.collect(Collectors.toList()));
}
return winnersForAllCombinations;
}
private List<PokerHand> calculateHandRank(List<Card> communityCardsDealt) {
List<PokerHand> playerRankList = new ArrayList<>();
Map<String, List<Card>> playersCards = this.game.getCardsDealtForAllPlayers();
playersCards.forEach((player, holeCards) -> {
PokerHand pokerHand = new PokerHand(player, holeCards);
HandRanker.checkRanking(pokerHand, communityCardsDealt);
playerRankList.add(pokerHand);
});
Collections.sort(playerRankList);
// if (logger.isInfoEnabled()) {
// logger.info("Player Rank List : {}", playerRankList);
// }
return playerRankList;
}
private List<Winner> prepareWinnerList(List<PokerHand> playerRankList) {
List<Winner> winnerList = new ArrayList<>();
if (!CollectionUtils.isEmpty(playerRankList)) {
// Grouping Players based on similar Ranks
Map<HandRankingEnum, List<PokerHand>> groupByRankMap = playerRankList.stream()
.collect(Collectors.groupingBy(PokerHand::getRankingEnum));
// Sort the Map based on Rank, highest rank first
List<Map.Entry<HandRankingEnum, List<PokerHand>>> sortedWinnerList = groupByRankMap
.entrySet().stream().sorted(reverseOrder(Map.Entry.comparingByKey()))
.collect(Collectors.toList());
// Reading the Winners of highest rank
Map.Entry<HandRankingEnum, List<PokerHand>> winnerListMap = sortedWinnerList
.get(0);
List<PokerHand> highestRankList = winnerListMap.getValue();
List<PokerHand> winnerHandList = new WinnerIdentifier().getWinners(highestRankList);
for (PokerHand hand : winnerHandList) {
Winner winnerPlayer = Winner.builder()
.rank((byte) hand.getRankingEnum().getValue())
.rankName(hand.getRankingEnum().name())
.playerId(hand.getGamePlayerId()).cards(hand.getRankingList())
.pots(new ArrayList<>()).build();
winnerList.add(winnerPlayer);
}
}
return winnerList;
}
}
`
Related
Our professor tasked us to create a lotto program that will generate 6 random numbers ranging from 1-55 without us using the arrays and loops, we can only use "if else" statements. We also have to put scanner in which the user/better will input his 6 numbers also ranging from 1-55. The user's numbers should win as long as the 6 of the numbers match regardless of arrangements. For example
User: 1,2,3,4,5,6
Random Number:6,3,4,2,1,5
System: You Win!
I created a lotto program but my program requires every numbers to match with regards to their arrangement
User: 1,2,3,4,5,6
Random:6,5,4,3,2,1
System: You Lose
I don't have any idea how to ignore the arrangements. I tried search for a lot of thing in the internet and they mostly use arrays and loops.
public class LottoGame {
public static void main(String... args) {
Scanner scan = new Scanner(System.in);
System.out.print("Input 6 numbers [1-55] separated with space: ");
NumberSet userNumberSet = new NumberSet();
userNumberSet.a = new AtomicInteger(scan.nextInt());
userNumberSet.b = new AtomicInteger(scan.nextInt());
userNumberSet.c = new AtomicInteger(scan.nextInt());
userNumberSet.d = new AtomicInteger(scan.nextInt());
userNumberSet.e = new AtomicInteger(scan.nextInt());
userNumberSet.f = new AtomicInteger(scan.nextInt());
System.out.format("User: %d,%d,%d,%d,%d,%d\n", userNumberSet.a.get(), userNumberSet.b.get(),
userNumberSet.c.get(), userNumberSet.d.get(), userNumberSet.e.get(), userNumberSet.f.get());
userNumberSet.sort();
NumberSet randomNumberSet = getRandomNumberSet();
System.out.format("Randome Number: %d,%d,%d,%d,%d,%d\n", randomNumberSet.a.get(), randomNumberSet.b.get(),
randomNumberSet.c.get(), randomNumberSet.d.get(), randomNumberSet.e.get(),
randomNumberSet.f.get());
randomNumberSet.sort();
boolean win = userNumberSet.a.get() == randomNumberSet.a.get();
win &= userNumberSet.b.get() == randomNumberSet.b.get();
win &= userNumberSet.c.get() == randomNumberSet.c.get();
win &= userNumberSet.d.get() == randomNumberSet.d.get();
win &= userNumberSet.e.get() == randomNumberSet.e.get();
win &= userNumberSet.f.get() == randomNumberSet.f.get();
System.out.println("System: " + (win ? "You Win!" : "You Lose"));
}
private static NumberSet getRandomNumberSet() {
Random random = new Random();
NumberSet numberSet = new NumberSet();
numberSet.a = new AtomicInteger(random.nextInt(55) + 1);
numberSet.b = new AtomicInteger(random.nextInt(55) + 1);
numberSet.c = new AtomicInteger(random.nextInt(55) + 1);
numberSet.d = new AtomicInteger(random.nextInt(55) + 1);
numberSet.e = new AtomicInteger(random.nextInt(55) + 1);
numberSet.f = new AtomicInteger(random.nextInt(55) + 1);
return numberSet;
}
private static final class NumberSet {
private AtomicInteger a;
private AtomicInteger b;
private AtomicInteger c;
private AtomicInteger d;
private AtomicInteger e;
private AtomicInteger f;
public void sort() {
sort(a, b);
sort(b, c);
sort(c, d);
sort(d, e);
sort(e, f);
}
private void sort(AtomicInteger one, AtomicInteger two) {
if (one.get() > two.get()) {
int tmp = one.get();
one.set(two.get());
two.set(tmp);
}
if (two == b) {
sort(one, c);
} else if (two == c) {
sort(one, d);
} else if (two == d) {
sort(one, e);
} else if (two == e) {
sort(one, f);
}
}
}
}
P.S. I think you are able to update a bit this snippte to check that NumberSet contains only unique numbers.
I've been trying for two days to get this running, but I cant for the life of me.
what I'm trying to do is solve an 8 puzzle using the A star algorithm and manhattan heuristic.
this is the part of the code for the A star:
public void solve(){
State s = duplicateState(stateToSolve);
StringState ss = new StringState(s);
makeQ(ss.getStringState(),null,s);//add the first State to queue
//s.setG(0);
//s.setF(s.gettG()+heuristicTwo(ss.getStringState(),goal));
s.setF(heuristicTwo(ss.toString(),goal));
while(!states.isEmpty()){
LinkedList<State>child=new LinkedList<State>();
State state = lowestF(states);
StringState pre = new StringState(state);
if (goalReached(state)&&!solved){
s = state;
solved=true;
System.out.println("#########\n# Solved #\n#########");
break;
}
//explore(state);
child=neighbours(child,state);
for(int i=0;i<child.size();i++)
{
child.get(i).setTotalCost(state.gettG()+findDistance(state,child.get(i)));
if(open.containsKey(child.get(i)))
{
if(child.get(i).gettG()<=child.get(i).getTotalCost())
System.out.println(child.get(i).getSolution());
continue;
}
else if(close.containsKey(child.get(i)))
{
if(child.get(i).gettG()<=child.get(i).getTotalCost())
continue;
System.out.println(child.get(i).getSolution());
StringState next = new StringState(child.get(i));
makeQ(next.getStringState(),pre.getStringState(),child.get(i));
close.remove(child.get(i));
}
else
{
System.out.println(child.get(i).getSolution());
StringState next = new StringState(child.get(i));
makeQ(next.getStringState(),pre.getStringState(),child.get(i));
child.get(i).setH(heuristicTwo(next.getStringState(),goal));
}
child.get(i).setG(child.get(i).getTotalCost());
}
close.put(ss.getStringState(),ss.getStringState());
}
solution = s.getSolution();
if (solution.equals("")||solution.equals(null))
System.out.println("no solution");
else{
System.out.println("Astar");
System.out.println(solution);
}
}
StringState is just takes the state of the board of the puzzle and converts in to a string.
to make thins a little more clear here some other parts of the code:
private Queue<State> states;
private State stateToSolve;
boolean solved=false;
private final String goal = "0123456789ABCDEF";
private final String goal2 = "123456789ABCDEF0";
private Map<String,String> close;//to keep track of previous checked status
private Map<String, String> open;
private String solution;
//-1,-1 for decrement of coordinates
private final int up = -4;
private final int down = 4;
private final int left = -1;
private final int right = 1;
//CONSTRUCTOR
public Astar(State s){
solution = "";
states = new LinkedList<State>();
stateToSolve = duplicateState(s);
close = new HashMap<String, String>();
open = new HashMap<String, String>();
solve();
}
All the neighbours function does is to take a state of the board and returns the neighbours of the board-meaning moving the blank tile to the left/right/up/down(if possible)and giving back the board state after doing it.
so the neighbours are the new states.
The problem that I'm facing (I came to realize after running the program and tried to print it's state at some points)is that it's going inside an infinite loop apter 2 moves of the blank tile.For example, when I'm trying to find a path for the String str1 = "1 2 0 3 4 5 6 7 8 9 A B C D E F";
the answer should be-left left
but I'm getting
left
left
left
right
left
down
left
left
left
right
left
down
left
left
and it just go on and on infinitelly..
Any help would be appreciated..
((I was using this -pseudo code)
// ************************************************************
// ELEVATOR.java
//
// ELEVAOTR SIMULATION
// PROBLEM: NEED TO FIND A WAY TO AMKE IT SO THAT THE PROGRAM KEEPS RNNING AFTER USER INPUTS
// THIER FIRST DESIRED FLOOR.
// ************************************************************
import java.util.*;
public class Elevator_Simulation {
public static void main (String[] args) {
Person User = new Person();
Floor floors = new Floor();
floors.moveElevator(User.getDesiredFloor());
}
}
class Elevator { //NEEDS SETTER & GETTER METHODS
private int mass=0;
private int capcity=0;
private String name="";
private String color="";
}
class Floor {
ArrayList<Object> floorLevel = new ArrayList<Object>();
Elevator Lift = new Elevator();
Person Man = new Person();
Floor() { //Floors 0-9
floorLevel.add(Lift); //0
floorLevel.add(null); //1
floorLevel.add(null); //2
floorLevel.add(null); //3
floorLevel.add(null); //4
floorLevel.add(null); //5
floorLevel.add(null); //6
floorLevel.add(null); //7
floorLevel.add(null); //8
floorLevel.add(null); //9
}
System.out.println("Elevator is at Floor: " + floorLevel.indexOf(Lift) );
public void moveElevator (int chosenFloor) {
if (chosenFloor > 9) {
System.out.println("Woooooah Buddy! You can only choose 0-9!");
return;
}
if (chosenFloor == floorLevel.indexOf(Lift)) {
System.out.println("Bro you're already on that floor...");
}
while (floorLevel.indexOf(Lift)>chosenFloor) {
Collections.swap(floorLevel, floorLevel.indexOf(Lift), ( floorLevel.indexOf(Lift)-1 ) );
System.out.println(floorLevel.indexOf(Lift) );
}
while (floorLevel.indexOf(Lift)<chosenFloor) {
Collections.swap(floorLevel, floorLevel.indexOf(Lift), ( floorLevel.indexOf(Lift)+1 ) );
System.out.println(floorLevel.indexOf(Lift) );
}
}
}
class Person {
Scanner scan = new Scanner(System.in);
public int getDesiredFloor() {
int desiredFloor = scan.nextInt();
return desiredFloor;
}
}
Above is an Elevator Simulator Code (before I attempt to make one with a GUI) and my only problem, aside from the obvious beginner flaws, is that I'm having trouble of finding a way to make it so that the program doesn't just end once the user inputs one floor. I at least want the program to run until the user ends it with a command. I'm thinking of using a while loop somewhere but where? Please help and point out anything I should improve in this code.
You can put the while loop around the line
floors.moveElevator(User.getDesiredFloor());
Just add an input check for a value that represents exiting.
I have two lists of intervals. I would like to remove all times from list1 that already exists in list2.
Example:
List1:
[(0,10),(15,20)]
List2:
[(2,3),(5,6)]
Output:
[(0,2),(3,5),(6,10),(15,20)]
Any hints?
Tried to remove one interval at the time but it seems like I need to take a different approach:
public List<Interval> removeOneTime(Interval interval, Interval remove){
List<Interval> removed = new LinkedList<Interval>();
Interval overlap = interval.getOverlap(remove);
if(overlap.getLength() > 0){
List<Interval> rms = interval.remove(overlap);
removed.addAll(rms);
}
return removed;
}
I would approach this problem with a sweep line algorithm. The start and end points of the intervals are events, that are put in a priority queue. You just move from left to right, stop at every event, and update the current status according to that event.
I made a small implementation, in which I use the following Interval class, just for simplicity:
public class Interval {
public int start, end;
public Interval(int start, int end) {
this.start = start;
this.end = end;
}
public String toString() {
return "(" + start + "," + end + ")";
}
}
The event points mentioned earlier are represented by the following class:
public class AnnotatedPoint implements Comparable<AnnotatedPoint> {
public int value;
public PointType type;
public AnnotatedPoint(int value, PointType type) {
this.value = value;
this.type = type;
}
#Override
public int compareTo(AnnotatedPoint other) {
if (other.value == this.value) {
return this.type.ordinal() < other.type.ordinal() ? -1 : 1;
} else {
return this.value < other.value ? -1 : 1;
}
}
// the order is important here: if multiple events happen at the same point,
// this is the order in which you want to deal with them
public enum PointType {
End, GapEnd, GapStart, Start
}
}
Now, what remains is building the queue and doing the sweep, as shown in the code below
public class Test {
public static void main(String[] args) {
List<Interval> interval = Arrays.asList(new Interval(0, 10), new Interval(15, 20));
List<Interval> remove = Arrays.asList(new Interval(2, 3), new Interval(5, 6));
List<AnnotatedPoint> queue = initQueue(interval, remove);
List<Interval> result = doSweep(queue);
// print result
for (Interval i : result) {
System.out.println(i);
}
}
private static List<AnnotatedPoint> initQueue(List<Interval> interval, List<Interval> remove) {
// annotate all points and put them in a list
List<AnnotatedPoint> queue = new ArrayList<>();
for (Interval i : interval) {
queue.add(new AnnotatedPoint(i.start, PointType.Start));
queue.add(new AnnotatedPoint(i.end, PointType.End));
}
for (Interval i : remove) {
queue.add(new AnnotatedPoint(i.start, PointType.GapStart));
queue.add(new AnnotatedPoint(i.end, PointType.GapEnd));
}
// sort the queue
Collections.sort(queue);
return queue;
}
private static List<Interval> doSweep(List<AnnotatedPoint> queue) {
List<Interval> result = new ArrayList<>();
// iterate over the queue
boolean isInterval = false; // isInterval: #Start seen > #End seen
boolean isGap = false; // isGap: #GapStart seen > #GapEnd seen
int intervalStart = 0;
for (AnnotatedPoint point : queue) {
switch (point.type) {
case Start:
if (!isGap) {
intervalStart = point.value;
}
isInterval = true;
break;
case End:
if (!isGap) {
result.add(new Interval(intervalStart, point.value));
}
isInterval = false;
break;
case GapStart:
if (isInterval) {
result.add(new Interval(intervalStart, point.value));
}
isGap = true;
break;
case GapEnd:
if (isInterval) {
intervalStart = point.value;
}
isGap = false;
break;
}
}
return result;
}
}
This results in:
(0,2)
(3,5)
(6,10)
(15,20)
You probably want to use an interval tree - this will quickly tell you if an interval overlaps with any of the intervals in the tree.
Once you have a set of overlapping intervals the task should be fairly easy (interval1 is from list1, interval2 is the overlapping interval from list2 / the interval tree): if interval1 contains interval2, then you have two new intervals (interval1min, interval2min), (interval2max, interval1max); if interval1 does not contain interval2, then you only have one new interval (interval1min, interval2min) or (interval2max, interval1max)
I've done the breadth-first search in a normal way.
now I'm trying to do it in a multithreaded way.
i have one queue which is shared between the threads.
i use synchronize(LockObject) when i remove a node from the queue ( FIFI queue )
so what I'm trying to do is that.
when i thread finds a solution all the other threads will stop immediately.
i assume you are traversing a tree for your BFS.
create a thread pool.
for each unexplored children in the node, retrieve a thread from the thread pool (perhaps using a Semaphore). mark the child node as 'explored' and explore the node's children in a BFS manner. when you have found a solution or done exploring all the nodes, release the semaphore.
^ i've never done this before so i might have missed out something.
Assuming you want to do this iteratively (see note at the bottom why there may be better closed solutions), this is not a great problem for exercising multi threading. The problem is that multithreading is great if you don't depend on previous results, but here you want the minimum amount of coins.
As you point out, a breadth first solution guarantees that once you reach the desired amount, you won't have any further solutions with less coins in a single threaded environment. However, in a multithreaded environment, once you start calculating a solution, you cannot guarantee that it will finish before some other solution. Let's imagine for the value 21: it can be a 20c coin and a 1c or four 5c coins and a 1c; if both are calculating simultaneously, you cannot guarantee that the first (and correct) solution will finish first. In practice, it is unlikely the situation will happen, but when you work with multithreading you want the solution to work in theory, because multithreads always fail in the demonstration, no matter if they should not have failed until the death heat of the universe.
Now you have 2 possible solutions: one is to introduce choke points at the beginning of each level; you don't start that level until the previous level is finished. The other is once you reach a solution continue doing all the calculations with a lower level than the current result (which means you cannot purge the others). Probably with all the synchronization needed you get better performance by going single threaded, but let's go on.
For the first solution, the natural form is to iterate increasing the level. You can use the solution provided by happymeal, with a Semaphore. An alternative is to use the new classes provided by java.
CoinSet getCoinSet(int desiredAmount) throws InterruptedException {
// Use whatever number of threads you prefer or another member of Executors.
final ExecutorService executor = Executors.newFixedThreadPool(10);
ResultContainer container = new ResultContainer();
container.getNext().add(new Producer(desiredAmount, new CoinSet(), container));
while (container.getResult() == null) {
executor.invokeAll(container.setNext(new Vector<Producer>()));
}
return container.getResult();
}
public class Producer implements Callable<CoinSet> {
private final int desiredAmount;
private final CoinSet data;
private final ResultContainer container;
public Producer(int desiredAmount, CoinSet data, ResultContainer container) {
this.desiredAmount = desiredAmount;
this.data = data;
this.container = container;
}
public CoinSet call() {
if (data.getSum() == desiredAmount) {
container.setResult(data);
return data;
} else {
Collection<CoinSet> nextSets = data.addCoins();
for (CoinSet nextSet : nextSets) {
container.getNext().add(new Producer(desiredAmount, nextSet, container));
}
return null;
}
}
}
// Probably it is better to split this class, but you then need to pass too many parameters
// The only really needed part is to create a wrapper around getNext, since invokeAll is
// undefined if you modify the list of tasks.
public class ResultContainer {
// I use Vector because it is synchronized.
private Vector<Producer> next = new Vector<Producer>();
private CoinSet result = null;
// Note I return the existing value.
public Vector<Producer> setNext(Vector<Producer> newValue) {
Vector<Producer> current = next;
next = newValue;
return current;
}
public Vector<Producer> getNext() {
return next;
}
public synchronized void setResult(CoinSet newValue) {
result = newValue;
}
public synchronized CoinSet getResult() {
return result;
}
}
This still has the problem that existing tasks are executed; however, it is simple to fix that; pass the thread executor into each Producer (or the container). Then, when you find a result, call executor.shutdownNow. The threads that are executing won't be interrupted, but the operation in each thread is trivial so it will finish fast; the runnables that have not started won't start.
The second option means you have to let all the current tasks finish, unless you keep track of how many tasks you have run at each level. You no longer need to keep track of the levels, though, and you don't need the while cycle. Instead, you just call
executor.submit(new Producer(new CoinSet(), desiredAmount, container)).get();
And then, the call method is pretty similar (assume you have executor in the Producer):
public CoinSet call() {
if (container.getResult() != null && data.getCount() < container.getResult().getCount()) {
if (data.getSum() == desiredAmount)) {
container.setResult(data);
return data;
} else {
Collection<CoinSet> nextSets = data.addCoins();
for (CoinSet nextSet : nextSets) {
executor.submit(new Producer(desiredAmount, nextSet, container));
}
return null;
}
}
}
and you also have to modify container.setResult, since you cannot depend that between the if and setting the value it has not been set by some other threads (threads are really annoying, aren't they?)
public synchronized void setResult(CoinSet newValue) {
if (newValue.getCount() < result.getCount()) {
result = newValue;
}
}
In all previous answers, CoinSet.getSum() returns the sum of the coins in the set, CoinSet.getCount() returns the number of coins, and CoinSet.addCoins() returns a Collection of CoinSet in which each element is the current CoinSet plus one coin of each possible different value
Note: For the problem of the coins with the values 1, 5, 10 and 20, the simplest solution is take the amount and divide it by the largest coin. Then take the modulus of that and use the next largest value and so on. That is the minimum amount of coins you are going to need. This rule applies (AFAICT) when the following property if true: if for all consecutive pairs of coin values (i.e. in this case, 1-5, 5-10, 10-20) you can reach any int multiple of the lower element in the pair with with a smaller number of coins using the larger element and whatever coins are necessary. You only need to prove it to the min common multiple of both elements in the pair (after that it repeats itself)
I gather from your comment on happymeal's anwer that you are trying to find how to reach a specific amount of money by adding coins of 1c, 5c, 10c and 20c.
Since each coin denomination divides the denomination of the next bigger coin, this can be solved in constant time as follows:
int[] coinCount(int amount) {
int[] coinValue = {20, 10, 5, 1};
int[] coinCount = new int[coinValue.length];
for (int i = 0; i < coinValue.length; i++) {
coinCount[i] = amount / coinValue[i];
amount -= coinCount[i] * coinValue[i];
}
return coinCount;
}
Take home message: Try to optimize your algorithm before resorting to multithreading, because algorithmic improvements can yield much greater improvements.
I've successfully implemented it.
what i did is that i took all the nodes in the first level, let's say 4 nodes.
then i had 2 threads. each one takes 2 nodes and generate their children. whenever a node finds a solution it has to report the level that it found the solution in and limit the searching level so other threads don't exceed the level.
only the reporting method should be synchronized.
i did the code for the coins change problem. this is my code for others to use
Main Class (CoinsProblemBFS.java)
package coinsproblembfs;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
/**
*
* #author Kassem M. Bagher
*/
public class CoinsProblemBFS
{
private static List<Item> MoneyList = new ArrayList<Item>();
private static Queue<Item> q = new LinkedList<Item>();
private static LinkedList<Item> tmpQ;
public static Object lockLevelLimitation = new Object();
public static int searchLevelLimit = 1000;
public static Item lastFoundNode = null;
private static int numberOfThreads = 2;
private static void InitializeQueu(Item Root)
{
for (int x = 0; x < MoneyList.size(); x++)
{
Item t = new Item();
t.value = MoneyList.get(x).value;
t.Totalvalue = MoneyList.get(x).Totalvalue;
t.Title = MoneyList.get(x).Title;
t.parent = Root;
t.level = 1;
q.add(t);
}
}
private static int[] calculateQueueLimit(int numberOfItems, int numberOfThreads)
{
int total = 0;
int[] queueLimit = new int[numberOfThreads];
for (int x = 0; x < numberOfItems; x++)
{
if (total < numberOfItems)
{
queueLimit[x % numberOfThreads] += 1;
total++;
}
else
{
break;
}
}
return queueLimit;
}
private static void initializeMoneyList(int numberOfItems, Item Root)
{
for (int x = 0; x < numberOfItems; x++)
{
Scanner input = new Scanner(System.in);
Item t = new Item();
System.out.print("Enter the Title and Value for item " + (x + 1) + ": ");
String tmp = input.nextLine();
t.Title = tmp.split(" ")[0];
t.value = Double.parseDouble(tmp.split(" ")[1]);
t.Totalvalue = t.value;
t.parent = Root;
MoneyList.add(t);
}
}
private static void printPath(Item item)
{
System.out.println("\nSolution Found in Thread:" + item.winnerThreadName + "\nExecution Time: " + item.searchTime + " ms, " + (item.searchTime / 1000) + " s");
while (item != null)
{
for (Item listItem : MoneyList)
{
if (listItem.Title.equals(item.Title))
{
listItem.counter++;
}
}
item = item.parent;
}
for (Item listItem : MoneyList)
{
System.out.println(listItem.Title + " x " + listItem.counter);
}
}
public static void main(String[] args) throws InterruptedException
{
Item Root = new Item();
Root.Title = "Root Node";
Scanner input = new Scanner(System.in);
System.out.print("Number of Items: ");
int numberOfItems = input.nextInt();
input.nextLine();
initializeMoneyList(numberOfItems, Root);
System.out.print("Enter the Amount of Money: ");
double searchValue = input.nextDouble();
int searchLimit = (int) Math.ceil((searchValue / MoneyList.get(MoneyList.size() - 1).value));
System.out.print("Number of Threads (Muste be less than the number of items): ");
numberOfThreads = input.nextInt();
if (numberOfThreads > numberOfItems)
{
System.exit(1);
}
InitializeQueu(Root);
int[] queueLimit = calculateQueueLimit(numberOfItems, numberOfThreads);
List<Thread> threadList = new ArrayList<Thread>();
for (int x = 0; x < numberOfThreads; x++)
{
tmpQ = new LinkedList<Item>();
for (int y = 0; y < queueLimit[x]; y++)
{
tmpQ.add(q.remove());
}
BFS tmpThreadObject = new BFS(MoneyList, searchValue, tmpQ);
Thread t = new Thread(tmpThreadObject);
t.setName((x + 1) + "");
threadList.add(t);
}
for (Thread t : threadList)
{
t.start();
}
boolean finish = false;
while (!finish)
{
Thread.sleep(250);
for (Thread t : threadList)
{
if (t.isAlive())
{
finish = false;
break;
}
else
{
finish = true;
}
}
}
printPath(lastFoundNode);
}
}
Item Class (Item.java)
package coinsproblembfs;
/**
*
* #author Kassem
*/
public class Item
{
String Title = "";
double value = 0;
int level = 0;
double Totalvalue = 0;
int counter = 0;
Item parent = null;
long searchTime = 0;
String winnerThreadName="";
}
Threads Class (BFS.java)
package coinsproblembfs;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
*
* #author Kassem M. Bagher
*/
public class BFS implements Runnable
{
private LinkedList<Item> q;
private List<Item> MoneyList;
private double searchValue = 0;
private long start = 0, end = 0;
public BFS(List<Item> monyList, double searchValue, LinkedList<Item> queue)
{
q = new LinkedList<Item>();
MoneyList = new ArrayList<Item>();
this.searchValue = searchValue;
for (int x = 0; x < queue.size(); x++)
{
q.addLast(queue.get(x));
}
for (int x = 0; x < monyList.size(); x++)
{
MoneyList.add(monyList.get(x));
}
}
private synchronized void printPath(Item item)
{
while (item != null)
{
for (Item listItem : MoneyList)
{
if (listItem.Title.equals(item.Title))
{
listItem.counter++;
}
}
item = item.parent;
}
for (Item listItem : MoneyList)
{
System.out.println(listItem.Title + " x " + listItem.counter);
}
}
private void addChildren(Item node, LinkedList<Item> q, boolean initialized)
{
for (int x = 0; x < MoneyList.size(); x++)
{
Item t = new Item();
t.value = MoneyList.get(x).value;
if (initialized)
{
t.Totalvalue = 0;
t.level = 0;
}
else
{
t.parent = node;
t.Totalvalue = MoneyList.get(x).Totalvalue;
if (t.parent == null)
{
t.level = 0;
}
else
{
t.level = t.parent.level + 1;
}
}
t.Title = MoneyList.get(x).Title;
q.addLast(t);
}
}
#Override
public void run()
{
start = System.currentTimeMillis();
try
{
while (!q.isEmpty())
{
Item node = null;
node = (Item) q.removeFirst();
node.Totalvalue = node.value + node.parent.Totalvalue;
if (node.level < CoinsProblemBFS.searchLevelLimit)
{
if (node.Totalvalue == searchValue)
{
synchronized (CoinsProblemBFS.lockLevelLimitation)
{
CoinsProblemBFS.searchLevelLimit = node.level;
CoinsProblemBFS.lastFoundNode = node;
end = System.currentTimeMillis();
CoinsProblemBFS.lastFoundNode.searchTime = (end - start);
CoinsProblemBFS.lastFoundNode.winnerThreadName=Thread.currentThread().getName();
}
}
else
{
if (node.level + 1 < CoinsProblemBFS.searchLevelLimit)
{
addChildren(node, q, false);
}
}
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
Sample Input:
Number of Items: 4
Enter the Title and Value for item 1: one 1
Enter the Title and Value for item 2: five 5
Enter the Title and Value for item 3: ten 10
Enter the Title and Value for item 4: twenty 20
Enter the Amount of Money: 150
Number of Threads (Muste be less than the number of items): 2