Created
February 24, 2020 14:31
-
-
Save gfreivasc/945c8a00f0bfa5db7e487baf4fa7360b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.gabrielfv.sandbox.rpn; | |
import java.util.Scanner; | |
import java.util.Stack; | |
/** | |
* Calculadora RPN interativa. | |
* | |
* RPN = Reverse Polish Notation, ou Notação Polonesa Inversa. | |
* (https://pt.wikipedia.org/wiki/Nota%C3%A7%C3%A3o_polonesa_inversa) | |
* | |
* Cada resultado intermediário durante a execução (ou seja, resultado obtido | |
* enquanto ainda existem outros números na pilha) é indicado por uma seta ">". | |
* Quando a pilha for esvaziada pelas operações, uma dupla seta indica o estado | |
* ">>". | |
*/ | |
public class RpnCalculator { | |
private static Scanner scanner = new Scanner(System.in); | |
/* | |
* Estrutura de pilha é a estrutura base de uma calculadora | |
* RPN. Os números são empilhados e cada operação remove os dois | |
* primeiros elementos da pilha, opera sobre eles e coloca o resultado | |
* de volta na pilha, para que seja possível prosseguir a operação. | |
* | |
* TODO: Ler sobre e entender estruturas de Pilha e Fila | |
* TODO: Pergunta: O que é FILO e FIFO? | |
*/ | |
private static Stack<Integer> buffer = new Stack<>(); | |
public static void main(String[] args) { | |
System.out.println("Digite inicie a operação (s para sair): "); | |
String input = ""; | |
while (!input.equals("s")) { | |
input = scanner.next(); | |
if (isInteger(input)) { | |
buffer.push(Integer.parseInt(input)); | |
} else if (isOperation(input)) { | |
int current = parseOperation(input, buffer); | |
if (buffer.size() == 0) { | |
System.out.println(">> " + current); | |
} else { | |
System.out.println("> " + current); | |
} | |
buffer.push(current); | |
} | |
} | |
} | |
// Aqui é necessário entender com cuidado algumas definições de uma RPN. | |
// Cada operação depende de dois números. Se há apenas um item na pilha | |
// quando for requisitada a operação, nada deve ocorrer e o numeral deve | |
// retornar à pilha. Se não houver nada na pilha, o número 0 deve ser | |
// colocado. O retorno deste método é o que será colocado na pilha. Perceba | |
// que [buffer.pop()] é chamado duas vezes, indicando que dois números são | |
// retirados, enquanto apenas um (o resultado entre eles) é colocado de volta. | |
public static int parseOperation(String operation, Stack<Integer> buffer) { | |
int result = (buffer.empty()) ? 0 : buffer.pop(); | |
if (!buffer.empty()) { | |
result = operate(operation, buffer.pop(), result); | |
} | |
return result; | |
} | |
// É necessário se atentar ao fato de que não é possível dividir por 0. | |
// Este é um problema comum em programação: Ter de tratar possíveis entradas | |
// inválidas que o usuário possa introduzir ao programa. No caso optamos por | |
// indicar o erro e em caso de operação inválida, manter o último número que | |
// havia anteriormente na pilha. | |
public static int operate(String operation, int left, int right) { | |
switch (operation) { | |
case "+": return left + right; | |
case "-": return left - right; | |
case "*": return left * right; | |
case "/": { | |
if (right == 0) { | |
System.out.println("ERR: Cannot divide by 0"); | |
return left; | |
} | |
return left / right; | |
} | |
default: return left; | |
} | |
} | |
// Para evitar prosseguir para estados inválidos por erro de digitação, | |
// os métodos abaixo verificam se a entrada do usuário pertence a uma de | |
// duas possíveis naturezas: | |
// É um numeral inteiro, ou | |
// É uma operação reconhecida | |
// Para que assim possamos prosseguir pro comportamento correto | |
public static boolean isInteger(String input) { | |
if (input == null) return false; | |
try { | |
Integer.parseInt(input); | |
} catch (NumberFormatException ex) { | |
return false; | |
} | |
return true; | |
} | |
public static boolean isOperation(String input) { | |
if (input == null) return false; | |
return input.equals("+") || input.equals("-") || input.equals("*") || input.equals("/"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment