Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Application.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
# All-rounder Backend Study

숫자를 입력하면 아스키 아트 형태로 출력하는 Java 기반 CLI 프린터 프로그램임
잉크 잔량을 관리하고, 출력 중 잉크 부족 시 자동으로 중단되며, 다양한 예외 상황을 정교하게 처리함

---

## 주요 기능

| 기능 | 설명 |
|------|------|
| 숫자 출력 | 입력된 숫자(0~9)를 아스키 아트로 출력함 |
| 용지 크기 설정 | 한 줄에 출력할 문자 개수를 지정할 수 있음 |
| 잉크 잔량 확인 | 현재 잉크 상태(최대 1000)를 확인할 수 있음 |
| 잉크 리필 | 출력 도중 언제든지 잉크를 다시 채울 수 있음 |
| 예외 처리 | 입력 오류, 잉크 부족, 파일 로딩 실패 등을 명확한 메시지로 안내함 |

----
10 changes: 9 additions & 1 deletion src/main/java/mission/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package mission;

import mission.controller.printerController;
import mission.model.ink;
import mission.utils.AsciiGenerator;
import mission.view.printerView;

public class Application {
public static void main(String[] args) {
//Todo: 프로그램 구현
printerController controller = new printerController(
new AsciiGenerator(), new ink(), new printerView()
);
controller.run();
}
}
112 changes: 112 additions & 0 deletions src/main/java/mission/controller/printerController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package mission.controller;

import mission.model.ink;
import mission.utils.AsciiGenerator;
import mission.view.printerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class printerController {
Copy link
Contributor

Choose a reason for hiding this comment

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

클래스명은 대문자로 시작하는게 컨벤션상 좋을거같아요

private final AsciiGenerator generator;
private final ink inkManager;
private final printerView view;
private static final int LINE_COUNT = 5;
private final Map<String, Runnable> menuMap = new HashMap<>();

public printerController(AsciiGenerator generator, ink inkManager, printerView view) {
this.generator = generator;
this.inkManager = inkManager;
this.view = view;
initMenu();
}

public void run() {
while (true) {
view.printMenu();
String input = view.input("");
if (input.equals("4")) return;
Runnable action = menuMap.get(input);
if (action != null) action.run();
Copy link
Contributor

Choose a reason for hiding this comment

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

runnable을 선언할 필요 없이 바로 실행하는 편이 가독성이나 효율성 측면에서 더 좋을 것 같아요

}
}

private void initMenu() {
menuMap.put("1", this::handlePrint);
menuMap.put("2", this::handleInkCheck);
menuMap.put("3", this::handleInkRefill);
}

private void handlePrint() {
String text = view.input("출력할 문자를 입력해주세요. ");
int size = view.paperSize("용지 크기를 입력해주세요. ");
printAsciiHorizontally(text, size);
view.showMessage("출력이 완료되었습니다. ");
}

private void handleInkCheck() {
int amount = inkManager.getInk();
view.showMessage(String.format("잉크 잔량 : %d/1000", amount));
}

private void handleInkRefill() {
inkManager.refillInk();
view.showMessage("잉크를 교체하였습니다. ");
}

public void printAsciiHorizontally(String input, int paperSize) {
int start = 0;
while (start < input.length()) {
int end = Math.min(start + paperSize, input.length());
printOneLine(input.substring(start, end));
start = end;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

reduce를 써서 함수형 프로그래밍으로 표현할 수 있지 않을까요?

}

private void printOneLine(String input) {
List<StringBuilder> lines = initLines();
try {
buildAsciiLines(input, lines);
printLines(lines);
} catch (IllegalStateException e) {
view.showMessage(e.getMessage());
}
}

private void buildAsciiLines(String input, List<StringBuilder> lines) {
for (char ch : input.toCharArray()) {
if (ch == ' ') {
appendSpace(lines);
continue;
}
inkManager.minusInk();
appendAscii(lines, ch);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분도 stream API를 사용하면 더 효율적이고 가독성 높게 구성할 수 있을 것 같아요


private List<StringBuilder> initLines() {
List<StringBuilder> lines = new ArrayList<>();
for (int i = 0; i < LINE_COUNT; i++) lines.add(new StringBuilder());
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분이랑 아래 부분들을 함수형으로 구성하면 좋을 것 같아요

return lines;
}

private void appendAscii(List<StringBuilder> lines, char ch) {
int num = Character.getNumericValue(ch);
List<String> ascii = generator.getNumberAsciiDesign(num);
for (int i = 0; i < ascii.size(); i++) {
lines.get(i).append(String.format("%s ", ascii.get(i)));
}
}

private void appendSpace(List<StringBuilder> lines) {
for (int i = 0; i < LINE_COUNT; i++) {
lines.get(i).append(String.format("%s ", " "));
}
}

private void printLines(List<StringBuilder> lines) {
for (StringBuilder line : lines) System.out.println(line);
}
}
22 changes: 22 additions & 0 deletions src/main/java/mission/model/ink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package mission.model;

public class ink {
private int ink = 1000;

public int getInk() {
return ink;
}

public void minusInk() {

if (ink <= 0) {
throw new IllegalStateException("[ERROR] 잉크가 부족해 출력을 중단합니다.");
}
this.ink -= 1;

}

public void refillInk() {
this.ink = 1000;
}
}
8 changes: 7 additions & 1 deletion src/main/java/mission/utils/AsciiGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Arrays;

public class AsciiGenerator {
private final List<List<String>> data;
Expand All @@ -24,7 +25,12 @@ public AsciiGenerator() {
getClass().getClassLoader().getResource("numberAsciiDesign/" + fileName + ".txt")
).toURI());
String content = Files.readString(path);
data.add(List.of(content.split("\n")));

List<String> paddedLines = Arrays.stream(content.split("\n"))
.map(line -> String.format("%-3s", line))
.toList();

data.add(paddedLines);
} catch (URISyntaxException | IOException e) {
throw new IllegalStateException("[ERROR] 아스키아트를 로드하지 못했습니다.");
}
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/mission/view/printerView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package mission.view;

import java.util.Scanner;

public class printerView {
private final Scanner scanner = new Scanner(System.in);

public void printMenu(){
System.out.println("프린터를 실행합니다.");
System.out.print("사용할 기능을 입력해주세요. 1) 출력, 2) 잉크 잔량 확인, 3) 잉크 교체, 4) 프로그램 종료");
}

public String input(String message){
System.out.println(message);
return scanner.nextLine();
}

public void showMessage(String message){
System.out.println(message);
}

public int paperSize(String message){
System.out.println(message);
int value = scanner.nextInt();
scanner.nextLine(); // 버퍼에 남아있는 \n 제거
return value;
}

}
38 changes: 38 additions & 0 deletions src/test/java/mission/InkTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package mission;

import mission.model.ink;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class InkTest {

@Test
void initial_ink_amount_should_be_1000() {
ink testInk = new ink();
assertEquals(1000, testInk.getInk());
}

@Test
void ink_decreases_by_1_per_print() {
ink testInk = new ink();
testInk.minusInk();
assertEquals(999, testInk.getInk());
}

@Test
void exception_thrown_when_ink_is_empty() {
ink testInk = new ink();
for (int i = 0; i < 1000; i++) testInk.minusInk();
IllegalStateException e = assertThrows(IllegalStateException.class, testInk::minusInk);
assertTrue(e.getMessage().contains("[ERROR] 잉크가 부족해 출력을 중단합니다."));
}

@Test
void refill_restores_ink_to_1000() {
ink testInk = new ink();
testInk.minusInk();
testInk.refillInk();
assertEquals(1000, testInk.getInk());
}
}