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

계산기 [STEP2] 가마 #582

Open
wants to merge 27 commits into
base: ic_11_forseaest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
56bb569
Refactor: CalculatorTests에 given-when-then 패턴 적용
forseaest Feb 14, 2024
8856f53
Feat: Operator 열거형 구현
forseaest Feb 14, 2024
f1e0eff
Feat: Formula 구조체 생성
forseaest Feb 14, 2024
5bb2a92
Feat: CalculatorItemQueue에 제네릭 적용
forseaest Feb 14, 2024
ae8c99a
Refactor: Operator에 은닉화 적용
forseaest Feb 14, 2024
67df33a
Feat: CalculatorTests에 제네릭 적용
forseaest Feb 14, 2024
24bdab5
Feat: Formula 구조체의 result 함수 로직 구현
forseaest Feb 14, 2024
4b0a17d
Feat: ExpressionParser 열거형 구현
forseaest Feb 14, 2024
ad1e070
Rename: ExpressionParser 관련 변수명 수정
forseaest Feb 14, 2024
e521136
Feat: Double 익스텐션 생성
forseaest Feb 14, 2024
0129742
Feat: String 익스텐션 생성 및 split 함수 구현
forseaest Feb 14, 2024
9203360
Chore: 파일 순서 변경
forseaest Feb 14, 2024
2c56234
Refactor: CalculatorItemQueue에서 CalculateItem, Double 익스텐션 분리
forseaest Feb 14, 2024
a1d431d
Fix: 나누기를 했을 때 몫이 아닌 나머지가 나오는 현상 해결
forseaest Feb 14, 2024
fdf89ee
Refactor: Operator의 함수 호출방법 변경
forseaest Feb 14, 2024
3584ae6
Style: 타입 명시하는 코딩 컨벤션 통일
forseaest Feb 17, 2024
d7d4c40
Feat: 0으로 나누기를 시도하는 경우에 대해 에러 처리 적용
forseaest Feb 19, 2024
1e12782
Rename: CalculatorTests에서 CalculatorItemQueueTests로 파일 및 클래스명 변경
forseaest Feb 19, 2024
41e1b02
[Feat] Formula 유닛 테스트 작성
forseaest Feb 19, 2024
f2d8334
[Refactor] Formula의 프로퍼티 초기화 진행
forseaest Feb 19, 2024
1e20eab
[Chore] ExpressionParser에서 사용하는 수식 기호 변경
forseaest Feb 22, 2024
59c8906
[Chore] Operator에서 사용하는 수식 기호 변경
forseaest Feb 22, 2024
b82fdf3
Rename: 폴더 구조 변경
forseaest Feb 23, 2024
278bde4
Chore: 불필요한 코드 삭제
forseaest Feb 23, 2024
701f69e
Chore: Formula에서 사용하는 수식 기호 변경
forseaest Feb 26, 2024
dd0018c
Refactor: Formula의 operators 배열의 자료형을 String에서 Operator로 변경
forseaest Feb 27, 2024
b192ff9
Refactor: ExpressionParser에서 하드코딩한 사칙연산자 Operator 열거형으로 변경
forseaest Feb 27, 2024
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
80 changes: 72 additions & 8 deletions Calculator/Calculator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@
objects = {

/* Begin PBXBuildFile section */
06145E582B792BA500F39DD3 /* CalculatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06145E572B792BA500F39DD3 /* CalculatorTests.swift */; };
060891552B8348B100002F9B /* CalculatorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 060891542B8348B100002F9B /* CalculatorError.swift */; };
060891572B834DF600002F9B /* FormulaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 060891562B834DF600002F9B /* FormulaTests.swift */; };
06145E582B792BA500F39DD3 /* CalculatorItemQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06145E572B792BA500F39DD3 /* CalculatorItemQueueTests.swift */; };
06145E5F2B792C1000F39DD3 /* CalculatorItemQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06145E5E2B792C1000F39DD3 /* CalculatorItemQueue.swift */; };
06EA151C2B7CDA22001821CA /* Operator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EA151B2B7CDA22001821CA /* Operator.swift */; };
06EA15202B7CFFB2001821CA /* Formula.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EA151F2B7CFFB2001821CA /* Formula.swift */; };
06EA15222B7D0084001821CA /* ExpressionParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EA15212B7D0084001821CA /* ExpressionParser.swift */; };
06EA15282B7D4B76001821CA /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EA15272B7D4B76001821CA /* StringExtension.swift */; };
06EA152A2B7D4CF4001821CA /* DoubleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EA15292B7D4CF4001821CA /* DoubleExtension.swift */; };
06EA152C2B7D4D11001821CA /* CalculateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EA152B2B7D4D11001821CA /* CalculateItem.swift */; };
C713D9422570E5EB001C3AFC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C713D9412570E5EB001C3AFC /* AppDelegate.swift */; };
C713D9442570E5EB001C3AFC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C713D9432570E5EB001C3AFC /* SceneDelegate.swift */; };
C713D9462570E5EB001C3AFC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C713D9452570E5EB001C3AFC /* ViewController.swift */; };
Expand All @@ -28,9 +36,17 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
060891542B8348B100002F9B /* CalculatorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorError.swift; sourceTree = "<group>"; };
060891562B834DF600002F9B /* FormulaTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormulaTests.swift; sourceTree = "<group>"; };
06145E552B792BA500F39DD3 /* CalculatorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CalculatorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
06145E572B792BA500F39DD3 /* CalculatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorTests.swift; sourceTree = "<group>"; };
06145E572B792BA500F39DD3 /* CalculatorItemQueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorItemQueueTests.swift; sourceTree = "<group>"; };
06145E5E2B792C1000F39DD3 /* CalculatorItemQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorItemQueue.swift; sourceTree = "<group>"; };
06EA151B2B7CDA22001821CA /* Operator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operator.swift; sourceTree = "<group>"; };
06EA151F2B7CFFB2001821CA /* Formula.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formula.swift; sourceTree = "<group>"; };
06EA15212B7D0084001821CA /* ExpressionParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpressionParser.swift; sourceTree = "<group>"; };
06EA15272B7D4B76001821CA /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
06EA15292B7D4CF4001821CA /* DoubleExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleExtension.swift; sourceTree = "<group>"; };
06EA152B2B7D4D11001821CA /* CalculateItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculateItem.swift; sourceTree = "<group>"; };
C713D93E2570E5EB001C3AFC /* Calculator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Calculator.app; sourceTree = BUILT_PRODUCTS_DIR; };
C713D9412570E5EB001C3AFC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C713D9432570E5EB001C3AFC /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -62,11 +78,51 @@
06145E562B792BA500F39DD3 /* CalculatorTests */ = {
isa = PBXGroup;
children = (
06145E572B792BA500F39DD3 /* CalculatorTests.swift */,
06145E572B792BA500F39DD3 /* CalculatorItemQueueTests.swift */,
060891562B834DF600002F9B /* FormulaTests.swift */,
);
path = CalculatorTests;
sourceTree = "<group>";
};
06D0E84E2B883BE400F3113E /* Model */ = {
isa = PBXGroup;
children = (
06145E5E2B792C1000F39DD3 /* CalculatorItemQueue.swift */,
06EA151F2B7CFFB2001821CA /* Formula.swift */,
06EA15212B7D0084001821CA /* ExpressionParser.swift */,
06EA152B2B7D4D11001821CA /* CalculateItem.swift */,
06EA151B2B7CDA22001821CA /* Operator.swift */,
060891542B8348B100002F9B /* CalculatorError.swift */,
);
path = Model;
sourceTree = "<group>";
};
06D0E84F2B883BFD00F3113E /* Controller */ = {
isa = PBXGroup;
children = (
C713D9452570E5EB001C3AFC /* ViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
};
06D0E8502B883C0600F3113E /* View */ = {
isa = PBXGroup;
children = (
C713D9472570E5EB001C3AFC /* Main.storyboard */,
C713D94C2570E5ED001C3AFC /* LaunchScreen.storyboard */,
);
path = View;
sourceTree = "<group>";
};
06D0E8512B883CE400F3113E /* Extension */ = {
isa = PBXGroup;
children = (
06EA15292B7D4CF4001821CA /* DoubleExtension.swift */,
06EA15272B7D4B76001821CA /* StringExtension.swift */,
);
path = Extension;
sourceTree = "<group>";
};
C713D9352570E5EB001C3AFC = {
isa = PBXGroup;
children = (
Expand All @@ -88,13 +144,13 @@
C713D9402570E5EB001C3AFC /* Calculator */ = {
isa = PBXGroup;
children = (
06D0E8512B883CE400F3113E /* Extension */,
06D0E84E2B883BE400F3113E /* Model */,
06D0E8502B883C0600F3113E /* View */,
06D0E84F2B883BFD00F3113E /* Controller */,
C713D9412570E5EB001C3AFC /* AppDelegate.swift */,
C713D9432570E5EB001C3AFC /* SceneDelegate.swift */,
C713D9452570E5EB001C3AFC /* ViewController.swift */,
06145E5E2B792C1000F39DD3 /* CalculatorItemQueue.swift */,
C713D9472570E5EB001C3AFC /* Main.storyboard */,
C713D94A2570E5ED001C3AFC /* Assets.xcassets */,
C713D94C2570E5ED001C3AFC /* LaunchScreen.storyboard */,
C713D94F2570E5ED001C3AFC /* Info.plist */,
);
path = Calculator;
Expand Down Expand Up @@ -200,7 +256,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
06145E582B792BA500F39DD3 /* CalculatorTests.swift in Sources */,
060891572B834DF600002F9B /* FormulaTests.swift in Sources */,
06145E582B792BA500F39DD3 /* CalculatorItemQueueTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -210,7 +267,14 @@
files = (
C713D9462570E5EB001C3AFC /* ViewController.swift in Sources */,
C713D9422570E5EB001C3AFC /* AppDelegate.swift in Sources */,
06EA15202B7CFFB2001821CA /* Formula.swift in Sources */,
06EA152A2B7D4CF4001821CA /* DoubleExtension.swift in Sources */,
06EA151C2B7CDA22001821CA /* Operator.swift in Sources */,
06EA152C2B7D4D11001821CA /* CalculateItem.swift in Sources */,
06EA15282B7D4B76001821CA /* StringExtension.swift in Sources */,
060891552B8348B100002F9B /* CalculatorError.swift in Sources */,
C713D9442570E5EB001C3AFC /* SceneDelegate.swift in Sources */,
06EA15222B7D0084001821CA /* ExpressionParser.swift in Sources */,
06145E5F2B792C1000F39DD3 /* CalculatorItemQueue.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@
import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}


}

12 changes: 12 additions & 0 deletions Calculator/Calculator/Extension/DoubleExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// DoubleExtension.swift
// Calculator
//
// Created by H on 2/15/24.
//

import Foundation

extension Double: CalculateItem {

}
14 changes: 14 additions & 0 deletions Calculator/Calculator/Extension/StringExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// StringExtension.swift
// Calculator
//
// Created by H on 2/15/24.
//

import Foundation

extension String {
func split(with target: Character) -> [String] {
return self.split(separator: target).map { String($0) }
}
}
12 changes: 12 additions & 0 deletions Calculator/Calculator/Model/CalculateItem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// CalculateItem.swift
// Calculator
//
// Created by H on 2/15/24.
//

import Foundation

protocol CalculateItem {

}
12 changes: 12 additions & 0 deletions Calculator/Calculator/Model/CalculatorError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// CalculatorError.swift
// Calculator
//
// Created by H on 2/19/24.
//

import Foundation

enum CalculatorError: Error {
case divideByZero
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@

import Foundation

protocol CalculateItem {

}

struct CalculatorItemQueue: CalculateItem {
private var inbox: [Int] = []
private var outbox: [Int] = []
struct CalculatorItemQueue<T>: CalculateItem {
private var inbox: [T] = []
private var outbox: [T] = []

var size: Int {
return inbox.count + outbox.count
Expand All @@ -27,11 +23,11 @@ struct CalculatorItemQueue: CalculateItem {
}
}

mutating func push(_ data: Int) {
mutating func push(_ data: T) {
inbox.append(data)
}

mutating func pop() -> Int? {
mutating func pop() -> T? {
if outbox.isEmpty {
outbox = inbox.reversed()
inbox.removeAll()
Expand All @@ -40,7 +36,7 @@ struct CalculatorItemQueue: CalculateItem {
return outbox.popLast()
}

mutating func front() -> Int? {
mutating func front() -> T? {
if outbox.isEmpty {
outbox = inbox.reversed()
inbox.removeAll()
Expand All @@ -49,7 +45,7 @@ struct CalculatorItemQueue: CalculateItem {
return outbox.last
}

mutating func rear() -> Int? {
mutating func rear() -> T? {
if inbox.isEmpty {
return outbox.first
}
Expand Down
54 changes: 54 additions & 0 deletions Calculator/Calculator/Model/ExpressionParser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// ExpressionParser.swift
// Calculator
//
// Created by H on 2/14/24.
//

import Foundation

enum ExpressionParser {
static func parse(from input: String) -> Formula {
var operands: CalculatorItemQueue<Double> = CalculatorItemQueue<Double>()
var operators: CalculatorItemQueue<Operator> = CalculatorItemQueue<Operator>()

let parsedExpressions = componentsByOperators(from: input)
for expression in parsedExpressions {
if let operand = Double(expression) {
operands.push(operand)
break
}

if let `operator` = Operator(rawValue: Character(expression)) {
operators.push(`operator`)
break
}
}

return Formula(operands: operands, operators: operators)
}

static private func componentsByOperators(from input: String) -> [String] {
var components: [String] = []
var tempOperand: String = ""

for char in input {
let str = String(char)
if Operator.allCases.contains(where: { `operator` in
return `operator`.rawValue == char
}) {
components.append(tempOperand)
components.append(str)
tempOperand = ""
} else {
tempOperand.append(str)
}
}

if tempOperand != "" {
components.append(tempOperand)
}

return components
}
}
44 changes: 44 additions & 0 deletions Calculator/Calculator/Model/Formula.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Formula.swift
// Calculator
//
// Created by H on 2/14/24.
//

import Foundation

struct Formula {
var operands: CalculatorItemQueue<Double> = CalculatorItemQueue<Double>()
var operators: CalculatorItemQueue<Operator> = CalculatorItemQueue<Operator>()

mutating func result() throws -> Double {
var formulaResult: Double? = nil

while let operand = operands.pop() {
if let result = formulaResult {
let operatorCharacter = operators.pop()

switch operatorCharacter {
case .add:
formulaResult = Operator.add.calculate(lhs: result, rhs: operand)
case .substract:
formulaResult = Operator.substract.calculate(lhs: result, rhs: operand)
case .divide:
if operand == 0 {
throw CalculatorError.divideByZero
}

formulaResult = Operator.divide.calculate(lhs: result, rhs: operand)
case .multiply:
formulaResult = Operator.multiply.calculate(lhs: result, rhs: operand)
default:
break
}
} else {
formulaResult = operand
}
}

return formulaResult ?? 0.0
}
}
44 changes: 44 additions & 0 deletions Calculator/Calculator/Model/Operator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Operator.swift
// Calculator
//
// Created by H on 2/14/24.
//

import Foundation

enum Operator: Character, CaseIterable, CalculateItem {
case add = "+"
case substract = "−"
case divide = "÷"
case multiply = "×"

func calculate(lhs: Double, rhs: Double) -> Double {
switch self {
case .add:
return add(lhs: lhs, rhs: rhs)
case .substract:
return substract(lhs: lhs, rhs: rhs)
case .divide:
return divide(lhs: lhs, rhs: rhs)
case .multiply:
return multiply(lhs: lhs, rhs: rhs)
}
}

private func add(lhs: Double, rhs: Double) -> Double {
return lhs + rhs
}

private func substract(lhs: Double, rhs: Double) -> Double {
return lhs - rhs
}

private func divide(lhs: Double, rhs: Double) -> Double {
return lhs / rhs
}

private func multiply(lhs: Double, rhs: Double) -> Double {
return lhs * rhs
}
}
Loading