Keeping track of digits before operator sign - java

For a calculator program, I keep track of all digits before an operator sign and limit their numbers to 12 with a counter, when an operator sign is selected, it resets the counter to zero. The problem with this is that if I delete the sign and continue editing those previous numbers, the count isn't in effect anymore because it has been reset to 0 after the operator sign. It there an alternative way to go about this?
Thanks in Advance!
private int numericCounter;
private boolean operatorAssigned;
private int cap = 12;
//if the number of digits is not 12, allow input
if (!(numericCounter >= cap)) {
textView.append(button.getText());
}
//if an operator "+" "-"...
//is rececived set numeric counter to 0
if (operatorAssigned) {
numericCounter = 0;
}
if (numericCounter == 0) {
operatorAssigned = false;
}
//Notification
if (numericCounter >= cap) {
Context context = getApplicationContext();
CharSequence text = "Maximum number of digits(12) reached";
int duration = Toast.LENGTH_SHORT;
//... show one Toast
if (mToast != null) mToast.cancel();
mToast = Toast.makeText(context, text, duration);
mToast.show();
//show another Toast
if (mToast != null) mToast.cancel();
mToast = Toast.makeText(context, text, duration);
mToast.show();
}
//if maximum number of digits allowed
//not equal to 12
//increment numeric counter by 1
if (!(numericCounter >= cap)) {
numericCounter++;
}
//Handles the delete button
findViewById(R.id.delete).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String text = textView.getText().toString();
if ((!text.isEmpty() && resultComputed == false)) {
String lastText = text.substring(0, text.length() - 1);
textView.setText(lastText);
lastNumeric = true;
//Checks if deleted text is a digit or an operator
if (lastText != "." || lastText != "+" || lastText != "-" || lastText != "/" || lastText != "/") {
numericCounter--;
}
} else if ((!text.isEmpty() && resultComputed == true)) {
textView.setText(txt);
resultComputed = false;
}
}
});

You could try a stack to keep a history of the counters. If you limit the stack to 2, you'll end up with the counter for the current number and the one for the previous number. Then, all you need to do is to manage the stack if you add/delete signs.

Just create a backup variable. something like
private int backUp = 0;
Then in your if(operatorAssigned) function,
do this:
backUp = numericCounter;
numbericCounter = 0;
This way, if and when you check for your deletion of operator, just assign the value of backUp to your numericCounter again.
This is just a very basic idea.

Related

JTextField limiting input after period

I'm writing a CashRegister program and I'm currently working on the CashierView where I have added an option for the Cashier to input the amount of cash received by the customer. I now formatted it so that the user only can input numbers and 1 period. I now want to limit the numbers you can input after the period to two. I'm struggling to make this work.
I commented out one of the codes that I tried, but didn't work, incase it might be interesting.
Appreciate all the help!
Br,
Victor
private void jCashReceivedKeyTyped(java.awt.event.KeyEvent evt) {
char c = evt.getKeyChar(); //Allows input of only Numbers and periods in the textfield
//boolean tail = false;
if ((Character.isDigit(c) || (c == KeyEvent.VK_BACKSPACE) || c == KeyEvent.VK_PERIOD)) {
int period = 0;
if (c == KeyEvent.VK_PERIOD) { //Allows only one period to be added to the textfield
//tail = false;
String s = getTextFieldCash();
int dot = s.indexOf(".");
period = dot;
if (dot != -1) {
evt.consume();
}
}
//. if (tail=true){ //This is the code that I tried to use to limit input after the period to two
// String x = getTextFieldCashTail();
// if (x.length()>1){
// evt.consume();
// }
// }
}
else {
evt.consume();
}
}
If you're dead set on doing this with a KeyEvent, here's one possible method:
private void jCashReceivedKeyTyped(java.awt.event.KeyEvent evt) {
char c = evt.getKeyChar(); //Allows input of only Numbers and periods in the textfield
if ((Character.isDigit(c) || (c == KeyEvent.VK_BACK_SPACE) || c == KeyEvent.VK_PERIOD)) {
String s = getTextFieldCash();
int dot = s.indexOf(".");
if(dot != -1 && c == KeyEvent.VK_PERIOD) {
evt.consume();
} else if(dot != -1 && c != KeyEvent.VK_BACK_SPACE){
String afterDecimal = s.substring(dot + 1);
if (afterDecimal.length() > 2) {
evt.consume();
}
}
}
}
Hope this helps. Just keep in mind that by listening to a KeyEvent, if someone copies and pastes values into your JTextField, this won't catch that. If you want to catch any possible type of input, you'll want to use a DocumentListener. If you're wondering how to use a DocumentListener, here is some code that shows how to use it on a JTextField.

