I have an ArrayList(called filmes) in which one of the elements is another ArrayList(called actores), this actores is made out of names of actors that have the same movie id as the movie in filmes.
But every time it adds an actor to the actores ArrayList it overwrites the previous one there.
So when there's more than one actor for the same movie it just shows the last one on the file.
For example the expected output should be 6978 | Big Trouble in Little China | 30-05-1986 [Kurt Russel,Kim Cattrall] [Comedy] but instead it's printing 6978 | Big Trouble in Little China | 30-05-1986 [Kim Cattrall] [Comedy]
/*Actorsfile.txt (the last element is the movie id)
11701,Angelina Jolie,false,1995
6384,Keanu Reeves,true,603
7382,Carrie-Anne Moss,false,603
11701,Angelina Jolie,false,10428
6856,Kurt Russell,true,6978
2109,Kim Cattrall,false,6978*/
try{
File ficheiroA = new File(Actorsfile);
Scanner leitorFicheiroA = new Scanner(ficheiroA);
while (leitorFicheiroA.hasNextLine()) {
ArrayList<Actor> actores = new ArrayList<>();
Actor actor = new Actor("");
String linha = leitorFicheiroA.nextLine();
String dadosA[] = linha.split(",");
if (dadosA.length == 4) {
int idFilmeA = Integer.parseInt(dadosA[3]);
int pos = index(idFilmeA, ids);
if (idFilmeA == ids[pos]) {
actor.nome = (dadosA[1]);
actores.add(actor);
filmes.get(pos).mudarActores(actores);
}
}
}
}
catch(FileNotFoundException e) {
String mensagem = "Erro: o ficheiro " + ficheiroActores + " nao foi encontrado.";
System.out.println(mensagem);
}
Actor Class:
public class Actor {
String nome;
String genero;
public Actor(String nome) {
this.nome = nome;
}
public String toString () {
return nome;
}
}
Filme Class:
public class Filme {
int id;
String titulo;
ArrayList<Actor> actores= new ArrayList<>();
ArrayList<GeneroCinematografico> generos= new ArrayList<>();
String dia,mes,ano;
public Filme(int id, String titulo,ArrayList<Actor> actores, ArrayList<GeneroCinematografico> generos,String ano,String mes,String dia) {
this.id = id;
this.titulo = titulo;
this.actores = actores;
this.generos = generos;
this.ano=ano;
this.mes=mes;
this.dia=dia;
}
public void mudarId(int id) {
this.id = id;
}
public void mudarTitulo(String titulo) {
this.titulo = titulo;
}
public void mudarActores(ArrayList<Actor> actores) {
this.actores =actores;
}
public void mudarGeneros(ArrayList<GeneroCinematografico> generos) {
this.generos = generos;
}
public String toString() {
return id + " | " + titulo + " | " + dia + "-" + mes + "-" + ano +" "+ actores +" "+ generos;
}
}
Edit:
I've done it a different way and now it's working well in the first filme, but the next are as a null.
Recent output it's 603 | The Matrix | 30-03-1999 [Keanu Reeves, Carrie-Anne Moss] [Science Fiction], 10428 | Hackers | 14-09-1995 null [Action] but the expected is 603 | The Matrix | 30-03-1999 [Keanu Reeves, Carrie-Anne Moss] [Science Fiction], 10428 | Hackers | 14-09-1995 [Angelina Jolie] [Action]. I would be greatful if I could do it this way, without using maps.
try{
File ficheiroA = new File(ficheiroActores);
Scanner leitorFicheiroA = new Scanner(ficheiroA);
i=0;
while (i<ids.length-1) {
int idFilme=ids[i];
ArrayList<Actor> actores = new ArrayList<>();
while (leitorFicheiroA.hasNextLine()) {
Actor actor;
String linha = leitorFicheiroA.nextLine();
String dadosA[] = linha.split(",");
int idFilmeA = Integer.parseInt(dadosA[3]);
//int pos = index(idFilmeA, ids);
if (dadosA.length == 4) {
if (idFilmeA == idFilme) {
actor =new Actor (dadosA[1]);
actores.add(actor);
}
}
filmes.get(i).mudarActores(actores);
}
i++;
}
You are declaring a new ArrayList inside the while, so it is resetting each iteration. What you want to do is to take the creation of the ArrayList outside the while. Instead of:
while (leitorFicheiroA.hasNextLine()) {
ArrayList<Actor> actores = new ArrayList<>();
You want:
ArrayList<Actor> actores = new ArrayList<>();
while (leitorFicheiroA.hasNextLine()) {
And then you call filmes.get(pos).mudarActores(actores); when the while finishes.
Edit:
To solve the problem you are commenting, I would remove filmes.get(pos).mudarActores(actores); from where it is now. Note that you have all the information you need in each Actor. So,I would leave the logic of the current while as is now, maybe put it in a function readActoresFromFile(), returning the List of Actores. Then I would iterate over each element of the List and put them on a Map which has the filmId as Key and the list of Actors of that film as values. Tell me if you need help with that.
Related
I'm making a reservation feature for my events, and I can successfully add the attendee, however when I want to display the details for every attendee, it gives me a ArrayIndexOutOfBounds exception error, which I'm not quite sure how to fix.
Main.java
private static Scanner sc = new Scanner(System.in);
private static int eventCreationLimit = 5;
private static Event[] events = new Event[eventCreationLimit];
private static int eventsCreated;
public static void main(String args[]) {
String input;
// Main menu.
do {
System.out.println("\n~ BOOKING SYSTEM ~");
System.out.println("------------------");
System.out.println("A. Schedule an Event");
System.out.println("B. Add an Attendee");
System.out.println("C. View Reservations");
System.out.println("X. Exit\n");
System.out.print("Select an option: ");
input = sc.nextLine();
switch (input.toUpperCase()) {
case "A":
scheduleAnEvent();
break;
case "B":
addAttendee();
break;
case "C":
displayReservations();
break;
case "X":
System.out.println("INFO: You have exited the booking system.");
break;
default:
System.out.println("ERROR: Invalid input!");
}
} while (!input.equalsIgnoreCase("X"));
}
private static void scheduleAnEvent() {
System.out.println("\n~ SCHEDULE A EVENT ~");
System.out.println("--------------------");
System.out.print("Enter the ID: ");
String ID = sc.nextLine();
...
System.out.print("Enter the attendee limit: ");
int attendeeLimit = Integer.parseInt(sc.nextLine());
// Add the new event to the array.
events[eventsCreated++] = new Event(ID, ..., attendeeLimit, attendeeLimit, ...);
for (int i = 0; i < eventsCreated; i++)
// Set the places available for the specific event being created to subtract it later when an attendee is added.
if (ID.equals(events[i].getID()))
// The number of places available left in the event can be displayed by going to "B. View All Events".
events[i].setPlacesAvailable(attendeeLimit);
// Give the user a confirmation message.
System.out.println("\nINFO: Sucessfully created Event: " + ID + ".");
}
private static void addAttendee() {
Event event = null;
boolean result = false;
System.out.println("\n~ ADD AN ATTENDEE ~");
System.out.println("-------------------");
System.out.print("Enter attendee name: ");
String name = sc.nextLine();
System.out.print("Enter attendee phone number: ");
String phone = sc.nextLine();
Attendee a = new Attendee(name, phone);
System.out.print("Enter event ID: ");
String eventID = sc.nextLine();
// Check if the given ID matches an event.
for (int i = 0; i < eventsCreated; i++)
if (events[i].getID().equals(eventID))
event = events[i];
if (event != null) {
if (event.getID().equals(eventID)) {
result = ((Event) event).addAttendee(a);
if (result) {
// If the event has enough room, then add the attendee.
System.out.println("INFO: Attendee successfully added to Event: " + eventID + ".");
displayReservations();
}
else
// If the event is full, then the attendee will not be added.
System.out.println("ERROR: The Event: " + eventID + " is full, the attendee could not be added.");
} else
System.out.println("ERROR: The given ID does not match any existing event.");
} else
System.out.println("ERROR: The event was not found.");
}
private static void displayReservations() {
System.out.println("\n~ RESERVATIONS ~");
System.out.println("----------------");
String pattern = "%-18s %-18s %-22s %-1s\n";
System.out.printf(pattern, "NAME", "PHONE", "EVENT ID", "FEE");
System.out.println("----------------------------------------------------------------");
// Display all reservations for events.
for (int i = 0; i < events[i].getAttendeeCount(); i++)
events[i].displayReservations();
}
Event.java
...
private String ID;
private int attendeeLimit;
private int attendeeCount;
private int placesAvailable;
private Attendee[] a = new Attendee[attendeeCount];
public Demonstration(..., String ID, int placesAvailable, int attendeeLimit, ...) {
this.ID = ID;
this.placesAvailable = placesAvailable;
this.attendeeLimit = attendeeLimit;
}
public String getID() { return this.ID; }
public int getPlacesAvailable() { return this.placesAvailable; }
public int getAttendeeLimit() { return this.attendeeLimit; }
public void setPlacesAvailable(int placesAvailable) { this.placesAvailable = placesAvailable; }
public boolean addAttendee(Attendee at) {
// Proceed to add the attendee if there is enough room.
if (attendeeCount <= placesAvailable) {
attendeeCount++;
// Decrease the number of places available by one.
setPlacesAvailable(placesAvailable - 1);
return true;
}
return false;
}
public void displayReservations() {
System.out.println("ID: " + ID);
if (attendeeCount > 0)
for (int i = 0; i < attendeeCount; i++)
a[i].attendeeDetails();
}
Attendee.java
private String name;
private String phone;
public Attendee(String name, String phone) {
this.name = name;
this.phone = phone;
}
public String getName() { return this.name; }
public String getPhone() { return this.phone; }
public void attendeeDetails() {
System.out.println("Name: " + name);
System.out.println("Phone: " + phone);
}
The above code gives me a ArrayIndexOutOfBoundsException error in the displayReservations() method (a[i].attendeeDetails()) whenever I try to add an attendee to an event.
Problem: How do I display all reservation details for all events? Thank you for your help!
EDIT
The error:
Index 0 out of bounds for length 0.
There are a couple of issues with your code:
You are maintaining an attendeeCount separately than the size of the Attendee[], but in your addAttendee() method, you never actually add the new Attendee to the array
Because Attendee[] is an array, it can't grow larger than the size when first initialized. If you want to use an array, instead of an ArrayList that can grow dynamically, you need to initialize the array to the maximum size: placesAvailable:
So, my recommendation would be to switch from using an array to an ArrayList by importing java.util.Arraylist, changing the declaration of the Attendee[] to an ArrayList, and updating the rest of the Event.java code to use the ArrayList, as well as making sure you add the new Attendee in the addAttendee() method. Finally, you don't need to maintain the attendee count separately, just ask the attendees ArrayList it's current size.
Event.java
...
import java.util.*; //You can import all java.util classes
private String ID;
private int attendeeLimit;
private int placesAvailable;
private List<Attendee> attendees = new ArrayList<>(); //Initialize the attendees ArrayList
public Demonstration(..., String ID, int placesAvailable, int attendeeLimit, ...) {
this.ID = ID;
this.placesAvailable = placesAvailable;
this.attendeeLimit = attendeeLimit;
}
public String getID() { return this.ID; }
public int getPlacesAvailable() { return this.placesAvailable; }
public int getAttendeeLimit() { return this.attendeeLimit; }
public void setPlacesAvailable(int placesAvailable) { this.placesAvailable = placesAvailable; }
public boolean addAttendee(Attendee at) {
// Proceed to add the attendee if there is enough room.
if (attendeeCount <= placesAvailable) {
attendees.add(at); //Make sure you add the new Attendee to the list
// Decrease the number of places available by one.
setPlacesAvailable(placesAvailable - 1);
return true;
}
return false;
}
public void displayReservations() {
System.out.println("ID: " + ID);
int attendeeCount = attendees.size(); //Calculate the number of Attendees
if (attendeeCount > 0)
for (int i = 0; i < attendeeCount; i++)
attendees.get(i).attendeeDetails();
}
attendeCount does not have a value as at the time you creating the Array "a". For what you are trying to achieve, I suggest:
i. Use an Arraylist.
ii. Initialize you array in the constructor to attendeLimit.
If possible, I also suggest you use parameter methods where neccessary.
First off - please forgive me, for I am an amateur.
For a project, I am taking an excel file as input containing a list of kittens and I want to output the addresses these kittens have been found at.
I have implemented the code so that a kitten is an object with a name, ID, and notes (kitten was assigned these attributes from evaluating each cell in the excel doc). The notes section contains info about where the kitten was found.
Excel document:
name | ID | Notes
--------------------
Kit | 5 | Great animal! Haha! Found at 1234 east
| | street. Incredibly ugly.
---------------------
Kat | 2 | Wow, what a charmer. from location 3456
| | Dusk road
.
.
.
Currently, my program converts the excel doc to a string and prints the entire 'Notes' section for each kitten. I want it to extract the address (trying to get as many of the addresses as possible) from the rest of the string, so the output would look something like this:
1234 east street, 3456 Dusk Road, ...
All I could find online was about String delims, etc, but I am not sure how to start thinking about extracting specific phrases from a long varied string. Is there some way to record info at some key word, like "Found at" or "from location", and then stop at a period?
Would it be easier not to convert each address to one long string, but instead, print out the extracted address for each kitten?
My Code (for reference):
public class Kitten {
private String name;
private String animalID;
private String addressFound;
public Kitten() {
super();
this.name = name;
this.animalID = animalID;
this.addressFound = addressFound;
}
//getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAnimalID() {
return animalID;
}
public void setAnimalID(String animalID) {
this.animalID = animalID;
}
public String getAddress() {
return addressFound;
}
public void setAddress(String addressFound) {
this.addressFound = addressFound;
}
}
INPUT: excel file with kitten info. Prints the "Notes" section for
each kitten
public class ReadExcel {
public void printer() {
try {
FileInputStream kittenFile = new FileInputStream(new
File("./IntakeNotesSimple.xlsx"));
XSSFWorkbook wb = new XSSFWorkbook(kittenFile);
XSSFSheet sheet = wb.getSheetAt(0);
ArrayList<Kitten> kittenList = new ArrayList<>();
for (int i= sheet.getFirstRowNum() + 1; i<= sheet.getLastRowNum();
i++) {
Kitten k = new Kitten();
Row r = sheet.getRow(i);
for (int j = r.getFirstCellNum(); j<= r.getLastCellNum(); j++)
{
Cell c = r.getCell(j);
if (j==0) {
k.setName(c.getStringCellValue());
}
if (j==1) {
k.setAnimalID(c.getStringCellValue());
}
if (j==2 && (c != null)) {
k.setAddress(c.getStringCellValue());
}
}
kittenList.add(k);
}
for (Kitten kit: kittenList) {
System.out.println(kit.getAddress() +"\n" +);
}
wb.close();
}
catch(Exception e) {
e.printStackTrace();
}
}
}
public class PrintOut {
public static void main(String[] args) throws FileNotFoundException {
ReadExcel addresses = new ReadExcel();
addresses.printer();
}
}
Let's say you have a list of words that will give you the start of the address (practically it won't there are so many possibilities, but let's imagine it as you suggest this would work in your OP).
The string you search in will start with some characters, then either "found at" or "from location" and it will end at the next , . ! or ? character. Finally some last part will contain some other characters.
The solution you should be using here is Regex, aka best pattern matching tool you could find. The regex for the pattern described above would be :
^.*?(found at|from location) (.*?)([\.,!?].*+|)$
This regex is not that easy so we might not get into details, I'd better link you to some visual tool for this regex : https://regex101.com/r/q1w428/1
So now, how to use it within java app ?
private static final String KITTEN_PATTERN_STRING = "^.*?(found at|from location) (.*?)([\\.,!?].*+|)$";
private static final Pattern KITTEN_PATTERN = Pattern.compile(KITTEN_PATTERN_STRING);
public String extractKittenAddress(String kittenString) {
Matcher m = KITTEN_PATTERN.matcher(kittenString);
if(m.matches())
return m.group(2);
return null;
}
And there you go!
I assumed that you have a string contains some text and address. And your delimiter word is :
Found at
So you can split your text and extract the address while iterating your data as below :
public class Main {
public static void main(String[]args) throws JsonProcessingException {
String textContaintsAddress = "Great animal! Haha! Found at 1234 east street. Incredibly ugly.";
String address[] = textContaintsAddress.split("Found at");
if (address.length > 1) {
System.out.println(address[1].trim());
}else{
System.out.println(textContaintsAddress);;
}
}
}
It prints :
1234 east street. Incredibly ugly.
Edit your code as below :
public class ReadExcel {
public void printer() {
try {
FileInputStream kittenFile = new FileInputStream(new
File("./IntakeNotesSimple.xlsx"));
XSSFWorkbook wb = new XSSFWorkbook(kittenFile);
XSSFSheet sheet = wb.getSheetAt(0);
ArrayList<Kitten> kittenList = new ArrayList<>();
for (int i= sheet.getFirstRowNum() + 1; i<= sheet.getLastRowNum();
i++) {
Kitten k = new Kitten();
Row r = sheet.getRow(i);
for (int j = r.getFirstCellNum(); j<= r.getLastCellNum(); j++)
{
Cell c = r.getCell(j);
if (j==0) {
k.setName(c.getStringCellValue());
}
if (j==1) {
k.setAnimalID(c.getStringCellValue());
}
if (j==2 && (c != null)) {
// here we add the logic
String textContaintsAddress = c.getStringCellValue();
String address[] = textContaintsAddress.split("Found at");
if (address.length > 1) {
k.setAddress(address[1].trim());
}else{
k.setAddress(textContaintsAddress);;
}
}
}
kittenList.add(k);
}
for (Kitten kit: kittenList) {
System.out.println(kit.getAddress() +"\n" +);
}
wb.close();
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Is there a way to "extract" individual strings from an ArrayList?
I have stored strings in an ArrayList and want to print them to the console.
I know that I can use a for-loop but it isn't quite that simple. I'm trying to create a column based print and I use a method (Created by "CandiedOrange" here on stack overflow) that takes strings separated by commas as input.
What it basically does is; It creates column spacing based on the length of strings in each column. (All credit to "CandiedOrange")
List<List<String>> lines = new ArrayList<>();
List<Integer> maxLengths = new ArrayList<>();
int numColumns = -1;
public Columns addLine(String... line) {
if (numColumns == -1){
numColumns = line.length;
for(int i = 0; i < numColumns; i++) {
maxLengths.add(0);
}
}
if (numColumns != line.length) {
throw new IllegalArgumentException();
}
for(int i = 0; i < numColumns; i++) {
maxLengths.set( i, Math.max( maxLengths.get(i), line[i].length() ) );
}
lines.add( Arrays.asList(line) );
return this;
}
The number of columns I want to print is unknown during compile time because the user enters the number of columns 1-5 during run time. So I figured I could use ArrayLists for the rows and use the addLine() method with each of the arraylists for the rows.
If there Is a better way of solving this, I'd be more than happy to know.
EDIT:
From the start:
I'm creating a Yahtzee game with 1-5 players. Each Player is defined by instances of the class "Player"
public class Player {
private String name;
private int ones;
private int twos;
private int threes;
private int fours;
private int fives;
private int sixes;
private int threeofakind;
private int fourofakind;
private int fullhouse;
private int smallstraight;
private int largestraight;
private int chance;
private int yahtzee;
private int totalscore;
public int getOnes() {
return ones;
}
public void setOnes(int ones) {
this.ones = ones;
}
public int getTwos() {
return twos;
}
public void setTwos(int twos) {
this.twos = twos;
}
public int getThrees() {
return threes;
}
public void setThrees(int threes) {
this.threes = threes;
}
public int getFours() {
return fours;
}
public void setFours(int fours) {
this.fours = fours;
}
public int getFives() {
return fives;
}
public void setFives(int fives) {
this.fives = fives;
}
public int getSixes() {
return sixes;
}
public void setSixes(int sixes) {
this.sixes = sixes;
}
public int getThreeofakind() {
return threeofakind;
}
public void setThreeofakind(int threeofakind) {
this.threeofakind = threeofakind;
}
public int getFourofakind() {
return fourofakind;
}
public void setFourofakind(int fourofakind) {
this.fourofakind = fourofakind;
}
public int getFullhouse() {
return fullhouse;
}
public void setFullhouse(int fullhouse) {
this.fullhouse = fullhouse;
}
public int getSmallstraight() {
return smallstraight;
}
public void setSmallstraight(int smallstraight) {
this.smallstraight = smallstraight;
}
public int getLargestraight() {
return largestraight;
}
public void setLargestraight(int largestraight) {
this.largestraight = largestraight;
}
public int getChance() {
return chance;
}
public void setChance(int chance) {
this.chance = chance;
}
public int getYahtzee() {
return yahtzee;
}
public void setYahtzee(int yahtzee) {
this.yahtzee = yahtzee;
}
public int getTotalscore() {
return totalscore;
}
public void setTotalscore(int totalscore) {
this.totalscore = totalscore;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I'm implementing MVC structure (to the best of my ability) which means that I have a View class with a method to display the main console column scoreboard. (Method unfinished)
public void displayMainScoreBoard(ArrayList<Player> playerList) {
Columns col = new Columns(); //Instance of column class.
ArrayList<String> Name = new ArrayList<>();
ArrayList<Integer> Ones = new ArrayList<>();
ArrayList<Integer> Twos = new ArrayList<>();
ArrayList<Integer> Threes = new ArrayList<>();
ArrayList<Integer> Fours = new ArrayList<>();
ArrayList<Integer> Fives = new ArrayList<>();
ArrayList<Integer> Sixes = new ArrayList<>();
ArrayList<Integer> Threeofakind = new ArrayList<>();
ArrayList<Integer> Fourofakind = new ArrayList<>();
ArrayList<Integer> Fullhouse = new ArrayList<>();
ArrayList<Integer> Smallstraight = new ArrayList<>();
ArrayList<Integer> Largestraight = new ArrayList<>();
ArrayList<Integer> Chance = new ArrayList<>();
ArrayList<Integer> Yahtzee = new ArrayList<>();
ArrayList<Integer> Totalscore = new ArrayList<>();
for (Player p : playerList) { //For every player, append their category data.
Name.add(p.getName());
Ones.add(p.getOnes());
Twos.add(p.getTwos());
Threes.add(p.getThrees());
Fours.add(p.getFours());
Fives.add(p.getFives());
Sixes.add(p.getSixes());
Threeofakind.add(p.getThreeofakind());
Fourofakind.add(p.getFourofakind());
Fullhouse.add(p.getFullhouse());
Smallstraight.add(p.getSmallstraight());
Largestraight.add(p.getLargestraight());
Chance.add(p.getChance());
Yahtzee.add(p.getYahtzee());
Totalscore.add(p.getTotalscore());
}
}
And heres CandiedOrange's full Column class. (Again, I claim no rights to his code.)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Columns {
List<List<String>> lines = new ArrayList<>();
List<Integer> maxLengths = new ArrayList<>();
int numColumns = -1;
public Columns addLine(String... line) {
if (numColumns == -1){
numColumns = line.length;
for(int i = 0; i < numColumns; i++) {
maxLengths.add(0);
}
}
if (numColumns != line.length) {
throw new IllegalArgumentException();
}
for(int i = 0; i < numColumns; i++) {
maxLengths.set( i, Math.max( maxLengths.get(i), line[i].length() ) );
}
lines.add( Arrays.asList(line) );
return this;
}
public void print(){
System.out.println( toString() );
}
public String toString(){
String result = "";
for(List<String> line : lines) {
for(int i = 0; i < numColumns; i++) {
result += pad( line.get(i), maxLengths.get(i) + 1 );
}
result += System.lineSeparator();
}
return result;
}
private String pad(String word, int newLength){
while (word.length() < newLength) {
word += " ";
}
return word;
}
}
How can I pass the Strings of my ArrayLists in my view to the addLine() Method?
I believe you should not be using that Columns class at all.
Most of your lists are numbers rather than strings. Numbers are best displayed right-justified. And the only string you have in each of the rows you want to display is the player name.
So instead of copying all the data to various lists, and assuming that for most of the numbers you have a reasonable width that they will not pass (4 digits? 6 digits?), then your task becomes:
Find the longest name in the list
Display each player such that the name is padded to accomodate the longest name found.
You could add these as methods to the Player class, so finding the maximal name length of a given list of players:
public static int maxNameLength( List<? extends Player> players ) {
int maxLength = 0;
for ( Player player : players ) {
int currLength = player.getName().length();
if ( currLength > maxLength ) {
maxLength = currLength;
}
}
return maxLength;
}
Now, displaying the current player in a properly padded way can be done using String.format, which uses a Formatter.
For the sake of brevity, suppose I just want to display the name, Yahtzee and total score. You'll have a method like this in Player:
public String getScoreLine( int maxLength ) {
String format = "%-" + maxLength + "s %6d %6d";
return String.format( format, getName(), getYahtzee(), getTotalscore() );
}
What the first part does is create a left-justified field for the string. So if maxLength is, say, 20, the format will be %-20s %6d %6d. The numbers will be displayed right-justified in fields 6 characters wide, the name, left-justified and padded to 20 characters.
Now you can loop on your list and display it like:
int maxNameLength = Player.maxNameLength( playerList );
for ( Player p : playerList ) {
System.out.println( p.getScoreLine( maxNameLength ) );
}
Note: if you want to put the getScoreLine method in your View rather than in the Player class (since you are trying to do MVC), you will need to give it the player as a parameter.
...that takes strings separated by commas as input.
Technically, it takes an array (more in this Java tutorial on varargs). But Java lets you create that array automatically when calling it with discrete arguments.
Since it accepts an array, and you have an ArrayList, you can easily get an array to pass to it, using toArray(T[]):
List<List<String>> linesToAdd = /*...*/;
// ...
for (List<String> line : linesToAdd) {
addLine(line.toArray(new String[line.size()]));
}
That said, it would be trivial (and a good coding exercise) to modify addLine to accept List<String> directly.
I followed the advice not to use the column class, even though I'd like to have tried using it. I semi-hardcoded the solution.
playerList is the list of players present in the game. and categories is obtained from another class to check which categories are pickable when scoring. (Displayed as X when unavailable and O when pickable.)
public void displayMainScoreBoard(ArrayList<Player> playerList, ArrayList<Boolean> categories) {
List<String> Name = new ArrayList<>();
List<String> Ones = new ArrayList<>();
List<String> Twos = new ArrayList<>();
List<String> Threes = new ArrayList<>();
List<String> Fours = new ArrayList<>();
List<String> Fives = new ArrayList<>();
List<String> Sixes = new ArrayList<>();
List<String> Threeofakind = new ArrayList<>();
List<String> Fourofakind = new ArrayList<>();
List<String> Fullhouse = new ArrayList<>();
List<String> Smallstraight = new ArrayList<>();
List<String> Largestraight = new ArrayList<>();
List<String> Chance = new ArrayList<>();
List<String> Yahtzee = new ArrayList<>();
List<String> Totalscore = new ArrayList<>();
for (Player p : playerList) { //For every player, append their category data.
Name.add(p.getName());
Ones.add(String.valueOf(p.getOnes()));
Twos.add(String.valueOf(p.getTwos()));
Threes.add(String.valueOf(p.getThrees()));
Fours.add(String.valueOf(p.getFours()));
Fives.add(String.valueOf(p.getFives()));
Sixes.add(String.valueOf(p.getSixes()));
Threeofakind.add(String.valueOf(p.getThreeofakind()));
Fourofakind.add(String.valueOf(p.getFourofakind()));
Fullhouse.add(String.valueOf(p.getFullhouse()));
Smallstraight.add(String.valueOf(p.getSmallstraight()));
Largestraight.add(String.valueOf(p.getLargestraight()));
Chance.add(String.valueOf(p.getChance()));
Yahtzee.add(String.valueOf(p.getYahtzee()));
Totalscore.add(String.valueOf(p.getTotalscore()));
}
boolean checkones = categories.get(0); //Checkers for which categories are available to score in.
boolean checktwos = categories.get(1);
boolean checkthrees = categories.get(2);
boolean checkfours = categories.get(3);
boolean checkfives = categories.get(4);
boolean checksixes = categories.get(5);
boolean checkthreeofkind = categories.get(6);
boolean checkfourofkind = categories.get(7);
boolean checkfullhouse = categories.get(8);
boolean checksmallstraight = categories.get(9);
boolean checklargestraight = categories.get(10);
boolean checkchance = categories.get(11);
boolean checkyahtzee = categories.get(12);
System.out.println("| "+ "| | Name " + stringBuilder(Name));
System.out.println("|" + isPickable(checkones) + "|1. | Ones " + stringBuilder(Ones));
System.out.println("|" + isPickable(checktwos) + "|2. | Twos " + stringBuilder(Twos));
System.out.println("|" + isPickable(checkthrees) + "|3. | Threes " + stringBuilder(Threes));
System.out.println("|" + isPickable(checkfours) + "|4. | Fours " + stringBuilder(Fours));
System.out.println("|" + isPickable(checkfives) + "|5. | Fives " + stringBuilder(Fives));
System.out.println("|" + isPickable(checksixes) + "|6. | Sixes " + stringBuilder(Sixes));
System.out.println("|" + isPickable(checkthreeofkind) + "|7. | Three of a kind " + stringBuilder(Threeofakind));
System.out.println("|" + isPickable(checkfourofkind) + "|8. | Four of a kind " + stringBuilder(Fourofakind));
System.out.println("|" + isPickable(checkfullhouse) + "|9. | Full House " + stringBuilder(Fullhouse));
System.out.println("|" + isPickable(checksmallstraight) + "|1. | Small Straight " + stringBuilder(Smallstraight));
System.out.println("|" + isPickable(checklargestraight) + "|11.| Large Straight " + stringBuilder(Largestraight));
System.out.println("|" + isPickable(checkchance) + "|12.| Chance " + stringBuilder(Chance));
System.out.println("|" + isPickable(checkyahtzee) + "|13.| Yahtzee " + stringBuilder(Yahtzee));
System.out.println("| "+ "| | Total Score " + stringBuilder(Totalscore));
}
/*
* Method for creating the lines for the scoreboard.
*/
public String stringBuilder(List<String> arrIn) {
StringBuilder sb = new StringBuilder();
for (String s : arrIn) {
sb.append("|");
sb.append(s);
sb.append(pad(s));
}
return sb.toString();
}
/*
* Method for padding the spaces between columns.
*/
public String pad(String s) {
int space = 15;
int sLength = s.length();
String retPad = "";
int temp = space - sLength;
for (int i = 0; i <= temp ; i++) {
retPad += " ";
}
return retPad;
}
public String isPickable(boolean b) {
if (b == true) {
return "O";
}
else {
return "X";
}
}
Gives this print out:
| | | Name |one |two |three
|X|1. | Ones |0 |0 |0
|X|2. | Twos |0 |0 |0
|X|3. | Threes |0 |0 |0
|X|4. | Fours |0 |0 |0
|X|5. | Fives |0 |0 |0
|X|6. | Sixes |0 |0 |0
|X|7. | Three of a kind |0 |0 |0
|X|8. | Four of a kind |0 |0 |0
|X|9. | Full House |0 |0 |0
|X|1. | Small Straight |0 |0 |0
|X|11.| Large Straight |0 |0 |0
|X|12.| Chance |0 |0 |0
|X|13.| Yahtzee |0 |0 |0
| | | Total Score |0 |0 |0
This way looks nice as long as a user doesn't enter a ridiculously long name. This can be fixed by asking the user to enter a shorter name (nick name).
Anyway, thanks for your help!
I've tried moving around my curly braces and just the entire structure of this program a bunch and can't seem to point out how to make this print out correctly. I have a text file that looks like this:
Game of Thrones|Action|HBO|50|Favorite
House of Cards|Drama|Netflix|50|Favorite
Huckabee|Bad Show|Fox News|25|Not favorite
Survivor|Reality|NBC|45|Not favorite
The Daily Show with Jon Stewart|Comedy|Comedy Central|30|Favorite
Louie|Comedy|FX|30|Favorite
Sports Center|Sports News|ESPN|60|Favorite
The Big Bang Theory|Comedy|CBS|30|Not favorite
Sesame Street|Educational|PBS|30|Favorite
Chopped|Food Show|Food Network|60|Favorite
I want my console to show this (minus the pipes) with a toString() that I have, which works perfectly fine, but it prints out with 10 copies of each show and I'm not sure what I can go about doing differently to fix this.
Question: How can I make it so the console prints out exactly 1 copy of each show instead of 10?
Driver Code:
public class TVShowDriver {
public static void main(String[] args) throws FileNotFoundException {
TVShow[] tvShow = new TVShow[10];
String tvName = "";
String genre = "";
String network = "";
int runningTime = 0;
String favorite = "";
// reads in Shows.txt
File tvShows = new File("./src/Shows.txt");
Scanner fileScanner = new Scanner(tvShows);
// while there is a new line in the data, goes to the next one
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
Scanner lineScanner = new Scanner(line);
lineScanner.useDelimiter("\\|");
// while there is a new attribute to read in on a given line, reads
// data
while (lineScanner.hasNext()) {
tvName = lineScanner.next();
genre = lineScanner.next();
network = lineScanner.next();
runningTime = lineScanner.nextInt();
favorite = lineScanner.next();
// creates a show
for (int i = 0; i < tvShow.length; i++) {
tvShow[i] = new TVShow(tvName, genre, network, runningTime,
favorite);
}
}
// prints out shows
for (int i = 0; i < 10; i++) {
System.out.println(tvShow[i]);
}
}
}
}
TVShow Class:
public class TVShow {
private String tvName;
private String genre;
private String network;
private int runningTime;
private String favorite;
public TVShow(String tvName, String genre, String network, int runningTime, String favorite)
{
this.tvName = tvName;
this.genre = genre;
this.network = network;
this.runningTime = runningTime;
this.favorite = favorite;
}
public String getTvName() {
return tvName;
}
public void setTvName(String tvName) {
this.tvName = tvName;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre = genre;
}
public String getNetwork() {
return network;
}
public void setNetwork(String network) {
this.network = network;
}
public int getRunningTime() {
return runningTime;
}
public void setRunningTime(int runningTime) {
this.runningTime = runningTime;
}
public String getFavorite() {
return favorite;
}
public void setFavorite(String favorite) {
this.favorite = favorite;
}
public String toString()
{
return "TV Show Name: " + tvName + ", Genre: " + genre + ", Network: " + network + ", Running Time: " + runningTime + " mins" + ", Favorite: " + favorite;
}
}
This...
// creates a show
for (int i = 0; i < tvShow.length; i++) {
tvShow[i] = new TVShow(tvName, genre, network, runningTime,
favorite);
}
...is wrong. Basically, each time you read a line from the file, you are re-filling the array with that show's details (sure you're making a new instance of TVShow, but it contains all the same details.
Instead, use a separate iteration value and increment each time you read a new line...
int currentLine = 0;
while (lineScanner.hasNext()) {
if (currentLine < tvShow.length) {
tvName = lineScanner.next();
genre = lineScanner.next();
network = lineScanner.next();
runningTime = lineScanner.nextInt();
favorite = lineScanner.next();
tvShow[currentLine] = new TVShow(tvName, genre, network, runningTime,
favorite);
currentLine++;
} else {
System.err.println("The array is full");
break;
}
}
I think your problem lies in this piece:
// creates a show
for (int i = 0; i < tvShow.length; i++) {
tvShow[i] = new TVShow(tvName, genre, network, runningTime,favorite);
}
You seem to be filling up the tvShow array each time with ten (which is the length of the array) copies of the same show.
A solution is to have a counter outside of your first while loop which you increment. Then use that counter to index into tvShow.
Alternatively, if you just want to print each show you could not bother to save them all in an array, create a TVShow variable outside of the while loops and reassign it.
So that would look like:
TVShow myShow; // outside of the first while loop loop
myShow = new TVShow(tvName, genre, network, runningTime,favorite); // where you were assigning into the array
It seems that 20 regiments were in a continuous process of formation. The first had 1000 men, the second had 950, the third 900, and so on down to the twentieth regiment, which garrisoned only 50. During each week, 100 men were added to each regiment, and at week's end, the largest regiment was sent off to the front.This lasted for a total of 20 weeks.
For this program I have already managed to print out the original number of men for each regiment. But I am having difficult adding 100 men to each regiment.The adding men must be a method in the army class. I am getting the regiment objects using a .txt file. All this files contains is the names of regiments numbered 1-20.
I currently have no errors my only problem is that I do not know how to add men to my regiment. I have to use the addMen method in the army class which I currently have blank.
public class Regiment {
private String name; //name of regiment
private int regNumber; //regiment number
private int men; // regiment men
public Regiment(int regNumber, String name, int men) {
this.name = name;
this.regNumber = regNumber;
this.men = men;
}
public String getName() {
return name;
}
public int getregNumber() {
return regNumber;
}
public int getMen() {
return men;
}
public int addMen2(int RegNumber) {
int men = 1050 - (regNumber * 50);
return men;
}
}
ArmyDataList:
class ArmyDataList {
public ArrayList<Regiment> list;
public ArmyDataList() {
list = new ArrayList<Regiment>();
}
public void AddToList(Regiment current) {
list.add(current);
}
public void RemoveFromList(Regiment current) {
list.remove(current);
}
public Regiment getLargest() {
if (list.isEmpty()) {
return null;
}
Regiment Reg1 = list.get(0);
for (int i = 1; i < list.size(); i++) {
Regiment current = list.get(i); // get next regiment
// is current regiment > largest
if (current.getMen() > Reg1.getMen()) {
Reg1 = current;
}
}
return Reg1;
}
public void addMen() {
}
public String toString() {
String out
= String.format("%28s%12s%n", "Regiments", " Men")
+ String.format("%12s%n", "Number")
+ String.format("%12s%16s%14s%n", "=======", "===============",
"=========");
for (int i = 0; i < list.size(); i++) {
Regiment regim = list.get(i);
int regNumber = regim.getregNumber();
String name = regim.getName();
int men = regim.addMen2(regNumber);
out = out + String.format("%12s", regNumber)
+ String.format("%16s", name)
+ String.format("%10s", men)
+ "\n";
}
return out + "\n";
}
}
RegimentTest:
public class RegimentTest {
public static void main(String[] args) throws IOException
{
ArmyDataList army = new ArmyDataList();
Scanner fileScan = new Scanner(new File("regiments.txt"));
System.out.println("Report Summary:\n");
while (fileScan.hasNext()) {
String line = fileScan.nextLine();
System.out.println(line);
Scanner in = new Scanner(line) ;
int regNumber = in.nextInt();
String name = in.next();
int men = 0 ; //men is set to 0 only because I havent add the men yet
Regiment adder = new Regiment(regNumber, name, men );
army.AddToList(adder) ;
}
System.out.println(army.toString());
}
Add a setMen(int numberOfMen) method to your Regiment class. Then in your addMen() method, you can do something like this:
public void addMen(){
for(Regiment r : list){ //iterate through the list of regiments
r.setMen(r.getMen() + 100); //add 100 men to each regiment
}
}
The setMen method would look like this:
public void setMen(int numberOfMen){
men = numberOfMen;
}
There is another issue with your toString method, where the regiment's addMen2 method is called - right now you're just printing the number, not initializing the number of men. In the constructor for your Regiment class, replace the line
this.men = men;
with
this.men = addMen2(regNumber);
Then in your toString method, replace
int men = regim.addMen2(regNumber);
with
int men = regim.getMen();
Here is what your main should look like:
public static void main(String[] args) throws IOException{
ArmyDataList army = new ArmyDataList();
Scanner fileScan = new Scanner(new File("regiments.txt"));
System.out.println("Report Summary:\n");
while (fileScan.hasNext()) {
String line = fileScan.nextLine();
System.out.println(line);
Scanner in = new Scanner(line);
int regNumber = in.nextInt();
String name = in.next();
int men = 0 ; //men is set to 0 only because I havent add the men yet
Regiment adder = new Regiment(regNumber, name, men );
army.AddToList(adder);
}
System.out.println(army.toString()); //print out the initial # of men
for(int i = 0; i < 20; i++)
army.addMen();
System.out.println(army.toString()); //print the final # of men
}
in Regiment get rid of method addMen2, and replace it with
public void addMen(int men) {
this.men +=men;
}
then in your army you could have method
public void addMen(int men) {
for(Regiment regiment : list){
regiment.addMen(men);
}
}
that will be simplest solution to add 100 men to each regiment,
other thing is, your toString is bit nasty, regiment should know how meny soldiers it ghas, you shouldnt need additional method to calculate it (reason why i recommend you to trash addMen2 method)
to initiate your Regiment, use constructor. You want to have regiments in sizes 1000, 1950, 1900 etc, do it when you are creating them
while (fileScan.hasNext()) {
String line = fileScan.nextLine();
System.out.println(line);
Scanner in = new Scanner(line) ;
int regNumber = in.nextInt();
String name = in.next();
int men = 1050 - (regNumber * 50);
Regiment adder = new Regiment(regNumber, name, men );
army.AddToList(adder) ;
}