Trouble retrieving random object from "deck" of card objects - oop

My issue is this : When I'm drawing a random card from the deck i've instantiated the returns are sometimes correct(i.e. KING_CLUBS) but sometimes I get a weird one (i.e. SEVEN_). This is odd because when the decks are instantiated, I added a print line statement in the Deck constructor to see if the ID's were being added correctly. Every time without fail the card id's are correct.
The println in Blackjack's hitUser() method was to check the ID of the card being drawn. Sometimes it's correct other times it's not. Can anyone tell me what's happening and why?
Runnable relevant code below
My Card Class:
import java.util.*;
import javax.swing.*;
import java.awt.*;
public class Card {
//cardValues[] represents the tangible values attached to the card faces(ACE, ONE, TWO, THREE, ..., KING)
private final static int cardValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
private final static String cardIDs[] = {"ACE_", "TWO_", "THREE_", "FOUR_", "FIVE_", "SIX_", "SEVEN_", "EIGHT_", "NINE_", "TEN_", "JACK_", "QUEEN_", "KING_"};
private int value;
//Name of the card, i.e. "ACE";
private String cardID;
/**
* Constructor
* #param v - card value(I.e. 1 for Ace or 13 for King)
*/
public Card(int v){
setValue(v);
setCardID(v);
}
/**
* Constructor
* #param v - card value(I.e. 1 for Ace or 13 for King)
* #param id - a manually set ID for the card(used for 'illegal' card instantiation)
*/
public Card(int v, String id){
setValue(v);
setCardID(id);
}
/**
* Returns the card ID
* #return - the card ID of the respective card
*/
public String getCardID(){
return cardID;
}
/**
* Returns the card value
* #return - the number value of the respective card
*/
public int getValue(){
return value;
}
/**
* Setter method for card value
* #param v - value
*/
public void setValue(int v){
//Checks to see if v is a valid cardValue
if(v >= 1 && v <= 13){
value = v;
}
}
/**
* 'legal' setter method for card ID
* #param v - number value of the card
*/
public void setCardID(int v){
//Checks to see if v is a valid cardValue
if(v >= 1 && v <= 13){
cardID = cardIDs[v - 1];
}
}
/**
* 'illegal' setter method for card ID
* #param id - String value of the card ID
*/
public void setCardID(String id){
cardID = id;
}
public String getIcon(){
return "blackjack/" + this.getCardID() + ".png";
}
My Deck Class:
import java.util.*;
import javax.swing.*;
import java.awt.*;
public class Deck {
private int numCards;
private String cardSuits[] = {"SPADES", "HEARTS", "DIAMONDS", "CLUBS"};
private static ArrayList<Card> cards = new ArrayList<Card>();
public static JLabel[] cardIcons = new JLabel[52];
public static int dealerHand, playerHand;
/**
* Constructor
*/
public Deck(){
//Will keep track of the index of the 52 cards created
int counter = 0;
for(int y = 0; y < 4; y++){
String suit = cardSuits[y];
for(int z = 1; z < 14; z++){
//Adds a new card and initializes it with its number value
cards.add(new Card(z));
//Replaces the card ID with a new ID containing the card suit (i.e. SPADES)
if(cards.get(counter).getCardID().indexOf("_") == cards.get(counter).getCardID().length() - 1){
String newID = cards.get(counter).getCardID() + suit;
cards.get(counter).setCardID(newID);
System.out.println(newID);
counter++;
} else {
}
}
}
}
/**
* Removes a card from the deck - gets rid of the object in the array of cards once it has been drawn
* #param id - the card to be removed
*/
public void removeCard(String id){
for(int i = 0; i < 52; i++){
if(cards.get(i).getCardID().equalsIgnoreCase(id)){
cards.remove(i);
}
}
}
/**
* Returns the object of the card within a deck
* #param c - the index of the card within the deck
* #return the card object
*/
public Card getCard(int c){
return cards.get(c);
}
/**
* Returns a random card from the array of cards in the deck
* #return - a random card object
*/
public Card getRandomCard(){
Random r = new Random();
int index = r.nextInt(cards.size());
return cards.get(index);
}
/**
* Resets the deck to its original, 'perfect' order
*/
public void reset(){
for(int x = 0; x<cards.size(); x++){
cards.remove(x);
}
//Will keep track of the index of the 52 cards created
int counter = 0;
for(int y = 0; y < 4; y++){
String suit = cardSuits[y];
for(int z = 0; z < 13; z++){
//Adds a new card and initializes it with its number value
cards.add(new Card(z));
//Replaces the card ID with a new ID containing the card suit (i.e. SPADES)
String newID = cards.get(counter).getCardID() + suit;
cards.get(counter).setCardID(newID);
counter++;
}
}
}
My Blackjack Class:
import javax.swing.*;
import net.miginfocom.swing.MigLayout;
/**
* This class provides all of the functionality of the blackjack game
* #author Mohamed Amadou
*
*/
public class Blackjack extends JFrame implements ActionListener{
public MigLayout mig = new MigLayout("insets 0");
public Deck bjDeckHouse = new Deck(), bjDeckUser = new Deck();
public int dealerOffset = 65, userOffset = 65, houseHand = 0,
public final int MAX_BET = 100000;
public JPanel bj = new JPanel(new MigLayout("insets 0")), blackjack = new JPanel(new MigLayout("insets 0"));
public JButton hit;
public Blackjack(){
buildUI();
mig.layoutContainer(bj);
setSize(780, 700);
setResizable(false);
setLayout(mig);
setTitle("Blackjack");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
public void buildUI(){
getContentPane().add(bj);
bj.setBackgroundColor(Color.BLACK);
hit = new JButton("Hit");
hit.addActionListener(this);
bj.add(hit, "pos 570px 285px");
}
public void hitUser(int hand){
JPanel test = new JPanel(new MigLayout("insets 0"));
JFrame testFrame = new JFrame();
testFrame.add(test);
Card hitCard = bjDeckUser.getRandomCard();
hand += hitCard.getValue();
String position = "pos "+ userOffset + "px" + " 580px";
System.out.println(hitCard.getCardID());
bjDeckUser.removeCard(hitCard.getCardID());
turns++;
checkBust(hand);
testFrame.setSize(400, 400);
testFrame.setResizable(false);
testFrame.setLayout(mig);
testFrame.setTitle("Blackjack Rules");
testFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
testFrame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == hit){
hitUser(userHand);
}
}

Your problem lies in reset():
for(int x = 0; x<cards.size(); x++){
cards.remove(x);
}
This actually does not remove all items (just play it through), you should use cards.clear(). Since the deck is then not empty, and you add another 52 cards, the deck will be incorrect. Additionally you will get weird names, probably also SEVEN_CLUBS_SPADES and similar.
Also, your code is a little bit confusing. Suite should be an attribute of a Card, not of a Deck. Cards should be immutable (maybe enums depending on usage). You have 2 initialization code snippets (you should have 1). GUI code in your "business model". Just a few ideas to clean up :)

Related

OOP throw two dice this.setSumTotal(); does not work

Just been experimenting with a class in which 2 dice are thrown and the total calculated. I am using OOP setting the total to this.dice1+this.dice2. However, when instantiating a Dice in another class the dice1 & dice2 throw work fine and generate 2 random numbers between 1 and 6. However, the sumTotal just defaults to 0 rather than adding dice1 and dice2.
Dice class:
public class Dice {
//create a random class
Random random = new Random();
//constants set the boundaries of possible dice roll values
private final static int UPPER_DICE_ROLL_LIMIT=6;
private final static int LOWER_DICE_ROLL_LIMIT=1;
//instance vars
private int dice1;
private int dice2;
private int sumTotal;
/**
* default constructor
*/
public Dice() {
}
/**
* #param dice1
* #param dice2
* #param sumTotal
*/
public Dice(int dice1, int dice2) {
this.setDice1(dice1);
this.setDice2(dice2);
this.setSumTotal();
}
/**
* #return the dice1
*/
public int getDice1() {
return dice1;
}
/**
* sets the number of dice1's roll - must be >=1 & <=6
* #param dice1 the dice1 to set
*/
public void setDice1(int dice1) throws IllegalArgumentException {
if (dice1>=LOWER_DICE_ROLL_LIMIT && dice1<=UPPER_DICE_ROLL_LIMIT) {
this.dice1 = dice1;
}else {
throw new IllegalArgumentException("Invalid number");
}
}
/**
* #return the dice2
*/
public int getDice2() {
return dice2;
}
/**
* sets the number of dice2's roll - must be >=1 & <=6
* #param dice2 the dice2 to set
*/
public void setDice2(int dice2) throws IllegalArgumentException {
if (dice2>=LOWER_DICE_ROLL_LIMIT && dice2<=UPPER_DICE_ROLL_LIMIT) {
this.dice2 = dice2;
}else {
throw new IllegalArgumentException("Invalid number");
}this.dice2 = dice2;
}
/**
* #return the sumTotal
*/
public int getSumTotal() {
return sumTotal;
}
/**
* sets the total score of the two dice (dice1 + dice2)
* #param sumTotal the sumTotal to set
*/
public void setSumTotal() {
this.sumTotal = this.dice1 + this.dice2;
}
/**
* method to set randomly set the values of the dice rolls
*/
public void rollDice() {
this.setDice1(random.nextInt(UPPER_DICE_ROLL_LIMIT)+1);
this.setDice2(random.nextInt(UPPER_DICE_ROLL_LIMIT)+1);
}
}
Game class:
public class Game {
public static void main(String[] args) {
Dice dice = new Dice();
dice.rollDice();
System.out.println(dice.getDice1());
System.out.println(dice.getDice2());
System.out.println(dice.getSumTotal());
}
}
Thanks in advance, Cameron
Your function setSumTotal() is currently not called after rolling your dice. You could change your function rollDice() to:
public void rollDice() {
this.setDice1(random.nextInt(UPPER_DICE_ROLL_LIMIT)+1);
this.setDice2(random.nextInt(UPPER_DICE_ROLL_LIMIT)+1);
this.setSumTotal();
}

Why doesn't my number sequence print from the 2d arraylist correctly?

I cannot get the loop to work in the buildDimArray method to store the number combinations "11+11", "11+12", "11+21", "11+22", "12+11", "12+12", "12+21", "12+22", "21+11", "21+12", "21+21", "21+22", "22+11", "22+12", "22+21", and "22+22" into the 2d arraylist with each expression going into one column of the index dimBase-1 row. The loop may work for other people, but for some reason mine isn't functioning correctly. The JVM sees the if dimBase==1 condition, but refuses to check the other conditions. The "WTF" not being printed as a result from the buildDimArray method. If dimBase=1, it prints successfully, but doesn't for the other integers. The dimBase==3 condition needs a loop eventually. The "WTF" is for illustrative purposes. I could get away with a 1d arraylist, but in the future I will likely need the 2d arraylist once the program is completed.
package jordanNumberApp;
import java.util.Scanner;
import java.util.ArrayList;
/*
* Dev Wills
* Purpose: This code contains some methods that aren't developed. This program is supposed to
* store all possible number combinations from numbers 1-dimBase for the math expression
* "##+##" into a 2d arraylist at index row dimBase-1 and the columns storing the
* individual combinations. After storing the values in the arraylist, the print method
* pours the contents in order from the arraylist as string values.
*/
public class JordanNumberSystem {
// a-d are digits, assembled as a math expression, stored in outcomeOutput, outcomeAnswer
public static int dimBase, outcomeAnswer, a, b, c, d;
public static String inputOutcome, outcomeOutput;
public static final int NUM_OF_DIMENSIONS = 9; //Eventually # combinations go up to 9
public static ArrayList<ArrayList<String>> dimBaseArray;
public static Scanner keyboard;
/*
* Constructor for JordanNumber System
* accepts no parameters
*/
public JordanNumberSystem() // Defunct constructor
{
// Declare and Initialize public variables
this.dimBase = dimBase;
this.outcomeOutput = outcomeOutput;
this.outcomeAnswer = outcomeAnswer;
}
// Set all values of variable values
public static void setAllValues()
{
// Initialize
dimBase = 1;
outcomeAnswer = 22; // variables not used for now
outcomeOutput = "1"; // variables not used for now
//a = 1;
//b = 1;
//c = 1;
//d = 1;
dimBaseArray = new ArrayList<ArrayList<String>>();
keyboard = new Scanner(System.in);
}
public static void buildDimArray(int dim)
{
dimBase = dim;
try
{
//create first row
dimBaseArray.add(dimBase-1, new ArrayList<String>());
if( dimBase == 1)
{
a = b = c = d = dimBase ;
dimBaseArray.get(0).add(a+""+b+"+"+c+""+d);
System.out.println("WTF"); // SHOWS
}
else if (dimBase == 2)
{ // dim = 2
a = b = c = d = 1 ;
System.out.println("WTF"); // doesn't show
// dimBaseArray.get(dimBase-1).add(a+""+b+"+"+c+""+d);
for( int i = 1 ; i <= dim ; i++)
a=i;
for( int j = 1 ; j <= dim ; j++)
b=j;
for( int k = 1 ; k <= dim ; k++)
c=k;
for( int l = 1 ; l <= dim ; l++)
{
d=l;
dimBaseArray.get(dim-1).add(a+""+b+"+"+c+""+d);
}
}
else if (dimBase == 3)
{
a = b = c = d = dimBase;
dimBaseArray.get(2).add(a+""+b+"+"+c+""+d);
System.out.println("WTF");
}
}catch (IndexOutOfBoundsException e)
{
System.out.println(e.getMessage());
}
}
public static void printArray(int num) // Prints the contents of the array
{ // Fixing the printing method
try
{
int i = num-1;
for( String string : dimBaseArray.get(i))
{
System.out.println(string);
System.out.println("");
}
} catch (IndexOutOfBoundsException e)
{
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws java.lang.IndexOutOfBoundsException
{
setAllValues(); // sets the initial a,b,c,d values and dimBase, initializes 2d arraylist
// Get the Dimension Base number
System.out.println("Enter Dimension Base Number. Input an integer: ");
int dimBaseInput = keyboard.nextInt(); // Receives integer
dimBase = dimBaseInput;
if( dimBase != 1 && dimBase != 2 && dimBase != 3)
{// Error checking
System.out.println("invalid Dimension Base Number should be 1 or 2 ");
System.exit(1);
}
// Build the arraylist, print, clear, exit
buildDimArray(dimBase);
printArray(dimBase);
dimBaseArray.clear();
System.exit(1);
}
}// End of class

Generate N-grams while preserving spaces in apache lucene

I am trying to generate N-grams using apache Lucene 5.5.4 for a given set input text. Following is my java code to do the same.
public static void main( String[] args )
{
Analyzer analyzer = createAnalyzer( 2 );
List<String> nGrams = generateNgrams( analyzer, "blah1 blah2 blah3" );
for ( String nGram : nGrams ) {
System.out.println( nGram );
}
}
public static Analyzer createAnalyzer( final int shingles )
{
return new Analyzer() {
#Override
protected TokenStreamComponents createComponents( #NotNull String field )
{
final Tokenizer source = new WhitespaceTokenizer();
final ShingleFilter shingleFilter = new ShingleFilter( new LowerCaseFilter( source ), shingles );
shingleFilter.setOutputUnigrams( true );
return new TokenStreamComponents( source, shingleFilter );
}
};
}
public static List<String> generateNgrams( Analyzer analyzer, String str )
{
List<String> result = new ArrayList<>();
try {
TokenStream stream = analyzer.tokenStream( null, new StringReader( str ) );
stream.reset();
while ( stream.incrementToken() ) {
String nGram = stream.getAttribute( CharTermAttribute.class ).toString();
result.add( nGram );
LOG.debug( "Generated N-gram = {}", nGram );
}
} catch ( IOException e ) {
LOG.error( "IO Exception occured! {}", e );
}
return result;
}
For my input blah1 blah2 blah3, the output is as follows and i am okay with it.
blah1
blah1 blah2
blah2
blah2 blah3
blah3
However, when the input is Foo bar Foo2, my requirement is to generate the following output:
Foo
Foo bar
bar
bar Foo2
Foo2
If you noticed, I have to preserve the spaces in between 2 words as it is in the input.(Foo bar and not Foo bar).
Can I make any tweaks and ask lucene to handle it internally?
May be its a minor tweak like adding a filter or something and since I am new to Lucene, I don't know where to start.
Thanks in Advance.
I had to write custom tokenizers and and trim filters to achieve this.
1) I created an abstract class DelimiterPreservingCharTokenizer by extending org.apache.lucene.analysis.Tokenizer class. Next, gave my implementation for incrementToken method. I would have extended org.apache.lucene.analysis.util.CharTokenizer if not the class was final. DelimiterPreservingCharTokenizer looks like below.
package lucene.tokenizers;
import java.io.IOException;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.util.CharTokenizer;
import org.apache.lucene.analysis.util.CharacterUtils;
import org.apache.lucene.analysis.util.CharacterUtils.CharacterBuffer;
import org.apache.lucene.util.AttributeFactory;
/**
*
* #author Arun Gowda.
* This class is exactly same as {#link CharTokenizer}. Except that, the stream will have leading delimiters. This is to support N-gram vicinity matches.
*
* We are creating a new class instead of extending CharTokenizer because, incrementToken method is final and we can not override it.
*
*/
public abstract class DelimiterPreservingCharTokenizer extends Tokenizer
{
/**
* Creates a new {#link DelimiterPreservingCharTokenizer} instance
*/
public DelimiterPreservingCharTokenizer()
{}
/**
* Creates a new {#link DelimiterPreservingCharTokenizer} instance
*
* #param factory
* the attribute factory to use for this {#link Tokenizer}
*/
public DelimiterPreservingCharTokenizer( AttributeFactory factory )
{
super( factory );
}
private int offset = 0, bufferIndex = 0, dataLen = 0, finalOffset = 0;
private static final int MAX_WORD_LEN = 255;
private static final int IO_BUFFER_SIZE = 4096;
private final CharTermAttribute termAtt = addAttribute( CharTermAttribute.class );
private final OffsetAttribute offsetAtt = addAttribute( OffsetAttribute.class );
private final CharacterUtils charUtils = CharacterUtils.getInstance();
private final CharacterBuffer ioBuffer = CharacterUtils.newCharacterBuffer( IO_BUFFER_SIZE );
/**
* Returns true iff a codepoint should be included in a token. This tokenizer
* generates as tokens adjacent sequences of codepoints which satisfy this
* predicate. Codepoints for which this is false are used to define token
* boundaries and are not included in tokens.
*/
protected abstract boolean isTokenChar( int c );
/**
* Called on each token character to normalize it before it is added to the
* token. The default implementation does nothing. Subclasses may use this to,
* e.g., lowercase tokens.
*/
protected int normalize( int c )
{
return c;
}
#Override
public final boolean incrementToken() throws IOException
{
clearAttributes();
int length = 0;
int start = -1; // this variable is always initialized
int end = -1;
char[] buffer = termAtt.buffer();
while ( true ) {
if ( bufferIndex >= dataLen ) {
offset += dataLen;
charUtils.fill( ioBuffer, input ); // read supplementary char aware with CharacterUtils
if ( ioBuffer.getLength() == 0 ) {
dataLen = 0; // so next offset += dataLen won't decrement offset
if ( length > 0 ) {
break;
} else {
finalOffset = correctOffset( offset );
return false;
}
}
dataLen = ioBuffer.getLength();
bufferIndex = 0;
}
// use CharacterUtils here to support < 3.1 UTF-16 code unit behavior if the char based methods are gone
final int c = charUtils.codePointAt( ioBuffer.getBuffer(), bufferIndex, ioBuffer.getLength() );
final int charCount = Character.charCount( c );
bufferIndex += charCount;
if ( isTokenChar( c ) ) { // if it's a token char
if ( length == 0 ) { // start of token
assert start == -1;
start = offset + bufferIndex - charCount;
end = start;
} else if ( length >= buffer.length - 1 ) { // check if a supplementary could run out of bounds
buffer = termAtt.resizeBuffer( 2 + length ); // make sure a supplementary fits in the buffer
}
end += charCount;
length += Character.toChars( normalize( c ), buffer, length ); // buffer it, normalized
if ( length >= MAX_WORD_LEN ) // buffer overflow! make sure to check for >= surrogate pair could break == test
break;
} else if ( length > 0 ) // at non-Letter w/ chars
break; // return 'em
}
if ( length > 0 && bufferIndex < ioBuffer.getLength() ) {//If at least one token is found,
//THIS IS THE PART WHICH IS DIFFERENT FROM LUCENE's CHARTOKENIZER
// use CharacterUtils here to support < 3.1 UTF-16 code unit behavior if the char based methods are gone
int c = charUtils.codePointAt( ioBuffer.getBuffer(), bufferIndex, ioBuffer.getLength() );
int charCount = Character.charCount( c );
bufferIndex += charCount;
while ( !isTokenChar( c ) && bufferIndex < ioBuffer.getLength() ) {// As long as we find delimiter(not token char), keep appending it to output stream.
if ( length >= buffer.length - 1 ) { // check if a supplementary could run out of bounds
buffer = termAtt.resizeBuffer( 2 + length ); // make sure a supplementary fits in the buffer
}
end += charCount;
length += Character.toChars( normalize( c ), buffer, length ); // buffer it, normalized
if ( length >= MAX_WORD_LEN ) {// buffer overflow! make sure to check for >= surrogate pair could break == test
break;
}
c = charUtils.codePointAt( ioBuffer.getBuffer(), bufferIndex, ioBuffer.getLength() );
charCount = Character.charCount( c );
bufferIndex += charCount;
}
//ShingleFilter will add a delimiter. Hence, the last iteration is skipped.
//That is, for input `abc def ghi`, this tokenizer will return `abc `(2 spaces only). Then, Shingle filter will by default add another delimiter making it `abc `(3 spaces as it is in the input).
//If there are N delimiters, this token will at max return N-1 delimiters
bufferIndex -= charCount;
}
termAtt.setLength( length );
assert start != -1;
offsetAtt.setOffset( correctOffset( start ), finalOffset = correctOffset( end ) );
return true;
}
#Override
public final void end() throws IOException
{
super.end();
// set final offset
offsetAtt.setOffset( finalOffset, finalOffset );
}
#Override
public void reset() throws IOException
{
super.reset();
bufferIndex = 0;
offset = 0;
dataLen = 0;
finalOffset = 0;
ioBuffer.reset(); // make sure to reset the IO buffer!!
}
}
2) A concrete class WhiteSpacePreservingTokenizer extending the above abstract class to provide delimiter
package spellcheck.lucene.tokenizers;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
import org.apache.lucene.util.AttributeFactory;
/**
*
* #author Arun Gowda
*
* This class is exactly same as {#link WhitespaceTokenizer} Only difference is, it extends DelimiterPreservingCharTokenizer instead of CharTokenizer
*/
public class WhiteSpacePreservingTokenizer extends DelimiterPreservingCharTokenizer
{
/**
* Construct a new WhitespaceTokenizer.
*/
public WhiteSpacePreservingTokenizer()
{}
/**
* Construct a new WhitespaceTokenizer using a given
* {#link org.apache.lucene.util.AttributeFactory}.
*
* #param factory
* the attribute factory to use for this {#link Tokenizer}
*/
public WhiteSpacePreservingTokenizer( AttributeFactory factory )
{
super( factory );
}
/** Collects only characters which do not satisfy
* {#link Character#isWhitespace(int)}.*/
#Override
protected boolean isTokenChar( int c )
{
return !Character.isWhitespace( c );
}
}
3) The tokenizer above will result in tailing spaces. (Ex: blah____) we need to add a filter to trim those spaces. So we need DelimiterTrimFilter as folows.(We can also just trim by using java's trim. but doing so will be very inefficient since it creates new string)
package spellcheck.lucene.filters;
import java.io.IOException;
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
public class DelimiterTrimFilter extends TokenFilter
{
private final CharTermAttribute termAtt = addAttribute( CharTermAttribute.class );
private char delimiter;
/**
* Create a new {#link DelimiterTrimFilter}.
* #param in the stream to consume
* #param delimiterToTrim delimiter that should be trimmed
*/
public DelimiterTrimFilter( TokenStream in, char delimiterToTrim )
{
super( in );
this.delimiter = delimiterToTrim;
}
#Override
public boolean incrementToken() throws IOException
{
if ( !input.incrementToken() )
return false;
char[] termBuffer = termAtt.buffer();
int len = termAtt.length();
if ( len == 0 ) {
return true;
}
int start = 0;
int end = 0;
// eat the first characters
for ( start = 0; start < len && termBuffer[start] == delimiter; start++ ) {
}
// eat the end characters
for ( end = len; end >= start && termBuffer[end - 1] == delimiter; end-- ) {
}
if ( start > 0 || end < len ) {
if ( start < end ) {
termAtt.copyBuffer( termBuffer, start, ( end - start ) );
} else {
termAtt.setEmpty();
}
}
return true;
}
}
4) My createAnalyzer will look like below
public static Analyzer createAnalyzer( final int shingles )
{
return new Analyzer() {
#Override
protected TokenStreamComponents createComponents( #NotNull String field )
{
final Tokenizer source = new WhiteSpacePreservingTokenizer();
final TokenStream filter = new ShingleFilter( new LowerCaseFilter( source ), shingles );
filter = new DelimiterTrimFilter( filter, ' ' );
return new TokenStreamComponents( source, filter );
}
};
}
Rest of the code will remain the same

arrayList i only show the last element

I have the following problem. I'm trying to show all the elements of a display arrayList but I can only see the last item repeated as many times as there are number of elements in the ArrayList.
import java.util.ArrayList;
import java.util.Iterator;
public class PurebaArrayList {
public static void main(String[] args) {
ArrayList<PuntoDouble> puntos = new ArrayList<>();
PuntoDouble p = new PuntoDouble();
for(int cont = 0; cont< 100; cont++){
p.setX(cont);
p.setY(cont);
puntos.add(p);
}
System.out.println(puntos.toString());
}
}
public class PuntoDouble{
private double x;
private double y;
public PuntoDouble(double x, double y) {
this.x = x;
this.y = y;
}
public PuntoDouble(){
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
#Override
public String toString() {
return "PuntoDouble{" + "x=" + x + ", y=" + y + '}';
}
}
Thanks
You need to create a new PuntoDouble for every entry you add to the list. At the moment you add just a single instance of a PuntoDouble which you modify.
Therefore change the code to:
for(int cont = 0; cont< 100; cont++){
PuntoDouble p = new PuntoDouble();
p.setX(cont);
p.setY(cont);
puntos.add(p);
}
You are, literally, adding the same PuntoDouble as each of the 100 elements of the array. If you want them to be distinct from each other, you need to make a new one for each.
For debugging,slightly change 100 to 3 and add for each iteration to print out the elements in puntos.
// adds to ArrayList
for(int cont = 0; cont< 10; cont++){
p.setX(cont);
p.setY(cont);
System.out.println("[add]" + p);
puntos.add(p);
}
// iterates ArrayList puntos' elements
for(PuntoDouble pd : puntos){
System.out.println("[contain]" + pd);
}
debug output lines:
[add]PuntoDouble{x=0.0, y=0.0}
[add]PuntoDouble{x=1.0, y=1.0}
[add]PuntoDouble{x=2.0, y=2.0}
[add]PuntoDouble{x=3.0, y= 3.0}
[contain]PuntoDouble{x=9.0, y=9.0}
[contain]PuntoDouble{x=9.0, y=9.0}
[contain]PuntoDouble{x=9.0, y=9.0}
What you did is created an PuntoDouble object p and initilized it by invoking default constructor. In the for loop, the values of p modifies, but the reference of p never changed, therefore you kept adding the same object into ArrayList 100 times, all of those added objects refer to the same address in memory(new an object once before the for loop) which the value x is 99.0 and y is 99.0 (the last added values)
What you should do is creating a new object each iterate.
for(int cont = 0; cont< 100; cont++){
puntos.add(new PuntoDouble(cont, cont));
}

get an specific object from my arrayList(Java)

hi my problem is that in my code i am calling a method that calculates the different between 2 point and then if that distance is less that 7 it will call another class method that should change the color of the target to red... my problem is that in my arraylist i have 3 or five or depends on the user input targets... so how can i specify the object in my arraylist that is going to be change of color>??? this is my code
package project1;
import java.util.*;
import javax.swing.*;
/**
*
* #author Elvis De Abreu
*/
public class TargetGallery
{
/**ArrayList of Targets initialize as a private*/
private ArrayList<Target> mytargets = new ArrayList<>();
/**Static object for the Target class*/
static Target tg = new Target();
/**Static object for the RifleSite class*/
static RifleSite rs = new RifleSite();
/**Static object for the TargetGallery class*/
static TargetGallery tgy = new TargetGallery();
/**the number of targets input by the user as private*/
private int number = 0;
/**array that store the distance between 2 point for each target*/
private double[] total;
/**
* Method that build the background of the canvas
* with a picture as a environment
*/
private void buildWorld()
{
StdDraw.setXscale(0, 250);
StdDraw.setYscale(0, 250);
StdDraw.picture(75, 130, "bath.jpeg", 450, 285);
}
/**
* Method that draw a weapon in the middle of the
* canvas as a shooter weapon
*/
private void drawShooter()
{
StdDraw.setXscale(0, 250);
StdDraw.setYscale(0, 250);
StdDraw.picture(125, 0, "weapon.png", 80, 45);
}
/**
* randomly generates X locations for the targets
* add them into the array list
*/
private void createTargets()
{
double x = 125;
double y = 175;
double radius = 7;
String input = JOptionPane.showInputDialog("Type a number" +
"between 2 and 5");
number = Integer.parseInt(input);
for(int i = 0; i < number; i++)
{
Target targ = new Target(x, y, radius);
mytargets.add(targ);
Random rand = new Random();
x = rand.nextInt(400) + 10;
for (Target e: mytargets)
{
if ((e.getX() <= (x+10)) || (e.getX() >= (x-10)))
{
mytargets.clear();
i--;
continue;
}
}
}
}
/**
* Method that run different methods which start the program
*/
public void run()
{
tgy.buildWorld(); //call the buildWorld method
tgy.drawShooter(); //call the drawShooter method
tgy.createTargets(); //call the createTarget method
tgy.simulate(); //call the simulate method
}
/**
* calculates the distance between the RifleSite and the Targets
*/
public void calcDistance()
{
//variable declaration/initialization
double distance;
double distance1;
int i = 0;
total = new double[number];
//for each loop to calculate x and y location of RifleSite and Targets
for (Target e: mytargets)
{
distance = Math.pow(e.getX()-rs.getX(), 2.0);
distance1 = Math.pow(e.getY()-rs.getY(), 2.0);
total[i++] = Math.sqrt(distance + distance1);
}
}
/**
* Method that simulates the game
*/
public void simulate()
{
//Variable declaration/initialization
boolean alive = true;
for(Target e: mytargets)
{
e.drawAlive();
}
rs.drawRifleSite();
//loop that will run while there is still targets alive or user press q
while(alive == true)
{
//if user press a key this
if (StdDraw.hasNextKeyTyped())
{
char ch = StdDraw.nextKeyTyped(); //store the key pressed
//if person press Q will quit the program
if (ch == 'q')
{
int done = JOptionPane.showConfirmDialog(null,
"The Program will close now bye :)");
System.exit(0);
}
else if (ch == 'f')
{
tgy.calcDistance(); //calculates the distance
//if statement to check if the distance if less than radius
for(int i = 0; i < number; i++)
{
if (total[i] <= 7)
{
//THIS IS WHERE MY METHOD SHOULD GO
//SHOULD BE SOMETHING LIKE E.drawDead
}
}
}
}
}
}
/**
* Method for the main of the Program
* #param args the command line arguments
*/
public static void main(String[] args)
{
}
}
Like this:mytargets.get(INDEX GO HERE)
i Hope that helps
(the index starts from 0)
For example:
Target t=mytargets.get(0);
if ((t.getX() > 10) && (t.getY() > 10))
{
//blablabla
}