How to Match Parenthesis to Parse a S-Expression?

I am trying to create a function that does the following:
Assuming that the code input is "(a 1 2 (b 3 4 5 (c 6) |7) 8 9)"
where the pipe | symbol is the position of the cursor,
the function returns:
a String "b 3 4 5 (c 6) 7" representing the code that is in the scope of the cursor
an int 8 representing the start index of the string relative to the input
an int 30 representing the end index of the string relative to the input
I already have working code that returns exactly that. However, the problem lies in ignoring comments, while keeping track of context (e.g. String literals, my own literal delimiters, etc).
Here is the code which keeps track of context:
public static void applyContext(Context context, String s, String snext, String sprev) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.context = Context.Contexts.MAIN;
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.context = Context.Contexts.MAIN;
} else if (s.equals("/") && snext.equals("/")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.COMMENT;
} else if (s.equals("\n")) {
if(context.context == Context.Contexts.COMMENT)
context.context = Context.Contexts.MAIN;
}
else if (s.equals("\\")) {
if(context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if(context.context == Context.Contexts.PATTERN)
context.context = Context.Contexts.MAIN;
}
}
Firstly, I'll be using the function above like so:
String sampleCode = "(a b "cdef" g \c4 bb2 eb4 g4v0.75\)";
Context c = new Context(Context.Contexts.MAIN);
for(int i = 0; i < sampleCode.length(); i++) {
String s = String.valueOf(sampleCode.charAt(i));
String snext = *nullcheck* ? String.valueOf(sampleCode.charAt(i + 1)) : "";
String sprev = *nullcheck* ? String.valueOf(sampleCode.charAt(i - 1)) : "";
applyContext(c, s, snext, sprev);
if(c.context == blahlbah) doBlah();
}
Second, I'll be using this both forwards an backwards, as the current method of doing the function stated at the top of the description is (in pseudocode) this:
function returnCodeInScopeOfCursor(theWholeCode::String, cursorIndex::int) {
var depthOfCodeAtCursorPosition::int = getDepth(theWholeCode, cursorIndex);
Context c = new Context(getContextAt(theWholeCode, cursorIndex));
var currDepth::int = depthOfCodeAtCursorPosition;
var startIndex::int, endIndex::int;
for(i = cursorIndex; i >= 0; i--) {//going backwards
s = .....
snext = ......
sprev = ......
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth --;
if s = ")" then currDepth ++;
}
when currDepth < depthOfCodeAtCursorPosition
startIndex = i + 1;
break;
}
currDepth = depthOfCodeAtCursorPosition;//reset
for(i = cursorIndex; i < theWholeCode.length; i++) {//going forwards
s = ...
snex......
sprev.....
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth ++;
if s = ")" then currDepth --;
}
when currDepth < depthOfCodeAtCursorPosition
endIndex = i - 1;
break;
}
var returnedStr = theWholeCode->from startIndex->to endIndex
return new IndexedCode(returnedStr, startIndex, endIndex);
As you can see, this function would work both forwards and in reverse. Or at least most of it. The only problem is that if I were to use this function backwards, the proper scanning of comments (denoted by the standard ECMA double slash "//") goes haywire.
If I were to create a separate function for reverse context application and check every line recursively for a double slash, then making everything after that '//' a COMMENT (or in the direction of the function's usage, everything before that //), it will take way too much processing time as I want to use this as a livecoding environment for music.
Also, removing the comments before trying to do that returnCodeInScopeOfCursor method may not be feasible... as I need to keep track of the indexes of the code and what not. If I were to remove the comments, there will be a big mess with all the code positions and keeping track of where did I remove what exactly and how many characters etc....
The text area input GUI I'm working with (RichTextFX) does not support Line-Char tracking, so everything is tracked using char index only, hence the problems...
So... I'm utterly perplexed as with what to do with my current code. Any help, suggestions, advice etc... will be greatly appreciated.
Could you pre-transform comments from // This is a comment<CR> to { This is a comment}<CR> you then have a language you can walk backwards and forwards.
Apply this transform on the way in and reverse it on the way out and all should be well. Notice we are replacing //... with {...} so all charaqcter offsets are retained.
Anyways, after a little experimenting with OldCurmudgeon's idea, I came up with a separate function to get context of the code in a reverse direction.
public static void applyContextBackwards(Context context, String entireCode, int caretPos) {
String s = String.valueOf(entireCode.charAt(caretPos));
//So far this is not used
//String snext = caretPos + 1 < entireCode.length() ? String.valueOf(entireCode.charAt(caretPos + 1)) : "";
String sprev = caretPos - 1 >= 0 ? String.valueOf(entireCode.charAt(caretPos - 1)) : "";
//Check for all the flags and what not...
if(context.commentedCharsLeft > 0) {
context.commentedCharsLeft--;
if(context.commentedCharsLeft == 0)
context.context = Context.Contexts.MAIN;//The comment is over
}
if(context.expectingEndOfString){
context.context = Context.Contexts.MAIN;
context.expectingEndOfString = false;
}
if(context.expectingEndOfPattern) {
context.context = Context.Contexts.MAIN;
context.expectingEndOfPattern = false;
}
//After all the flags are cleared, do this
if(context.commentedCharsLeft == 0) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.expectingEndOfString = true;//Change the next char to a MAIN, cuz this one's still part of the string
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.expectingEndOfString = true;//Change the next char to a MAIN, cuz this one's still part of the string
} else if (s.equals("\n")) {
int earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine = -1;//-1 for no comments
//Loop until the next \n is found. In the process, determine location of comment if any
for(int i = caretPos; i >= 0; i--) {
String curr = String.valueOf(entireCode.charAt(i));
String prev = i - 1 >= 0 ? String.valueOf(entireCode.charAt(i - 1)) : "";
if(curr.equals("\n"))
break;//Line has been scanned through
if(curr.equals("/") && prev.equals("/"))
earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine = caretPos - i;
}
//Set the comment context flag
//If no comments, -1 + 1 will be 0 and will be treated as no comments.
context.commentedCharsLeft = earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine + 1;
if(earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine > 0) {
context.context = Context.Contexts.COMMENT;
}
} else if (s.equals("\\")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if (context.context == Context.Contexts.PATTERN)
context.expectingEndOfPattern = true;//Change the next char to a MAIN cuz this one's still part of the Pattern
}
}
}

