I am trying to implement a calculator that works just like the normal calculators, I managed to block out many inputs from keyboard to prevent unnecessary characters, Then i managed to analyze the textfield content and put the content in an arraylist. The array list contains operators including brackets and put in the array list as well. Now I want to be able to take the brackets and perform multiplication for them or perform the operator that comes before it. My code for the bracket analyzer is as below
private void BracketSolver(int opnBracketPosition, ArrayList Analyzed)
{Boolean _closed=true;
for (int i=opnBracketPosition;i<Analyzed.size();i++)//check all array element
{
if (Analyzed.get(i).equals("("))//if its an open bracket
{
_closed = false;//a bracket opened
if(Analyzed.get(i+1).equals("-")){//if a minus after the bracket, then turn the number after the minus to a negative and delete the minus
Analyzed.set(i+2,String.valueOf((-1)*Double.parseDouble(Analyzed.get(i+2).toString())));
Analyzed.remove(i+1);}
for (int j=i+1;j<Analyzed.size();j++){//check all element after the open bracket
if(Analyzed.get(j).equals("("))
{
BracketSolver(j, Analyzed);i=0;
}//if we meet another open bracket, then restart the function from there
else if(Analyzed.get(j).equals(")"))//but if its a closing
{
_closed = true;//it has been closed
if(i!=0){//make sure is not zero to prevent error of i-1=-1
if((Analyzed.get(i-1).equals("+"))||(Analyzed.get(i-1).equals("-"))
||(Analyzed.get(i-1).equals("x"))||(Analyzed.get(i-1).equals("^"))
||(Analyzed.get(i-1).equals("÷"))||(Analyzed.get(i-1).equals("√"))) {
//if an operator is before the bracket then just delete the brackets and calculate
Analyzed.remove(j);Analyzed.remove(i);//remove the brackets
Calculator_Basic(Analyzed, i, j-1);//solve for all after the open bracket n before the close
}
else{Analyzed.remove(j);Analyzed.set(i,String.valueOf('x'));
//remove the close bracket but change the open bracket to multiply
Calculator_Basic(Analyzed, i+1, j-1);//solve for all after the open bracket n before the close
}
}else{ Analyzed.remove(j);Analyzed.remove(i);//remove the brackets
Calculator_Basic(Analyzed, i, j-1);//solve for all after the open bracket n before the close
}//i=0;//restart
}
}
}
} if(!_closed)//if it has ended and still no close
{throw new IllegalArgumentException("Syntax Error: Bracket Not Closed");
}
}
the function calculator_Basic is another function that takes an arraylist and a start and end integer and calculates everything in between. It already works fine but if you need it to help me out i can paste it as well, though it is very plenty and rough. Now my problem is this code cannot perform on something like (5)(8). I do not know why. I know my code is plenty and might be uneasy to understand.
The next set of code is what I used in storing the text field into an array list
private static ArrayList<String> AnalyzedContent;
private void Analyzer()//function that analyzes the user input char by char and takes the numbers
{
AnalyzedContent = new ArrayList();//to store everything
char[] operators = {'+','-','x','÷','^','√','(',')'};//array holding all operators
String set = "";//string to hold the numbers
for (int i=0;i<Display.getText().length();i++)//for all chars in display
{//if its an operator
if((Display.getText().charAt(i)==operators[0])||(Display.getText().charAt(i)==operators[1])||(Display.getText().charAt(i)==operators[2])
||(Display.getText().charAt(i)==operators[3])||(Display.getText().charAt(i)==operators[4])||(Display.getText().charAt(i)==operators[5])
||(Display.getText().charAt(i)==operators[6])||(Display.getText().charAt(i)==operators[7]))
{
if (!set.equals(""))AnalyzedContent.add(set);//check if set is not empty then store its content
set = "";//reset the set
for (int j = 0; j<operators.length;j++){//check which operator it is and store
if (Display.getText().charAt(i)==operators[j])
{
if((i==0)&&(j!=6))throw new ArithmeticException("Syntax Error::Cannot Begin with Operator");
//if it is start of the display and operator is not open bracket then throw error
AnalyzedContent.add(operators[j] + "");
}}
//j=operators.length;//leave the loop when something is found
}
else//else if its a number append to set which might already contain numbers not separated by an operator
{
set = set + Display.getText().charAt(i);//append the number to previous
}
}if (!set.equals(""))AnalyzedContent.add(set);//check if set is not empty then store its content
thanks in advance anyone
Again, My if statement for the operators using || is very rough, I am guessing there is a neater way to do it, if someone could help me there too.
Related
I need to create a program to store all words in an array list. Then check the user input from the textfield to see if it starts with anything other than numbers and punctuation. Otherwise it will need to display an error and prvent the string to be added to the arraylist and display an appropriate error.
https://pastebin.com/8UwDm4nE
Heres the ActionEvent listener that contins the code to check that. Im not really sure how to get it working.
#Override
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < 1; i++) {
String str = tf.getText(); // MUST BE STORED ON AN ARRAY LIST
ta.append(str + "\n"); // Append the text on new line each
if(str.startsWith(String.valueOf(nums))) { // Check input for a number at the start
error.setText("Error: Word starts a number. Please try again!");
error.setForeground(Color.RED);
ta.append("");
} else if (str.startsWith(String.valueOf(punct))) { // Check if input contains a punctuation at the start
error.setText("Error: Word starts with an illegal character. Please try again!");
error.setForeground(Color.RED);
ta.append("");
}
}
}
I'm going to rephrase your problem a bit as clarification, please correct me if I'm misunderstanding.
You have a text field and a text area. You want a user to type a word into the text field and submit it. If that word starts with a number or punctuation, then indicate an error to the user. Otherwise, add it to the text area (on a new line) and the inner ArrayList.
To solve this problem, there are a couple things you'll need:
An ArrayList<String> that is a class member variable where you can store your words
An event handler that handles the button click.
The event handler should:
Parse the string from the text field (using getText(), as you already are).
Do the error checks you're already doing.
If neither of the error conditions are hit (so add an else clause for this), add the word to the text area (which you're already doing) and add it to the ArrayList.
Hopefully this helps you get a clearer idea of how to approach the problem. If not, please post a code sample of what you tried and what error you're specifically running into.
EDIT:
Here is some pseudocode for your if-else error-handling block of code, assuming you declare a new ArrayList to hold your words as a class member:
// as class member variable
List<String> wordList = new ArrayList<>();
// word handler code
if (str starts with a number) {
// handle error
} else if (str starts with punctuation) {
// handle error
} else {
ta.append(str + "\n");
wordList.add(str);
}
The method has to receive a String in format "[1,2,3,4,5]" with just integers inside, but it can also have "[1,2,3,[]]" or "[1,2,3,[1,2,3]]". I already have the code to just add the numbers to the list, but I can't figure out how to handle when I have another List inside.
I've thought of having a class List and when I find another brackets inside to call the function again, but don't know how to substring correctly when I see another opening bracket [.
After I remove the brackets I split the string like this:
String[] arr = string.split(",");
And start to add those results to the List I have to return with a for loop, my problem is when I see an opening bracket again [ I would have to substring and call with the resulting String my method again but don't know how to determine the closing bracket. What I've tried is to get the index of a closing bracket with indexOf:
String aux = arr[i];
int closingBracket = aux.indexOf("]");
But if I have an input string like [1,2,3,4,[,6] which shouldn't be accepted it will accept it.
What you need to do is figure out, on paper, what is called a finite state machine (FSM). When you encounter a token (comma, bracket, digit) you enter a particular state. Once in a certain state, you can only accept certain other tokens which may put you in a different state or leave you in the current one. You could have many different states which can accept different tokens and perform different actions.
For example.
When you see a digit, the next token may be.
1. Another digit
2. A closing bracket.
3. A comma.
Each of those tokens may prompt a different state and/or action.
1. Another digit - keep on processing since numbers have many digits.
2. closing bracket - save the number in a list and get the next list (See below)
3. comma - save the number and look for next number
Assuming you want to save all of this in a list of lists it would be easiest to start off with a List<Object> since you can save integers and lists of lists in that type of list with indefinite depths.
I also suggest you look at the Stack class. You may want to be pushing the current list and popping a recent one as your parsing depth changes.
Finally, to ensure your brackets are properly matched to the following. Increment a counter when you see a '[' and decrement the counter when you see a ']'. If the counter ever goes negative, you have too many right brackets. If at the end it is positive, you don't have enough right brackets.
For more on this check out Finite State Machines at Wikipedia.
I decided to include a small example of what I was talking about. It may not cover all possible edge cases but the purpose is illustrative.
public static void main(String[] args) {
String strlist =
"[1,2,113], [4,5,[5,2,10],1], [],[1,2,3,4,5,[10,11,12,13,[14,15]]]";
int bracketCount = 0;
int num = 0;
// inital list
List<Object> list = new ArrayList<>();
// hold sublists for precessing
Stack<List<Object>> stack = new Stack<>();
char[] chars = strlist.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
switch (c) {
// state1 left bracket - push current list on stack for later
// retrieval
// allocate new list and add it to one just pushed (remember,
// I still have its reference).
// Assign nlist to list
// increment bracket count
case '[':
stack.push(list);
List<Object> nlist = new ArrayList<>();
list.add(nlist);
list = nlist;
bracketCount++;
break;
// state2 right bracket - Finished processing current sublist.
// if previous tokens were not brackets, then add the
// number to the list and pop off the previous one.
// decrement bracket count
case ']':
if (chars[i - 1] != '[' && chars[i - 1] != ']') {
list.add(num);
}
list = stack.pop();
bracketCount--;
break;
// state3 - whitespace - ignore
case ' ':
case '\t':
break;
// state4 comma - if previous token was not a right bracket,
// then add number. Reset num for next number.
case ',':
if (chars[i - 1] != ']') {
list.add(num);
}
num = 0;
break;
// state5 digit - assumed to be a digit. Each time a digit
// is encountered, update the number
default:
num = num * 10 + c - '0';
}
if (bracketCount < 0) {
System.out.println("too many ] brackets at location " + i);
}
}
if (bracketCount > 0) {
System.out.println("insufficent number of ] brackets");
}
System.out.println(list);
}
}
Note that in the above example, the "states" are rather "pseudo states." That is you don't need to check the current state you are in in order to determine how to process the current token or flag an error.
I'm stuck on creating a program to solve a question for a class. I have a main method and a secondary testing method that are working in conjunction to solve this problem, however I can't get the solution to work when there's a change.
The problem is making sure a word is square free, here's an excerpt from the problem:
For this part, implement a method called isSquareFree that takes as input (a reference to ) an array of characters. You may assume that the elements of the array are all lower case letters. (In other words, you do not need to worry about a question like: "is Z the same letter as z?") Your method should test if the given input array of characters is square-free. If it is, the method should print a message stating that, otherwise it should print a message stating that the world is not square-free, where the square subword starts and what that subword is. For example, if the given array contained the word zatabracabrac the method should print: The word, zatabracabrac, is not square free, since it has subword, abrac twice starting at position 4 of the word.
Below is the current code I have, it works in the case that there is a repeating character directly next to each other, but I'm unsure of how to continue to check if there is multiple repeating characters (abab for example) nor am I sure how to print out the repeating subword.
public static void main(String[] args) {
// part (a) of the main
Scanner keyboard = new Scanner(System.in);
System.out.println("***************************");
System.out.println(" Part (a)");
System.out.println("***************************");
do{
System.out.println("Enter a word and then press enter:");
String str=keyboard.next();
char[] word = str.toCharArray();
isSquareFree(word);
System.out.println("Do you want to test another word? Press y for yes, or another key for no");
}while(keyboard.next().charAt(0)=='y');
}
public static void isSquareFree(char[] word){
int sqf = 0;
for(int i=0; i<word.length; i++){
for(int j=0; j<word.length-1;j++){
if (word[j] == word[j+1]){
sqf = 1;
j = word.length;
}
else{
sqf = 2;
}
}
}
if (sqf == 1){
System.out.println();
System.out.println("Not Square Free");
}
else{
System.out.println();
System.out.println("Square Free");
}
}}
I'd also like to add that I'm not allowed to use the arrays class for this question, nor am I allowed to use strings and I cannot change the main method, not can I change the input for my other method.
To see if a sequence of characters repeats, for a given sequence length (say, n), you would replace your if with a loop that compares word[j+x] with word[j+n+x] for each value of x between 0 and n; and only consider them the same if all n match. Thus, you'd need to loop over these n values for x; if you need to consider different values of n, then you'd need yet another loop to go through those.
It isn't clear from your code what you are using i for, but if it is the length of the repeating part (what I've called n), then you'd only need to consider values up to half the length of word (or else there isn't room to repeat it).
To print out a sub word, you could print out each individual letter in order (using print instead of println)
I have to create a word game called "Lingo", so far everything is going well but lately I had problems occurring with the checks, in the game there are 3 checks.
//FIRST CHECK
for (int i=0;i<input.length();i++){
if(input.charAt(i)==CorrectWord.charAt(i)){
LingoBoard[0][i].setBackground(Color.GREEN);
//WHEN every letter(input) matches the correct word = the background(TextArea) becomes green.
//SECOND CHECK
else { LingoBoard[0][i].setBackground(Color.RED); }
//When the letters do not match the letters from the correct word = TextArea becomes red
//THIRD CHECK
//When the letters are in the correct word but not in the right place = TextArea becomes magenta
I'm stuck with the third check, i can't seem to find a way that can fix my problem.
i tried this, but it makes the background magenta for all 3 checks.
if((LingoBoard[0][i].getText().charAt(i)!=CorrectWord.charAt(i))){
LingoBoard[0][i].setBackground(Color.MAGENTA);
A better way of matching a correct word is:
if(input.equals(CorrectWord)) {
LingoBoard[0][i].setBackground(Color.GREEN);
}
Though I'm surprised that your code works as you have no closing curly brace (}) after that first if statement. Could you post the whole class, if it's not too large?
For the second and third check, you're better off doing something like the following:
if(!(input.equals(CorrectWord))) {
// create temporary array to match against
ArrayList<Character> tempArray = new ArrayList<Character>();
for(char c : input.toCharArray) {
// create from copy of player's input
tempArray.add(c);
}
// for each character in the solution
for(char c : CorrectWord.toCharArray()) {
// loop through the player's input
for(char d : input.toCharArray()) {
// and check if features there
if(d == c) {
tempArray.remove(d);
// we only want to remove one char at a time, so break if found
break;
}
}
}
// if all the letters have been found, regardless of their order
if(tempArray.size() == 0) {
LingoBoard[0][i].setBackground(Color.MAGENTA);
} else {
LingoBoard[0][i].setBackground(Color.RED);
}
}
Haven't tested the code, written it on the spot. I hate nested for loops but I haven't found a better way to handle char array manipulation.
This is an assignment i have to complete.
Can someone lead me in the right direction?
The program compiles but wont run correctly.
The error is InputMissmatch exception.
The error you are getting means that you are trying to use some kind of data as another one, in your case, you are probably trying to use a String as a float.
When using any of the next methods in the Scanner class you should first be sure that there's an appropiate input from the user.
In order to do so, you need to use the has methods.
Your problem is that you are not checking wether the input is a correct float or not before using your Scanner.nextFloat();
You should do something like this:
if (hope.hasNextFloat())
{
// Code to execute when you have a proper float,
// which you can retrieve with hope.nextFloat()
}
else
{
// Code to execute when the user input is not a float
// Here you should treat it properly, maybe asking for new input
}
That should be enough to point you in the right direction.
Also, check the Scanner api documentation for further details.
EDIT
Also, you are asking the user to input characters (or strings): "A", "B", etc..., but you are trying to compare them with a float. That's wrong, you should compare them with a string or character, like this:
if (hope.hasNextString())
{
if (hope.nextString().equals("A"))
{
// Code for option "A"
}
else if (hope.nextString().equals("B"))
{
// Code for option "B"
}
else ...
}
You could use a switch there, but it seems that you are not yet very fammiliar with java, so I'll leave it for another time.
Your problem is that you are entering a letter into a float field.
In your program you're asking the user to enter a float:
A = hope.nextFloat();
But if you enter the letter "A", you're going to get an exception because "A" is not a float, it's a string.
A simpler way to solve your problem is instead of having all the choices fields, you just read the input the user enters from the scanner like:
String choice = hope.next();
Next in the if statement, you check if the value from the string choice is equal to a specific letter, for example
if (choice.equals("A")) {
number4 = (number1 + number2 + number3);
System.out.printf("Your results are:" + (number4));
}
And you can do the same thing for the other choices you have.