Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1 task #346

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions homework-g596-narsia/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mipt-java-2016</artifactId>
<groupId>ru.mipt.java2016</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>homework-g596-narsia</artifactId>
<dependencies>
<dependency>
<groupId>ru.mipt.java2016</groupId>
<artifactId>homework-base</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>ru.mipt.java2016</groupId>
<artifactId>homework-tests</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>


</project>
Binary file added homework-g596-narsia/src/description.pdf
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
package ru.mipt.java2016.homework.g596.narsia.task1;

import ru.mipt.java2016.homework.base.task1.Calculator;
import ru.mipt.java2016.homework.base.task1.ParsingException;

import java.util.*;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Считается плохим тоном импортировать через *. Перечисли всё, что ты импортируешь отдельно


// подробное описание работы кода
// можно найти в файле description
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Пиши комментарии прямо в коде



public class MyCalculator implements Calculator {
private enum SymbolType { DIGIT, POINT, USUAL_OPERATOR, MINUS, SPACE,
OPENING_BRACKET, CLOSING_BRACKET, FIRST, INVALID }


private SymbolType whatIsIt(Character symbol) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не слишком-то похоже на понятное название
Почему принимает Character?

if (Character.isDigit(symbol)) {
return SymbolType.DIGIT;
}
if (symbol.equals('.')) {
return SymbolType.POINT;
}
if ((symbol.equals('+')) || (symbol.equals('*')) || (symbol.equals('/'))) {
return SymbolType.USUAL_OPERATOR;
}
if (symbol.equals('-')) {
return SymbolType.MINUS;
}
if (Character.isWhitespace(symbol)) {
return SymbolType.SPACE;
}
if (symbol.equals('(')) {
return SymbolType.OPENING_BRACKET;
}
if (symbol.equals(')')) {
return SymbolType.CLOSING_BRACKET;
}
if (symbol.equals('~')) {
return SymbolType.FIRST;
}
return SymbolType.INVALID;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Во многих языках программирования есть такая штука, как assert. Его используют, чтобы поймать некорректные состояния. Этот твой SymbolType.INVALID - как раз такое состояние. Кидай отсюда исключение

}


private void isAlmostValid(String expression) throws ParsingException {
if (expression == null) {
throw new ParsingException("Invalid expression");
}
char prevSymbol = '~';
char curSymbol;
char importantPrevSymbol = '~';
boolean pointFlag = false;
boolean spaceFlag = false;

for (int index = 0; index < expression.length(); ++index) {
curSymbol = expression.charAt(index);
switch (whatIsIt(curSymbol)) {
case DIGIT:
if (whatIsIt(prevSymbol) == SymbolType.SPACE) {
if ((whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) ||
(whatIsIt(importantPrevSymbol) == SymbolType.CLOSING_BRACKET)) {
throw new ParsingException("Invalid expression");
}
}
if (whatIsIt(prevSymbol) == SymbolType.CLOSING_BRACKET) {
throw new ParsingException("Invalid expression");
}
break;

case POINT:
if (whatIsIt(prevSymbol) == SymbolType.DIGIT) {
if (!pointFlag) {
pointFlag = true;
} else {
throw new ParsingException("2 points in one number");
}
} else {
throw new ParsingException("Invalid expression");
}
break;

case USUAL_OPERATOR:
if ((whatIsIt(importantPrevSymbol) == SymbolType.USUAL_OPERATOR) ||
(importantPrevSymbol == '(') || (importantPrevSymbol == '~') ||
(importantPrevSymbol == '.')) {
throw new ParsingException("Invalid expression");
}
if (whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) {
pointFlag = false;
}
break;

case MINUS:
if (importantPrevSymbol == '.') {
throw new ParsingException("Invalid expression");
}
if (whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) {
pointFlag = false;
}
break;

case SPACE:
if (prevSymbol == '.') {
throw new ParsingException("Invalid expression");
}
if (whatIsIt(prevSymbol) == SymbolType.DIGIT) {
pointFlag = false;
}
break;

case OPENING_BRACKET:
if ((whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) ||
(importantPrevSymbol == '.') || (importantPrevSymbol == ')')) {
throw new ParsingException("Invalid expression");
}
break;

case CLOSING_BRACKET:
if (whatIsIt(importantPrevSymbol) == SymbolType.DIGIT) {
pointFlag = false;
}
if ((importantPrevSymbol == '.') || (importantPrevSymbol == '(') ||
(importantPrevSymbol == '~') ||
(whatIsIt(importantPrevSymbol) == SymbolType.USUAL_OPERATOR) ||
(importantPrevSymbol == '-')) {
throw new ParsingException("Invalid expression");
}
break;

default:
throw new ParsingException("Invalid expression");
}
prevSymbol = curSymbol;
if (whatIsIt(curSymbol) != SymbolType.SPACE) {
importantPrevSymbol = curSymbol;
spaceFlag = true;
}
}
if (!spaceFlag) {
throw new ParsingException("Invalid expression");
}
}


private String removeSpaces(String expression) {
StringBuilder result = new StringBuilder(expression.length());
for (int index = 0; index < expression.length(); ++index) {
if (!Character.isWhitespace(expression.charAt(index))) {
result.append(expression.charAt(index));
}
}
return result.toString();
}