if there a better way to write this if statment in java

So is there a way to simplify this to make is smaller in anyway?
else if(selectedCards.size() == 3
&& cardAt(selectedCards.get(0)).pointValue() + cardAt(selectedCards.get(1)).pointValue() + cardAt(selectedCards.get(2)).pointValue() == 0
&& !cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(1)).rank())
&& !cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(2)).rank())
&& !cardAt(selectedCards.get(1)).rank().equals(cardAt(selectedCards.get(2)).rank()))
From what I can see you're trying to test if the 3 cards have different ranks. An easier way to test this is to put them into a Set and see if the set size is same as selected set. This scales to any number of selected cards...
public boolean differentRanks(List<Integer> selectedCards) {
Set<Integer> ranks = new HashSet<Integer>();
for (int card : selectedCards) {
ranks.add(cardAt(card).rank());
}
return ranks.size() == selectedCards.size();
}
I'd also create a method to total the points for the selected cards...
public int sum(List<Integer> selectedCards) {
int total;
for (int card : selectedCards) {
total += cardAt(card).pointValue();
}
return total;
}
So the condition would end up
} else if (selectedCards.size() == 3 && sum(selectedCards) == 0 &&
differentRanks(selectedCards) {
This would be one option:
else if(selectedCards.size() == 3
&& cardAt(selectedCards.get(0)).pointValue() + cardAt(selectedCards.get(1)).pointValue() + cardAt(selectedCards.get(2)).pointValue() == 0
&& !(cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(1)).rank())).equals(cardAt(selectedCards.get(2)).rank()) )
To make more readable this condition you could do something like this:
//here you extract the values you need only once and use them in your condition block below
int cardsSize = selectedCards.size();
int pointValue0 = cardsSize == 3 ? cardAt(selectedCards.get(0)).pointValue() : 0;
int pointValue1 = cardsSize == 3 ? cardAt(selectedCards.get(1)).pointValue() : 0;
int pointValue2 = cardsSize == 3 ? cardAt(selectedCards.get(2)).pointValue() : 0;
bool rankEquals = CompareRanks(cardAt(selectedCards.get(0)),cardAt(selectedCards.get(1)),cardAt(selectedCards.get(2));
if (<condition>) {
//block of sentences
} else if (cardsSize == 3 && (pointValue0 + pointValue1 + pointValue2) == 0 && !rankEquals )
I'm suggesting the creation of a function called "CompareRanks" where you receive 3 different objects (result of "cardAt") and you get the rank in there and compare if the values are the same or not.
This option leads you to more lines of code but is cleaner and more readable for any person besides you.
In my opinion most readable:
else if(selectedCards.size() == 3 && checkRanks(selectedCards))
{
//...
}
//...
private boolean checkRanks(List<Card> cards)
{
Card zeroCard = cardAt(selectedCards.get(0));
Card firstCard = cardAt(selectedCards.get(1));
Card secondCard = cardAt(selectedCards.get(2));
boolean isZero = zeroCard.pointValue() + firstCard.pointValue() + secondCard.pointValue() == 0;
boolean zeroCardRankNotEqualFirst = !zeroCard.rank().equals(firstCard.rank())
boolean zeroCardRankNotEqualSecond = !zeroCard.rank().equals(secondCard.rank())
boolean firstCardRankNotEqualsSecond = !firstCard.rank().equals(secondCard.rank());
return isZero && zeroCardRankNotEqualFirst && zeroCardRankNotEqualSecond && firstCardRankNotEqualsSecond;
}

Else if condition being ignored?

I'm new to Java and i have to make a small application that will calculate GCD of up to 5 numbers.
If the input is nothing before 5 numbers have been entered, the application will calculate it on the already given numbers
Unfortunately my code seems to ignore my else if statement that will make sure it doesn't try to add "" to a int array.
This is the part that i am struggling on, i have already tried contains instead of equals but with no result.
Am i writing the !input.. wrong? The code runs correct when i try to add a 0, it will not execute the else if.
But if i enter "" to make the application run the first part of the if statement it will go to the else if after its done and try to add "" to the array which of course results in an error.
I'm sure its something small i am missing or am unaware of, but i can't seem to figure it out.
}else if(Integer.parseInt(input) != 0 || !input.equals(""));{
ggdGetallen[count] = Integer.parseInt(input);
count++;
txtGetal.selectAll();
}
Full code
private void txtGetalActionPerformed(java.awt.event.ActionEvent evt) {
String input = txtGetal.getText();
//Berekenen van het kleinste getal in het array
if(count > 4 || input.equals("")){
int kleinsteGetal = ggdGetallen[0];
for (int getal : ggdGetallen){
if (getal < kleinsteGetal && getal != 0){
kleinsteGetal = getal;
}
}
boolean isDividableBy;
boolean ggdFound = false;
while(!ggdFound){
for (int getal : ggdGetallen) {
if (getal != 0){
isDividableBy = (getal % kleinsteGetal == 0);
ggdFound = true;
if(!isDividableBy){
kleinsteGetal--;
ggdFound = false;
break;
}
}
}
}
lblResultaat.setText(String.format("De grootste gemene deler is %d", kleinsteGetal));
}else if(Integer.parseInt(input) != 0 || !input.equals(""));{
ggdGetallen[count] = Integer.parseInt(input);
count++;
txtGetal.selectAll();
}
}
remove semicolon from your else if.

While Loops and Reverse Fibonacci

I've come across a problem. I'm trying to make a class which takes the maximum number that a user puts in and adds the integer before it until it gets to 0, however, when I run it, the numbers get larger and larger until it crashes. What seems to be throwing this into an infinite loop?
public class Summation {
public static void main(String[] args) {
EasyReader console = new EasyReader();
System.out.print("Debug? (Y/N): ");
char debug = console.readChar();
if ((debug!='Y')&&(debug!='N')){
System.out.println("Please enter Y or N");
main(null);
}
else{
System.out.print("Enter max range:");
int max = console.readInt();
int s = sum(max,debug);
System.out.print(s);
}
}
public static int sum(int m, char d){
int sm = 1;
boolean isRunning = true;
while ((isRunning == true)&&(d=='Y')){
if ((--m)==0) {
isRunning = false;
}
else{
sm = m+(--m);
System.out.println("sm is"+sm);
}
while ((isRunning == true)&&(d=='N')){
if ((--m)==0) {
isRunning = false;
}
else{
sm = m+(--m);
}
}
}return sm;
}
}
There's a scenario where your condition for exit
if ((--m)==0)
will never again be reached, because m is already less than 0, and it's never going back.
that scenario is whenever m is an even number.
while ((isRunning == true)&&(d=='Y'))
{
// this condition decriments `m` every time it runs, regardless of whether it evaluates to true
if ((--m)==0)
{
// if `m` was set to 0 on your last iteration, it will be set to -1
isRunning = false;
}
else
{
// if m is 1 before this line it will be 0 after it.
sm = m+(--m);
System.out.println("sm is"+sm);
}
while ((isRunning == true)&&(d=='N'))
{
// this code will never get executed
}
}
return sm;
Answer to your problem is very simple
Just modify the condition
if (m==0) {
isRunning = false;
}
When you are checking --m == 0, it is very much possible that m will be jumping over 0 and will enter negative territory without even setting this condition to be true.
Everything you are doing is wrong :).
First - FORMATTING. You maybe even dont know that, but the second while is INSIDE the first while cycle. If you use netbeans, its ALT+SHIFT+F.
The using of --m is not good for your example, cause it firsts decrease the "m" value and then it compares. So even when you asking at
(--m)==0
you decrease a value. And because you are using it again at
sm = m+(--m)
you can even skip the "0" value and get into negative numbers.
However if you want only "add numbers in reverse order from given number to 0 in while loop" it is not fibonacci and you can use this code (it could be done better, but this is using your code) :
public class Summation {
public static void main(String[] args) {
System.out.println(sum(10, 'Y'));
}
public static int sum(int m, char d) {
int sm = 0;
boolean isRunning = true;
while ((isRunning == true) && (d == 'Y')) {
sm += m;
if (m == 0) {
isRunning = false;
} else {
m--;
System.out.println("sm is" + sm);
}
while ((isRunning == true) && (d == 'N')) {
if ((--m) == 0) {
isRunning = false;
} else {
sm = m + (--m);
}
}
}
return sm;
}
}
Note that second while cycle couldnt be reached - it passes only when "d == Y" and then it starts only when "d == N"

Categories

Resources