I am new to Java and I am attempting to manipulate some football match data in order to get a more in-depth understanding of the results. I have managed to get it to read from the CSV and I can get the individual values. The CSV format is like this fopr about 400 rows:
Arsenal,Leicester,4,3,H
Brighton,Man City,0,2,A
Chelsea,Burnley,2,3,A
Crystal Palace,Huddersfield,0,3,A
Everton,Stoke,1,0,H
Southampton,Swansea,0,0,D
What I have struggled with is to retrieve the home team and away teams(objects and unsure how to match the string from the CSV to them): current points, league position goal, difference along with the match in a row in excel (I plan to use an artificial neural network to predict matches from this data) then I would like to match and update the correct object of each team e.g.if home team is Arsenal and they win 2-0 update Team Arsenal() to have 3 more points, 2 more goals scored, update league table position. Once this is done it will read the next result and repeat.
I know this is a lot but I am really struggling on these parts so would really appreciate some help for a newbie to java.
Here is my current code:
InputHere.java:
package BasicP;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class InputHere {
public static void main(String[] args) {
List<Match> matches = new ArrayList<>();
Path logFile = Paths.get("C:\\Users\\Lewys\\Documents", "FinalofFootballDataws.csv");
try (BufferedReader read
= Files.newBufferedReader(logFile, StandardCharsets.US_ASCII)) {
String firstLine = read.readLine();
while (firstLine != null) {
String[] variables = firstLine.split(",");
String homeName = variables[0];
String awayName = variables[1];
String strHomeScore = variables[2];
String strAwayScore = variables[3];
int homeScore = Integer.parseInt(strHomeScore);
int awayScore = Integer.parseInt(strAwayScore);
firstLine = read.readLine();
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
return;
}
}
Team.java:
public class Team {
private String teamName;
private int numberWin;
private int numberDraw;
private int numberLoss;
private int matchesPlayed;
private int points;
private int goalsScored;
private int goalsConceded;
private int tablePosition;
public Team(String teamName, int numberWin, int numberDraw,
int numberLoss, int matchesPlayed, int points,
int goalsScored, int goalsConceded, int tablePosition) {
}
public int getNumberWin() {
return numberWin;
}
public int getNumberDraw() {
return numberDraw;
}
public int getNumberLoss() {
return numberLoss;
}
public int getMatchesPlayed() {
return matchesPlayed;
}
public int getPoints() {
return points;
}
public int getGoalsScored() {
return goalsScored;
}
public int getGoalsConceded() {
return goalsConceded;
}
public int getTablePosition() {
return tablePosition;
}
public void setNumberWin(int i) {
numberWin = numberWin + i;
}
public void setNumberDraw(int i) {
numberDraw = numberDraw + i;
}
public void setNumberLoss(int i) {
numberLoss = numberLoss + i;
}
public void setMatchesPlayed(int i) {
matchesPlayed = matchesPlayed + i;
}
public void setPoints(int i) {
points = points + i;
}
public void setGoalsScored(int i) {
goalsScored = goalsScored + i;
}
public void setGoalsConceded(int i) {
goalsConceded = goalsConceded + i;
}
public void settablePosition(int i) {
tablePosition = i;
}
public String getTeamName() {
return teamName;
}
public void setTeamName(String teamName) {
this.teamName = teamName;
}
}
I try solve your issue.
Firt a write a CSVReader, but I suggest you to try using a specific library for it to better manage all csv format.
public class FootballMatchCSVReader {
public List<FootballMatch> read(String filePath) throws IOException {
return readAllLines(filePath).stream().map(line -> mapToFootballMatch(line.split(","))).collect(toList());
}
private List<String> readAllLines(String filePath) throws IOException {
return Files.readAllLines(Paths.get(filePath));
}
private FootballMatch mapToFootballMatch(String[] args) {
return new FootballMatch(args[0],args[1],Integer.valueOf(args[2]),Integer.valueOf(args[3]),args[4].charAt(0));
}
}
That return a List of FootballMatch
public class FootballMatch {
private String homeTeam;
private String awayTeam;
private int homeTeamScore;
private int awayTeamScore;
private char finalResult;
public FootballMatch(String homeTeam, String awayTeam, int homeTeamScore, int awayTeamScore, char winner) {
this.homeTeam = homeTeam;
this.awayTeam = awayTeam;
this.homeTeamScore = homeTeamScore;
this.awayTeamScore = awayTeamScore;
this.finalResult = winner;
}
public String getHomeTeam() {
return homeTeam;
}
public void setHomeTeam(String homeTeam) {
this.homeTeam = homeTeam;
}
public String getAwayTeam() {
return awayTeam;
}
public void setAwayTeam(String awayTeam) {
this.awayTeam = awayTeam;
}
public int getHomeTeamScore() {
return homeTeamScore;
}
public void setHomeTeamScore(int homeTeamScore) {
this.homeTeamScore = homeTeamScore;
}
public int getAwayTeamScore() {
return awayTeamScore;
}
public void setAwayTeamScore(int awayTeamScore) {
this.awayTeamScore = awayTeamScore;
}
public char getFinalResult() {
return finalResult;
}
public void setFinalResult(char finalResult) {
this.finalResult = finalResult;
}
#Override
public String toString() {
return "FootballMatch{" +
"homeTeam='" + homeTeam + '\'' +
", awayTeam='" + awayTeam + '\'' +
", homeTeamScore=" + homeTeamScore +
", awayTeamScore=" + awayTeamScore +
", finalResult=" + finalResult +
'}';
}
}
Now I write a FootballMatchStatisticsEngine that compute the TeamStatistic for each match
public class TeamStatistic {
private String teamName;
private int numberWin;
private int numberDraw;
private int numberLoss;
private int matchesPlayed;
private int points;
private int goalsScored;
private int goalsConceded;
private int tablePosition;
public TeamStatistic(String teamName, int numberWin, int numberDraw, int numberLoss, int matchesPlayed, int points, int goalsScored, int goalsConceded, int tablePosition) {
this.teamName = teamName;
this.numberWin = numberWin;
this.numberDraw = numberDraw;
this.numberLoss = numberLoss;
this.matchesPlayed = matchesPlayed;
this.points = points;
this.goalsScored = goalsScored;
this.goalsConceded = goalsConceded;
this.tablePosition = tablePosition;
}
public String getTeamName() {
return teamName;
}
public void setTeamName(String teamName) {
this.teamName = teamName;
}
public int getNumberWin() {
return numberWin;
}
public void setNumberWin(int numberWin) {
this.numberWin = numberWin;
}
public int getNumberDraw() {
return numberDraw;
}
public void setNumberDraw(int numberDraw) {
this.numberDraw = numberDraw;
}
public int getNumberLoss() {
return numberLoss;
}
public void setNumberLoss(int numberLoss) {
this.numberLoss = numberLoss;
}
public int getMatchesPlayed() {
return matchesPlayed;
}
public void setMatchesPlayed(int matchesPlayed) {
this.matchesPlayed = matchesPlayed;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public int getGoalsScored() {
return goalsScored;
}
public void setGoalsScored(int goalsScored) {
this.goalsScored = goalsScored;
}
public int getGoalsConceded() {
return goalsConceded;
}
public void setGoalsConceded(int goalsConceded) {
this.goalsConceded = goalsConceded;
}
public int getTablePosition() {
return tablePosition;
}
public void setTablePosition(int tablePosition) {
this.tablePosition = tablePosition;
}
#Override
public String toString() {
return "TeamStatistic{" +
"teamName='" + teamName + '\'' +
", numberWin=" + numberWin +
", numberDraw=" + numberDraw +
", numberLoss=" + numberLoss +
", matchesPlayed=" + matchesPlayed +
", points=" + points +
", goalsScored=" + goalsScored +
", goalsConceded=" + goalsConceded +
", tablePosition=" + tablePosition +
'}';
}
}
public class FootballMatchStatisticsEngine {
public List<TeamStatistic> computeTeamStatistics(List<FootballMatch> footballMatches) {
List<TeamStatistic> teamStatistics = getTeamStatistics(footballMatches);
updatePosition(teamStatistics);
return teamStatistics;
}
private void updatePosition(List<TeamStatistic> teamStatistics) {
/*
This function apply the relative table position to each TeamStatistics.
*/
IntStream.range(0,teamStatistics.size()).forEach(i -> teamStatistics.get(i).setTablePosition(i+1));
}
private List<TeamStatistic> getTeamStatistics(List<FootballMatch> footballMatches) {
/*
The flat operation explode each match into two different TeamStatistics. One for home team and one for away team.
After I compute the groupBy operation over team name and reduce the resulting list of Team statistics sumurizing her data.
*/
return footballMatches
.stream()
.flatMap(fm -> footballMatchtoTeamStatistics(fm).stream())
.collect(groupingBy(TeamStatistic::getTeamName, reducing(getTeamStatisticReduceOperation())))
.values().stream().map(Optional::get)
.sorted(comparingInt(TeamStatistic::getPoints).reversed())
.collect(Collectors.toList());
}
private BinaryOperator<TeamStatistic> getTeamStatisticReduceOperation() {
return (x, y) ->
new TeamStatistic(
x.getTeamName(),
x.getNumberWin() + y.getNumberWin(),
x.getNumberDraw() + y.getNumberDraw(),
x.getNumberLoss() + y.getNumberLoss(),
x.getMatchesPlayed() + y.getMatchesPlayed(),
x.getPoints() + y.getPoints(),
x.getGoalsScored() + y.getGoalsScored(),
x.getGoalsConceded() + y.getGoalsConceded(), 0);
}
private List<TeamStatistic> footballMatchtoTeamStatistics(FootballMatch footballMatch) {
return Arrays.asList(
new TeamStatistic(
footballMatch.getHomeTeam(),
footballMatch.getFinalResult() == 'H' ? 1 : 0,
footballMatch.getFinalResult() == 'D' ? 1 : 0,
footballMatch.getFinalResult() == 'A' ? 1 : 0,
1,
footballMatch.getFinalResult() == 'H' ? 3 : footballMatch.getFinalResult() == 'D' ? 1 : 0,
footballMatch.getHomeTeamScore(),
footballMatch.getAwayTeamScore(),
0),
new TeamStatistic(
footballMatch.getAwayTeam(),
footballMatch.getFinalResult() == 'A' ? 1 : 0,
footballMatch.getFinalResult() == 'D' ? 1 : 0,
footballMatch.getFinalResult() == 'H' ? 1 : 0,
1,
footballMatch.getFinalResult() == 'A' ? 3 : footballMatch.getFinalResult() == 'D' ? 1 : 0,
footballMatch.getAwayTeamScore(),
footballMatch.getHomeTeamScore(),
0)
);
}
}
To test this code I write a file with the follow lines:
Arsenal,Leicester,4,3,H
Man City,Leicester,2,1,H
Brighton,Man City,0,2,A
Chelsea,Arsenal,0,2,A
Chelsea,Burnley,2,3,A
Crystal Palace,Huddersfield,0,3,A
Everton,Stoke,1,0,H
Southampton,Swansea,0,0,D
running the follow code
FootballMatchCSVReader reader = new FootballMatchCSVReader();
FootballMatchStatisticsEngine statisticsEngine = new FootballMatchStatisticsEngine();
try {
List<FootballMatch> footbalMatches = reader.read("src/test/resources/input.txt");
List<TeamStatistic> teamStatistics = statisticsEngine.computeTeamStatistics(footbalMatches);
teamStatistics.forEach(t -> System.out.println(t));
} catch (IOException e) {
e.printStackTrace();
}
This is the output
TeamStatistic{teamName='Arsenal', numberWin=2, numberDraw=0, numberLoss=0, matchesPlayed=2, points=6, goalsScored=6, goalsConceded=3, tablePosition=1}
TeamStatistic{teamName='Man City', numberWin=2, numberDraw=0, numberLoss=0, matchesPlayed=2, points=6, goalsScored=4, goalsConceded=1, tablePosition=2}
TeamStatistic{teamName='Huddersfield', numberWin=1, numberDraw=0, numberLoss=0, matchesPlayed=1, points=3, goalsScored=3, goalsConceded=0, tablePosition=3}
TeamStatistic{teamName='Everton', numberWin=1, numberDraw=0, numberLoss=0, matchesPlayed=1, points=3, goalsScored=1, goalsConceded=0, tablePosition=4}
TeamStatistic{teamName='Burnley', numberWin=1, numberDraw=0, numberLoss=0, matchesPlayed=1, points=3, goalsScored=3, goalsConceded=2, tablePosition=5}
TeamStatistic{teamName='Southampton', numberWin=0, numberDraw=1, numberLoss=0, matchesPlayed=1, points=1, goalsScored=0, goalsConceded=0, tablePosition=6}
TeamStatistic{teamName='Swansea', numberWin=0, numberDraw=1, numberLoss=0, matchesPlayed=1, points=1, goalsScored=0, goalsConceded=0, tablePosition=7}
TeamStatistic{teamName='Stoke', numberWin=0, numberDraw=0, numberLoss=1, matchesPlayed=1, points=0, goalsScored=0, goalsConceded=1, tablePosition=8}
TeamStatistic{teamName='Crystal Palace', numberWin=0, numberDraw=0, numberLoss=1, matchesPlayed=1, points=0, goalsScored=0, goalsConceded=3, tablePosition=9}
TeamStatistic{teamName='Brighton', numberWin=0, numberDraw=0, numberLoss=1, matchesPlayed=1, points=0, goalsScored=0, goalsConceded=2, tablePosition=10}
TeamStatistic{teamName='Chelsea', numberWin=0, numberDraw=0, numberLoss=2, matchesPlayed=2, points=0, goalsScored=2, goalsConceded=5, tablePosition=11}
TeamStatistic{teamName='Leicester', numberWin=0, numberDraw=0, numberLoss=2, matchesPlayed=2, points=0, goalsScored=4, goalsConceded=6, tablePosition=12}
I have done a Java program to add flight details and i want to perform sort operation based on flight names using comparator . But i get compilation error in FLight.java on this line....Collections.sort(flightObject,new Compareid());
package com.flight;
import java.util.*;
public class Flight
{
public String flightName;
public String source;
public String destination;
public int flightId;
public int flightFare;
public Flight(String flightName,int flightId,String source, String destination, int flightFare)
{
super();
this.flightName = flightName;
this.source = source;
this.destination = destination;
this.flightId = flightId;
this.flightFare = flightFare;
}
public String getFlightName()
{
return flightName;
}
public int getFlightId()
{
return flightId;
}
public String getSource() {
return source;
}
public String getDestination() {
return destination;
}
public int getFlightFare() {
return flightFare;
}
public boolean searchFlight(int originalFlightId, int newFlightId )
{
if(originalFlightId==newFlightId)
{
return true;
}
else
{
return false;
}
}
class Compareid implements Comparator<Flight>{
public int compare(Flight flightObject1,Flight flightObject2){
return (flightObject1.flightName.compareTo (flightObject2.flightName));
}
}
}
This is the main class.............
package com.main;
import com.flight.*;
import java.util.*;
public class HighFly
{
public static void main(String[] args)
{
Flight indigo=new Flight("Indigo",1000,"Trivandrum","Dubai",25000);
Flight emirates=new Flight("Emirates",1001,"Dehi","US",30000);
Flight airindia=new Flight("Air India",1002,"Kochi","Malaysia",29000);
ArrayList<Flight>flightList=new ArrayList<Flight>();
flightList.add(indigo);
flightList.add(emirates);
flightList.add(airindia);
System.out.println("FlightId FlightName Source Destination Fare");
for(Flight flightObject:flightList)
{
System.out.print(flightObject.getFlightId());
System.out.print("\t\t"+flightObject.getFlightName());
System.out.print("\t\t"+flightObject.getSource());
System.out.print("\t\t"+flightObject.getDestination());
System.out.println("\t\t"+flightObject.getFlightFare());
}
//SEARCHING FLIGHT EXISTS
System.out.println("Enter flight id");
Scanner scanner= new Scanner(System.in);
int checkFlightId=scanner.nextInt();
for(Flight flightObject:flightList)
{
if(flightObject.searchFlight(flightObject.flightId,checkFlightId))
{
System.out.println("Success");
}
else
{
System.out.println("Not success");
}
}
//*********sorting***********
for(Flight flightObject:flightList)
{
Collections.sort(flightObject,new Compareid());
}
System.out.println(" after sorting ");
System.out.println("FlightId FlightName Source Destination Fare");
for(Flight flightObject:flightList)
{
System.out.print(flightObject.getFlightId());
System.out.print("\t\t"+flightObject.getFlightName());
System.out.print("\t\t"+flightObject.getSource());
System.out.print("\t\t"+flightObject.getDestination());
System.out.println("\t\t"+flightObject.getFlightFare());
}
}
}
Help me solve this issue. I want to implement this in arraylist. Please find the error in the following code.
Moved Comparator out of the Flight Class
import java.util.Comparator;
class Compareid implements Comparator<Flight> {
public int compare(Flight flightObject1, Flight flightObject2) {
return (flightObject1.flightName.compareTo(flightObject2.flightName));
}
}
Collections.sort(flightList, new Compareid()); // Need to pass the list instead of individual Objects refer to the HighFly Class below.
import java.util.*;
public class HighFly {
public static void main(String[] args) {
Flight indigo = new Flight("Indigo", 1000, "Trivandrum", "Dubai", 25000);
Flight emirates = new Flight("Emirates", 1001, "Dehi", "US", 30000);
Flight airindia = new Flight("Air India", 1002, "Kochi", "Malaysia",
29000);
ArrayList<Flight> flightList = new ArrayList<Flight>();
flightList.add(indigo);
flightList.add(emirates);
flightList.add(airindia);
System.out
.println("FlightId FlightName Source Destination Fare");
for (Flight flightObject : flightList) {
System.out.print(flightObject.getFlightId());
System.out.print("\t\t" + flightObject.getFlightName());
System.out.print("\t\t" + flightObject.getSource());
System.out.print("\t\t" + flightObject.getDestination());
System.out.println("\t\t" + flightObject.getFlightFare());
}
// SEARCHING FLIGHT EXISTS
System.out.println("Enter flight id");
Scanner scanner = new Scanner(System.in);
int checkFlightId = scanner.nextInt();
for (Flight flightObject : flightList) {
if (flightObject.searchFlight(flightObject.flightId, checkFlightId)) {
System.out.println("Success");
} else {
System.out.println("Not success");
}
}
// *********sorting***********
for (Flight flightObject : flightList) {
Collections.sort(flightList, new Compareid());
}
System.out.println(" after sorting ");
System.out
.println("FlightId FlightName Source Destination Fare");
for (Flight flightObject : flightList) {
System.out.print(flightObject.getFlightId());
System.out.print("\t\t" + flightObject.getFlightName());
System.out.print("\t\t" + flightObject.getSource());
System.out.print("\t\t" + flightObject.getDestination());
System.out.println("\t\t" + flightObject.getFlightFare());
}
}
}
And the updated fligh class is
public class Flight {
public String flightName;
public String source;
public String destination;
public int flightId;
public int flightFare;
public Flight(String flightName, int flightId, String source,
String destination, int flightFare) {
super();
this.flightName = flightName;
this.source = source;
this.destination = destination;
this.flightId = flightId;
this.flightFare = flightFare;
}
public String getFlightName() {
return flightName;
}
public int getFlightId() {
return flightId;
}
public String getSource() {
return source;
}
public String getDestination() {
return destination;
}
public int getFlightFare() {
return flightFare;
}
public boolean searchFlight(int originalFlightId, int newFlightId) {
if (originalFlightId == newFlightId)
{
return true;
} else {
return false;
}
}
}
I need to register the order of each customer
The waiter can only deliver orders after write down all requests of your customers.
Customer must wait until the request is delivered
I can not synchronize the client actions with the waiter
I need synchronize each action from my objects Customer and Waiter
Customer has 1 order
Waiter has N customers
The sequence of actions to be synchronized was implemented in the "run" method of each thread
package room;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Customer extends Thread {
private Random random;
private int id;
private static int ID;
private Order order;
private Waiter waiter;
public Customer(Waiter garcom) {
this.random = new Random();
this.id = ID + 1;
Customer.ID++;
this.waiter = garcom;
}
#Override
public void run() {
orderRequest();
waitOrder();
receiveRequest();
consumer();
}
public synchronized void orderRequest() {
synchronized (this.order) {
int r = random.nextInt(3);
switch (r) {
case 0:
this.order.setOrder("Food");
break;
case 1:
this.order.setOrder("Drink");
break;
default:
this.order.setOrder("Help");
break;
}
System.out.println(this.toString() + " request " + this.order.getOrder() + "to " + this.waiter.toString());
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public synchronized void receiveRequest() {
synchronized (this.order) {
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(this + " has received " + this.order + " from " + this.waiter);
}
}
private void waitOrder() {
synchronized (this.order) {
System.out.println(this + " consumer " + this.order);
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public synchronized void consumer() {
synchronized (this.order) {
System.out.println(this + " was consumed " + this.order);
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void setOrder(Order order) {
this.order = order;
}
public Order getOrder() {
return order;
}
#Override
public String toString() {
return "Customer: " + id;
}
}
package room;
public class Order {
private int orderNumber;
private static int ORDER_NUMBER = 0;
private Customer customer;
private String order;
public Order(Customer c) {
this.customer = c;
this.orderNumber = ORDER_NUMBER + 1;
this.customer.setOrder(this);
Order.ORDER_NUMBER++;
}
public String getOrder() {
return order;
}
public int getOrderNumber() {
return orderNumber;
}
public void setOrder(String order) {
this.order = order;
}
public Customer getCustomer() {
return customer;
}
#Override
public String toString() {
return "Order: " + order + " Nº " + orderNumber;
}
}
package room;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Waiter extends Thread {
private Saloon saloon;
private int id;
private static int ID = 0;
private List<Order> orders;
public Waiter(Saloon bar) {
this.saloon = bar;
this.id = ID + 1;
Waiter.ID++;
this.orders = new ArrayList<>();
}
#Override
public void run() {
while (saloon.isOpen()) {
registerOrder();
deliveryRequest();
saloon.round();
}
}
public synchronized void registerOrder() {
for (Order order : orders) {
synchronized (order) {
order.notify();
try {
order.wait();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println(this.toString() + " "
+ "record " + order.toString()
+ " to " + order.getCustomer());
}
}
}
public synchronized void deliveryRequest() {
for (Order order : orders) {
synchronized (order) {
order.notify();
try {
order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Waiter.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(this.toString() + " "
+ "delivered " + order.toString()
+ " to " + order.getCustomer());
}
}
}
public synchronized void recordOrder(Order order) {
synchronized (orders) {
this.orders.add(order);
}
}
public List<Order> getOrders() {
return orders;
}
public Saloon getSaloon() {
return saloon;
}
#Override
public String toString() {
return "Waiter: " + id;
}
}
package room;
import java.util.ArrayList;
import java.util.List;
public class Saloon {
private int maxRound;
private int numGarcons;
private volatile int round;
private int capacity;
private int customerCount;
private final List<Waiter> waiters;
public Saloon() {
this.waiters = new ArrayList<>();
this.round = 1;
}
public Saloon(int customerCount, int waiterCount,
int capacity, int rounds) {
this();
this.numGarcons = waiterCount;
this.customerCount = customerCount;
this.capacity = capacity;
this.maxRound = rounds;
}
/**
* Should it be call each round
*/
public void openBar() {
this.capacity = this.customerCount / this.capacity;
System.out.println("Round " + this.round);
for (int i = 0; i < this.numGarcons; i++) {
//Create a waiter
Waiter g = new Waiter(this);
for (int j = 0; j < this.capacity; j++) {
//create customer
Customer c = new Customer(g);
//an order
Order p = new Order(c);
//register order
g.recordOrder(p);
//call thread client
c.start();
}
//waiter serves one client at a time
g.start();
this.waiters.add(g);
}
}
public boolean isOpen() {
if (this.round < this.maxRound) {
return true;
}
return false;
}
public void round() {
this.round++;
}
}
Okay I must say I enjoyed the challenge... But I have figured this out. I should note that I attempted your original maxRounds and though it works there is a bug where 1 extra customer can make it through the queue. NOTE: I am do not claim this is the absolute best way to do this... nor necessarily the most elegant but it should point you towards the right direction.
I would suggest reading about BlockingQueues and classes the extend it.
Main call to the saloon:
public static void main(String[] args) {
Saloon saloon = new Saloon(100, 4, 50);
saloon.openBar();
}
Saloon Class:
package room;
import java.util.ArrayList;
import java.util.List;
public class Saloon {
private volatile static int round;
private static int maxRound;
private int numWaiters;
private final List<Waiter> waiters;
private int customerMax; // current implementation doesn't need this but you could if you wanted
private volatile static boolean isOpen;
private OrderQueue<Order> orderQueue; // This is the creation of the queue
public Saloon() {
this.waiters = new ArrayList<>();
Saloon.round = 1;
}
public Saloon(int customerMax, int numWaiters, int maxRounds) {
this();
this.customerMax = customerMax;
this.numWaiters = numWaiters;
this.orderQueue = new OrderQueue<Order>(numWaiters);
Saloon.maxRound = maxRounds;
}
/**
* Should it be call each round
*/
public void openBar() {
System.out.println("Round " + round);
isOpen = true;
// Create all waiters at once outside the loop
for (int i = 0; i < this.numWaiters; i++) {
waiters.add(new Waiter(i + 1, orderQueue));
waiters.get(i).start();
}
int customersServed = 1; // Generating the id number here is a better choice IMO
while(isOpen) {
for (Waiter waiter : waiters) {
if (round >= maxRound) {
closeBar();
}
if (waiter.isAvailable() && !waiter.isClockedOut()) {
// create customer
Customer customer = new Customer(customersServed++, waiter, orderQueue);
customer.start();
}
}
}
}
/**
* A simple implementation to close the bar
*/
public void closeBar() {
isOpen = false; // ends the loop
int waitersFinished = 0; // used to check if all waiters stopped serving
while (waitersFinished < numWaiters) {
for (Waiter waiter : waiters) {
if (waiter.isAvailable()) {
synchronized (orderQueue) {
// if nothing is currently in the queue for the waiters
if (orderQueue.isEmpty()) {
orderQueue.done(); // close the queue
orderQueue.notify(); // notify the queue
}
waiter.clockOut(); // clockout the waiter could use better implementation
waitersFinished++; // increment waiters finished
}
}
}
}
}
public static boolean isOpen() {
return isOpen;
}
// I would not recommend using this... this is the source of the glitch
public synchronized static void round() {
if (round <= maxRound) { // only if reached maxRounds
System.out.println("Round " + round);
round++;
}
}
}
OrderQueue Class:
package room;
import java.util.concurrent.ArrayBlockingQueue;
/**
*
* Note I did not create this.. tomasb did and I implemented it.
*
* #param <T>
*/
public class OrderQueue<T> extends ArrayBlockingQueue<T> {
private static final long serialVersionUID = 1L;
private boolean done = false;
/**
* creates an order queue with a max capacity.. orders that can be concurrently handled
* #param capacity
*/
public OrderQueue(int capacity) {
super(capacity);
}
/**
* closes the while loop ending this orderqueue
*/
public void done() {
done = true;
}
public boolean isDone() {
return done;
}
/**
* May return null if producer ends the production after consumer has
* entered the element-await state.
*/
public T take() throws InterruptedException {
T el;
while ((el = super.poll()) == null && !done) {
synchronized (this) {
wait();
}
}
return el;
}
}
Order Class:
package room;
public class Order {
private int orderNumber;
private static int ORDER_NUMBER = 0;
private String order;
public Order(int orderNumber) {
this.orderNumber = ORDER_NUMBER + 1;
this.orderNumber = orderNumber;
}
public String getOrder() {
return order;
}
public int getOrderNumber() {
return orderNumber;
}
public void setOrder(String order) {
this.order = order;
}
#Override
public String toString() {
return "Order: " + order + " Nº " + orderNumber;
}
}
Customer Class:
package room;
import java.util.Random;
public class Customer extends Thread {
private int id;
private int orderNumber = 1;
private Order order;
private Waiter waiter;
private OrderQueue<Order> orderQueue; // This provides an esay way to pass objects
public Customer(int id, Waiter waiter, OrderQueue<Order> orderQueue) {
this.id = id;
this.waiter = waiter;
this.orderQueue = orderQueue;
waiter.addCustomer(this);
System.out.println("Customer: " + id + " sat at a table!");
}
#Override
public void run() {
// Notice that wait has been removed. The orderQueue takes care of this.
orderRequest();
receiveRequest();
consumer();
System.out.println("Customer: " + id + " has left satisfied!");
}
public void orderRequest() {
// none of thie should be synchronized as it is local
order = new Order(orderNumber++);
Random random = new Random();
int r = random.nextInt(3);
switch (r) {
case 0:
order.setOrder("Food");
break;
case 1:
order.setOrder("Drink");
break;
default:
order.setOrder("Help");
break;
}
System.out.println(this.toString() + " request " + order.getOrder() + " to " + this.waiter.toString());
// only the call to the orderqueue is synchronized
try {
synchronized (orderQueue) {
orderQueue.put(order);
orderQueue.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void receiveRequest() {
System.out.println(this + " has received " + this.order + " from " + this.waiter);
}
public void consumer() {
System.out.println(this + " was consumed " + this.order);
}
#Override
public String toString() {
return "Customer: " + id;
}
}
And finally the Waiter Class:
package room;
public class Waiter extends Thread {
private int id;
private Order custOrder;
private Customer customer;
private volatile boolean isAvailable;
private volatile boolean clockOut;
private OrderQueue<Order> orderQueue; // The queue again
public Waiter(int id, OrderQueue<Order> orderQueue) {
this.id = id;
this.orderQueue = orderQueue;
System.out.println("Waiter " + id + " is ready to serve!");
}
#Override
public void run() {
isAvailable = true;
while (!orderQueue.isDone() && !clockOut) {
if (isAvailable) { // this waiter is ready for a task
registerOrder();
isAvailable = false;
synchronized (orderQueue) { // Synchronize this to the queue to prevent worse glitches
Saloon.round();
}
if (custOrder != null) { // error checking
System.out.println(this.toString() + " record " + custOrder.toString() + " to " + customer);
deliveryRequest();
} else {
isAvailable = true;
}
}
}
}
public synchronized void registerOrder() {
try {
custOrder = orderQueue.take(); // this is how you pull the order
} catch (InterruptedException e1) {
System.out.println(true);
}
}
public synchronized void deliveryRequest() {
System.out.println(this.toString() + " " + "delivered " + custOrder.toString() + " to " + customer);
isAvailable = true;
}
public void addCustomer(Customer customer) { // a easy way to add customers to the waiter after creation
this.customer = customer;
isAvailable = false;
}
public Order getOrder() {
return custOrder;
}
#Override
public String toString() {
return "Waiter: " + id;
}
public boolean isAvailable() {
return isAvailable;
}
public void clockOut() {
clockOut = true;
}
public boolean isClockedOut() {
return clockOut;
}
}
I have the following Scenario.
There is a restroom in a Building.
It will have 2 types[As of now] of toilet. MALE and FEMALE which is n in number.
If a group of People enters into a restroom.I want them to occupy maximum no of rooms as possible.
Assume there are 20 people entering into restroom at a time with the following combination
People 20
Male 10 Female 10
RestRoom Avaialbiltiy
MALE 2
FEMALE 1
And some people will take more time, so the next person have to wait in the queue.And male cannot enter into female toilet and vice-versa.
For the above scenario I have extended the ThreadpoolExecutor and add the Person one by one and check assign them as soon as toilet with match is avaialable.
So here is the MCVE for the example.I wanted to check if this is the correct way to handle condition in a ThreadPool
RestRoom.java
import java.util.HashMap;
import java.util.Map;
public enum RestRoom {
MALE,
FEMALE;//will extend for ex [Differently Abled]
public int maxInstance = 0;
public RestRoom withMaxInstance(int maxInstance) {
this.maxInstance = maxInstance;
return this;
}
public static int getTotalNoOfRestRooms() {
int count = 0;
for (RestRoom room : RestRoom.values()) {
count += room.maxInstance;
}
return count;
}
public static Map<RestRoom, Integer> getAvailabiltyAsMap() {
Map<RestRoom, Integer> avaialbilty = new HashMap<>();
for (RestRoom room : RestRoom.values()) {
avaialbilty.put(room, room.maxInstance);
}
return avaialbilty;
}
}
Person.java (Runnable)
import java.util.logging.Level;
import java.util.logging.Logger;
public class Person implements Runnable {
private final String name;
private final RestRoom gender;
private int second;
public Person(String name, RestRoom gender) {
this.name = name;
this.gender = gender;
}
public Person withTime(int second) {
this.second = second;
return this;
}
#Override
public void run() {
try {
System.out.println("Running " + name + " with " + gender);
Thread.sleep(second * 1000);
} catch (InterruptedException ex) {
Logger.getLogger(Person.class.getName()).log(Level.SEVERE, null, ex);
}
}
public String getName() {
return name;
}
public RestRoom getGender() {
return gender;
}
#Override
public String toString() {
return "Person{" + "name=" + name + ", gender=" + gender + '}';
}
}
CustomThreadPool.java
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CustomThreadPool extends ThreadPoolExecutor {
Map<RestRoom, Integer> avaialbilty = new HashMap<>();
LinkedBlockingDeque<Runnable> remaining = new LinkedBlockingDeque<>();
public CustomThreadPool(int corePoolSize, long keepAliveTime) {
super(corePoolSize, corePoolSize, keepAliveTime, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>());
avaialbilty = RestRoom.getAvailabiltyAsMap();
}
#Override
protected void afterExecute(Runnable runnable, Throwable throwable) {
avaialbilty.put(getRestRoomFor(runnable), avaialbilty.get(getRestRoomFor(runnable)) + 1);
for (int i = 0; i < remaining.size(); i++) {
execute(remaining.remove());
}
if (remaining.isEmpty()) {
shutdown();
}
}
#Override
public void execute(Runnable runnable) {
if (avaialbilty.get(getRestRoomFor(runnable)) > 0) {
avaialbilty.put(getRestRoomFor(runnable), avaialbilty.get(getRestRoomFor(runnable)) - 1);
super.execute(runnable);
} else {
remaining.add(runnable);
}
}
private RestRoom getRestRoomFor(Runnable runnable) {
return asPerson(runnable).getGender();
}
private Person asPerson(Runnable runnable) {
return (Person) runnable;
}
}
Test.java
public class Test {
public static void main(String[] args) {
RestRoom.MALE.withMaxInstance(3);
RestRoom.FEMALE.withMaxInstance(2);
CustomThreadPool threadPool = new CustomThreadPool(RestRoom.getTotalNoOfRestRooms(), 2);
for (int i = 0; i < 10; i++) {
threadPool.execute(new Person("M" + i, RestRoom.MALE).withTime(2));
threadPool.execute(new Person("F" + i, RestRoom.FEMALE).withTime(1));
}
}
}