Just one last part remaining in the ChatBot. I need to figure out a way to modify the chatbot class so
that it occasionally (say, 30% of the time) returns a randomly-‐generated standard reply to user input one of at least five possible replies, like “LOL”, “OMG”, “You don’t say”, “Really?”, or “I see”.
Edit: Applied recommended changes:
import java.util.Random;
import java.util.Scanner;
public class ChatBot
{
private int responseCount = 0;
public String getResponse(String value)
{
String X = longestWord(value);
this.responseCount++;
if (responseCount == 10)
{
return "Sorry, but our time is up. I can't talk with you any longer.";
}
if (value.contains("you"))
{
return "I'm not important. Let's talk about you instead.";
}
else if (X.length() <= 3)
{
return "Maybe we should move on. Is there anything else you would like to talk about?";
}
else if (X.length() == 4)
{
return "Tell me more about " + X;
}
else if (X.length() == 5)
{
return "Why do you think " + X + " is important?";
}
else if (X.length() <=9)
{
return "Now we are getting somewhere. How does " + X + " affect you the most?";
}
return getRandomResponse();
}
public String longestWord(String value){
Scanner input = new Scanner (value);
String longest = new String();
longest = "";
while (input.hasNext())
{
String temp = input.next();
if(temp.length() > longest.length())
{
longest = temp;
}
}
return longest;
}
private String getRandomResponse()
{
String [] responses = {"OMG", "LOL", "You don't say", "Really?", "I See"};
return responses [(int)(Math.random() * responses.length)];
}
}
The problem is, it keeps returning the same response, instead of one of the five responses given. Any help would me much appreciated, thank you!
Edit:It's now giving only the random responses, and overriding every other response in the getResponse() method.
Given your logic, your getRandomResponse method should always return "OMG". This is because on the first run of the loop in that method, counter = 1. Thus the first if statement will run and will return "OMG" exitting the method. A nicer equivalent might putting all teh responses into an array and returning a random value from it, rather than doing somehting strange with iteration:
String[] responses = {"OMG", "LOL", "You don't say", "Really?", "I See"};
return responses[(int)(Math.random() * responses.length)];
In getRandomResponse, you make a random number generator using Random(), but you never use it. Then in your for loop, you execute your decision-making tree but use a variable counter that always begins at 0. Then on the first time through your loop, the first if statement will execute because 0 < 5, so "OMG" is returned.
Edit: I just noticed something else that is not going to work in your code:
Random randomNumber = new Random();
for (int counter =0; counter<10; counter++)
{
counter = randomNumber.nextInt();
You're trying to use counter to do two different things: you are trying to run this loop 10 times, but you're also using it to store random values.
Related
So I have written a code that allows a user to find a word in a TextArea. I have nearly succeeded but for one thing. here, I will show you all the code and tell my problem.
if(ta.getText().length() != 0 && t1.getText().length() != 0)
{
char c1[] = ta.getText().trim().toCharArray();
char c2[] = t1.getText().trim().toCharArray();
for(int i=startFlag;i<c1.length;i++)
{
if(c1[i]==c2[0])
{
start = i;
break;
}
}
k=start;
for(int i=0;i<c2.length;i++)
{
if(c2[i] != c1[start++])
{
}
else
countFlag++;
}
if(countFlag==c2.length)
{
ta.select(k,c2.length);
startFlag++;
}
}
For reference, ta is the TextArea and t1 is the TextField where the user enters a word to find. i have a problem in the second for loop. What should I write in the if () block there so that whenever c2[i] != c1[start++] the control is shifted to the first for loop, that would again determine the value of start?
Create a method to get "start" that you can then call whenever you want.
if(ta.getText().length() != 0 && t1.getText().length() != 0)
{
char c1[] = ta.getText().trim().toCharArray();
char c2[] = t1.getText().trim().toCharArray();
k=getStart(startFlag, c1.length);
for(int i=0;i<c2.length;i++)
{
if(c2[i] != c1[start++])
{
start = getStart(startFlag, c1.length);
}
else
countFlag++;
}
if(countFlag==c2.length)
{
ta.select(k,c2.length);
startFlag++;
}
}
And getStart() is:
public int getStart(int startFlag, int length) {
for(int i=startFlag;i<length;i++)
{
if(c1[i]==c2[0])
{
return i;
}
}
}
You may need different inputs to getStart(), but hopefully this gets across the general idea.
The way your code is set up right now, what you're asking for is impossible. To do what you're asking, you'll need to refactor your current code into different methods. More specifically, you'll need to put the for loops into their own methods and then call these methods.
So what you would need to do is make a separate method for the for loop.
public static int startForLoop(int i) {
for(int i=startFlag;i<c1.length;i++)
{
if(c1[i]==c2[0])
{
start = i;
break;
}
}
}
Then you can just call startForLoop(0) initially and in the 2nd for loops if statment:
if(c2[i] != c1[start++])
{
startForLoop(start+1)
}
This will continue the for loop where it left off. If you need to run the 2nd for loop again then you have to make a separate method for it as well and basically place both of them in a while loop that continues till you find the result you want in the 2nd for loop.
May be this code piece help you what you are looking for.
Basically it moves along with the string to be searched in keeping in mind the index of the string to be searched for.
Sorry but i have implemented it in java, but the notion is same and the result returned is the best what i got.you must give it a try!
private static String searchString(String searchIN,String searchFOR){
if (searchFOR != "") {
int index = searchIN.toUpperCase().indexOf(searchFOR.toUpperCase());
String before = "";
String highlighted = "";
String after = "";
while (index >= 0) {
int len = searchFOR.length();
before = searchIN.substring(0, index);
highlighted = "\"" + searchFOR + "\"";//do what ever you want to do with searched string
after = searchIN.substring(index + len);
searchIN = before + highlighted + after;
index = searchIN.toUpperCase().indexOf(searchFOR.toUpperCase(), index + highlighted.length());
}
}
return searchIN;
}
for(int x = 0;x<14;x++){
day[x]= theSheet.changeLetters(day[x]);
}
public String changeLetters(String entering){
if(entering.equalsIgnoreCase("a")){
entering = "10";
} else {
if(entering.equalsIgnoreCase("b")){
entering = "11";
} else {
if(entering.equalsIgnoreCase("c")){
entering = "12";
} else {
if(entering.equalsIgnoreCase("d")){
entering = "13";
} else {
if(entering.equalsIgnoreCase("e")){
entering = "14";
} else {
if(entering.equalsIgnoreCase("f")){
entering = "15";
} else {
if(entering.equalsIgnoreCase("g")){
entering = "16";
} else {
if(entering.equalsIgnoreCase("h")){
entering = "17";
}
}
}
}
}
}
}
}
return entering;
}
Says the error is here if(entering.equalsIgnoreCase("a")) and in the for loop I am using to run the method. I'm trying to change the letter put into the string into a number.
Can anyone explain to me where the error might be? I'm having trouble spotting the issue. it lets me enter the letters fine but it has an exception once it gets to this for loop and runs this method.
why don't you use
if (condition) {
// ...
} else if (condition2) {
// ...
} else if (condition3) {
// ...
}
// and so on
to make your code more readable. Your nested conditions are a mess. If you fix them, you might as well fix the error (if it's in the part of code you showed us).
Also add
System.out.println("Entering = '" + entering "'");
at the beginnig of your method to see if really receives what you are expecting it to receive.
Ok according to
Yes the code is being initialized in a for loop before that one using
for(int x =1;x<8;x++){ day[x-1] = JOptionPane.showInputDialog("Enter
hour pairs for day "+x +".\n Enter the first digit: "); day[x] =
JOptionPane.showInputDialog("Enter the second digit: "); } the letters
being put in the array are then changed into numbers using the for
loop posted earlier.
You have a logic error. You are overwriting previous entries and not filling the array up to 14 items. So items after 8 are left null, thus the NullPointerException.
Try this:
String[] day = new String[14];
for( int i = 0; i < 14; i+=2 ) {
day[i] = JOptionPane.showInputDialog("Enter hour pairs for day "+(i/2+1) +".\n Enter the first digit: ");
day[i+1] = JOptionPane.showInputDialog("Enter the second digit: ");
}
As a bonus, you can simplify the if-else code with:
public String changeLetters( String entering ) {
return String.valueOf(entering.toUpperCase().charAt(0) - 55);
}
As #jlordo already stated avoid nested if-statements with such a depth.
As an alternative you might use a switch statement in combination with an enum like this - although the following approach consists of more code it is more general and better suitable to be extended (e.g. using all letter of the alphabet and beyond) and it would make the code much more readable and more appropriate with respect to what you want to express.
Letter letter;
if (letter.equals("a")) letter = Letter.a;
if (letter.equals("A")) letter = Letter.A;
// and so on ...
switch (letter) {
case a : {
// do some code here ...
break;
}
case A : {
// do some code here ...
break;
}
// and so on ...
}
public enum Letter {
a (1),
A (2),
b (3),
B (4),
c (5),
C (6);
// and so on
private final int index;
Letter(int i) {
index = i;
}
public int getIndex () {
return index;
}
}
Note that if you're using Java 7 you can use the switch statement even without the enum since it accepts strings as well like this:
switch (entering) {
case "a" : {
// ...
}
// ...
}
I'm currently in the process of building a small Asteroids style game which is intended for use by the kids at a local junior school. The aim is to help them with their times-tables.
A randomly generated question is displayed on-screen, (example: 6 * ? = 12), and a number of star images with numbers on them are floating around, waiting to be be shot at! You control a ship and fly around hunting the correct answer.
Bullets collide with the stars and a test needs to be performed to see if the user has shot the correct answer or not.
The star's filenames are simply "1.png", "2.png" etc, and I have a small function to return the first character of the filename, and convert it to an int:
public rightAnswer() {
String filename = "12.png"; //would be passed as parameters
int coefficient = 2; //
int answer = 24; //
char first = filename.charAt(0);
char second = filename.charAt(1);
int target;
if (second != '.') { //dealing only with 1 or 2-digit numbers
String both = String.valueOf(first) + String.valueOf(second);
target = Integer.parseInt(both);
}
else {
target = Character.digit(first, 10);
}
if (target * coefficient == answer) {
System.out.println("Answer is correct! (target = " + target + ")");
}
else {
System.out.println("Wrong! (target = " + target + ")");
}
}
While writing I got struck by a problem. I can't figure out how to retrieve the filename of the collided star to pass it to the above test function.
edit:
taking a shot at Enno Shioji's solution, I've come to this:
//star map
Map<ImageEntity, Integer> star_number = new HashMap<ImageEntity, Integer>();
//later, while loading the images into the game...
for (int n = 0; n < 10; n++) { // 10 loops
stars[n] = new ImageEntity(this);
String filename = (n+2) + ".png"; // 2- 12 range
stars[n].load(filename);
star_number.put(stars[n], n+2);
}
//then later again, run when collision is detected between a bullet and a star...
public boolean correctAnswer(ImageEntity star, int expectedAnswer) {
if (star_number.get(star) == expectedAnswer)
return true;
else return false;
}
Is this looking right?
I would not try to grab the filename. Instead, you should keep track of which star corresponds to which number, in a Map.
// Do this wherever you have easy access to the file name
Map<Star,Integer> star_number = new HashMap<Star,Integer>();
star_number.put(star1,1);
star_number.put(star2,2);
etc...
//Then later...
boolean collided(Star star, Integer expectedAnswer){
Integer answerGiven = star_number.get(star);
return expectedAnswer.equals(answerGiven);
}
or, you could also keep track by defining the Star object as such:
class Star{
Integer number;
StarImage image;
Star(StarImage image, Integer number){
this.number = number;
this.image = image;
}
// then later...
boolean collided(Star star, Integer expectedAnswer){
return star.number.equals(expectedAnswer);
}
Hope this helps. Good luck with your project :)
Time for my daily newbie Java question :-D
I must not be understanding conditionals in a while loop correctly.
I have this:
while (true){
if (){
...
} else {
...
}
if (){
...
} else {
...
}
if (SENTINEL){
break;
}
}
The first if/else statement is working, and the sentinel is working, but the second if statement gets skipped. If I flip the first and second if statement, then the first if statement still always gets executed and skips the second. What am I missing?
Can I have two if/else statements in one block like this?
I'll include the whole code, though it's pretty ugly, and I'm sure I'll get lots of people telling me better ways of doing this. I don't mind learning better ways, but for now, I just want an answer to this looping question. thanks!
public class FindRange extends ConsoleProgram {
private static final int SENTINEL = 0;
int value = 0;
int highNumber = 0;
int latestValue = 0;
int lowNumber = 0;
public void run() {
addNumbers();
}
private void addNumbers(){
value = readInt("Enter number:");
while(true){
if (value == SENTINEL){
break;
}
latestValue = readInt("Enter number:");
getHighNumber();
getLowNumber();
if (latestValue == SENTINEL){
break;
}
}
println("High Number is "+highNumber+".");
println("Low Number is "+lowNumber+".");
}
private void getHighNumber(){
if (latestValue >= value){
highNumber = latestValue;
}else {
highNumber = value;
}
}
private void getLowNumber(){
if (latestValue <= value){
lowNumber = latestValue;
}else {
lowNumber = value;
}
}
}
Are you trying to find the minimum and maximum of a series of numbers? If so, you should definitely use Math.min() and Math.max(). It's much clearer that way and you can do away with the if statements. It's also simple enough to do it in the loop with local variables instead of fields.
The common idiom is something like this:
minValue = Math.min(minValue, candidateValue);
maxValue = Math.max(maxValue, candidatevalue);
It's possible that the behavior you're seeing comes from the fact that you are always comparing the latest value to the initial value. The initial value will never change-- so if you put in the following input:
20, 60, 50
the high value that gets reported would be 50. That's because 50 is the most recent value to be greater than 20. I think you probably mean to compare the latest value to the high value, no?
You can definitely have 2 if/else blocks within the loop; however if your sentinel gets hit the loop will exit.
Posting the entire block would help.
What will happen (after reading the posted code) is when any new value you enter within the loop is greater than the original value, lowNumber is set back to the original. So for example if your input is:
7 6 5 8
Your corresponding low number values will be:
7 6 5 7
Which is incorrect. What you could do is toast the "value" variable altogether, set your low and high to the original value, then compare latest with low and high in the get* methods.
Shouldn't you be setting value = latestValue at the bottom of your while loop?
Value never gets updated after the initial read... maybe something like this:
public class FindRange extends ConsoleProgram {
private static final int SENTINEL = 0;
public void run() {
addNumbers();
}
private void addNumbers() {
int value = 0;
// Set this to highest possible value
int highNumber = Integer.MIN_VALUE;
// Set this to lowest possible value
int lowNumber = Integer.MAX_VALUE;
while (true) {
value = readInt("Enter number:");
if (value == SENTINEL)
break;
lowNumber = Math.min(lowNumber, value);
highNumber = Math.max(highNumber, value);
}
println("High Number is " + Integer.toString(highNumber) + ".");
println("Low Number is " + Integer.toString(lowNumber) + ".");
}
}
I am working on an algorithm, and I need to be able to pass in a List and see if there are four numbers in a row at any point in the list.
I have been struggling with an easy way to do this... Here is the basic idea.. I would like the fourNumbersInARow() method to return true:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Numbers {
/**
* #param args
*/
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<Integer>();
for(int i = 0; i<10; i++){
numbers.add((new Random().nextInt()));
}
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
System.out.println(fourNumbersInARow());
}
private static boolean fourNumbersInARow() {
}
}
Use two variables: last_value and row_count. Going through the list one by one, always look whether the current value is exactly one bigger than the last_value; if yes, increase row_count, if no, reset it to 1. In any case, set last_value to the current value and loop. If at any point row_count becomes 4, return true. If you reach the end of the list, return false.
EDIT: changed counter range to start at 1
Here's an implementation in Java.
static boolean fourNumbersInARow(List<Integer> list) {
int last = 0xFACADE; // can be any number
int count = 0; // important!
for (int i : list) {
if (i == last + 1) {
if (++count == 4) return true;
} else {
count = 1;
}
last = i;
}
return false;
}
Unlike others, this resets the count of numbers in a row to 1 when the sequence is broken (because a number on its own is 1 number in a row). This allows for easier treatment of the first iteration where technically there is no previous number.
In pseudocode:
consecutiveCount = 1
lastNumber = firstElementInList(list)
for (number in list.fromSecondElement()):
if (number - lastNumber == 1):
consecutiveCount++
else:
consecutiveCount = 1
if (consecutiveCount == 4):
return true
lastNumber = number
return false
The bottom line is, you'll want to keep track of the last number in that was in the list, and compare it with the current number to see if the difference is 1. In order to remember the last number, a variable such as lastNumber is needed.
Then, in order to keep track of how many consecutive numbers there have been there should be a counter for that as well, which in the example about is the consecutiveCount.
When the condition where four consecutive numbers have occurred, then the method should return true.
This sounds a little like a homework question, so I don't want to write out a complete solution. But in your method just iterate through the list. Take the first number and see if the next number comes after the current, if so then set a variable flag with the start position and the current number, on the next iteration through the loop check to see if that value is before the previous the value etc... Once four in a row are found, break out of the loop and return true. If you encounter a number that is no chronologically correct then set a flag(start location) to null or negative and start the process over from the current location in the list.
Check this Code, this will return true if there a sequence of 4 numbers and else false otherwise
public class FindFourSequence {
public boolean isFourinRow(ArrayList seqList) {
boolean flag = false;
int tempValue = 0;
int tempValue2 = 0;
int tempValue3 = 0;
int tempValue4 = 0;
Iterator iter = seqList.iterator();
while(iter.hasNext()){
String s1 = (String)iter.next();
tempValue=Integer.valueOf(s1).intValue();
if(!(iter.hasNext())){
break;
}
String s2 = (String)iter.next();
tempValue2=Integer.valueOf(s2).intValue();
if(((tempValue2-tempValue)==1) || (tempValue-tempValue2)==1){
if(!(iter.hasNext())){
break;
}
String s3 = (String)iter.next();
tempValue3=Integer.valueOf(s3).intValue();
if((tempValue3-tempValue2)==1 || (tempValue2-tempValue3)==1){
if(!(iter.hasNext())){
break;
}
String s4 = (String)iter.next();
tempValue4=Integer.valueOf(s4).intValue();
if((tempValue3-tempValue4==1) || (tempValue4-tempValue3)==1){
flag = true;
return flag;
}
}
}
}
return flag;
}
public static void main(String[] args) throws Exception {
ArrayList aList = new ArrayList();
boolean flag = false;
FindFourSequence example = new FindFourSequence();
Random random = new Random();
for (int k = 0; k < 25; k++) {
int number = random.nextInt(20);
System.out.println(" the Number is :" + number);
aList.add("" + number);
}
/* aList.add("" + 1);
aList.add("" + 2);
aList.add("" + 3);
aList.add("" + 4);*/
flag = example.isFourinRow(aList);
System.out.println(" the result value is : " + flag);
}
}