private String removeUnaryMinuses(String expressionWithoutSpaces) {
expressionWithoutSpaces = expressionWithoutSpaces.concat("~");
StringBuilder result = new StringBuilder(expressionWithoutSpaces.length());
boolean bracketFlag = false;
for (int index = 0; index < expressionWithoutSpaces.length(); ++index) {
if (expressionWithoutSpaces.charAt(index) == '-') {
if (index == 0) {
result.append('0');
} else {
switch (whatIsIt(expressionWithoutSpaces.charAt(index - 1))) {
case OPENING_BRACKET:
result.append("0-");
continue;
case USUAL_OPERATOR:
case MINUS:
result.append("(0-");
bracketFlag = true;
continue;
default:
break;
}
}
}
if ((!Character.isDigit(expressionWithoutSpaces.charAt(index))) &&
(expressionWithoutSpaces.charAt(index) != '.') && (index > 0) && (bracketFlag)) {
result.append(")");
bracketFlag = false;
}
if (expressionWithoutSpaces.charAt(index) != '~') {
result.append(expressionWithoutSpaces.charAt(index));
}
}
return result.toString();
}


private int getCode(char first, char second) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как говорили Великие:

А какой именно код возвращает эта функция? Лично мне сходу вообще непонятна семантика этой функции, в которой к тому же ещё и вложенные switch блоки, а значения кодов - тайна, покрытая мраком и нигде не задокументированная.

Почему не сделать enum вместо цифр? С ним назначение функции слегка прояснится. Заодно можно будет переименовать getCode во что-нибудь более определенное

switch (first) {
case '~':
if ((whatIsIt(second) == SymbolType.USUAL_OPERATOR) ||
(second == '-') || (second == '(')) {
return 1;
}
if (second == '~') {
return 4;
}
if (second == ')') {
return 5;
}
case '+':
case '-':
if ((second == '*') || (second == '/') || (second == '(')) {
return 1;
}
if ((second == '~') || (second == ')') ||
(second == '+') || (second == '-')) {
return 2;
}
case '*':
case '/':
if (second == '(') {
return 1;
}
if ((second == '~') || (second == ')') ||
(whatIsIt(second) == SymbolType.USUAL_OPERATOR) ||
(second == '-')) {
return 2;
}
case '(':
if ((second == '(') || (whatIsIt(second) == SymbolType.USUAL_OPERATOR) ||
second == '-') {
return 1;
}
if (second == ')') {
return 3;
}
if (second == '~') {
return 5;
}
default:
return -1;
}
}


private String getRPN(String expression) throws ParsingException {
expression = expression.concat("~");
Character curSymbol;
Character prevSymbol = '~';
Stack<Character> texas = new Stack<>();
StringBuilder california = new StringBuilder(expression.length());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

То, что в статье, которую ты скинул, есть слова Техас и Калифорния, ещё не значит, что их нужно использовать, как названия переменных. Придумай что-нибудь более говорящее

texas.push('~');

int index = 0;
while (true) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как интересно ты в исходном решении заменил for на while.

curSymbol = expression.charAt(index);
if (index > 0) {
prevSymbol = expression.charAt(index - 1);
}
switch (whatIsIt(curSymbol)) {
case DIGIT:
case POINT:
if ((Character.isDigit(prevSymbol)) || (prevSymbol == '.') ||
(prevSymbol == '~')) {
california.append(curSymbol);
++index;
} else {
california.append(" ");
california.append(curSymbol);
++index;
break;
}
continue;

default:
break;
}

switch (getCode(texas.peek(), curSymbol)) {
case 1:
texas.push(curSymbol);
++index;
break;
case 2:
california.append(" ");
california.append(texas.peek());
texas.pop();
break;
case 3:
texas.pop();
++index;
break;
case 4:
return california.toString();
case 5:
throw new ParsingException("Invalid bracket balance");
default:
break;
}
}
}


private double doOperation(double first, double second, char operator) {
switch (operator) {
case '+':
return first + second;
case '-':
//сейчас будет костыль
if ((first == 0) && (second == 0)) {
return -0.0;
}
return first - second;
case '*':
return first * second;
case '/':
return first / second;
default:
return -1.0;
}
}


@Override
public double calculate(String expression) throws ParsingException {
isAlmostValid(expression);
String withoutSpaces = removeSpaces(expression);
String withoutSpacesAndUnaryMinuses = removeUnaryMinuses(withoutSpaces);
String rpn = getRPN(withoutSpacesAndUnaryMinuses);
Stack<Double> numbers = new Stack<>();
Double first;
Double second;
StringBuilder curNumber = new StringBuilder();
char curChar = '~';
char prevChar;
for (int cnt = 0; cnt < rpn.length(); ++cnt) {
prevChar = curChar;
curChar = rpn.charAt(cnt);
switch (whatIsIt(curChar)) {
case DIGIT:
case POINT:
curNumber.append(curChar);
break;
case USUAL_OPERATOR:
case MINUS:
second = numbers.peek();
numbers.pop();
first = numbers.peek();
numbers.pop();
numbers.push(doOperation(first, second, curChar));
break;
case SPACE:
if (Character.isDigit(prevChar)) {
numbers.push(Double.parseDouble(curNumber.toString()));
curNumber.delete(0, curNumber.length());
}
default:
break;
}
}
return numbers.peek();
}
}
Loading