백준이나 프로그래머스에서 문제풀이를 하는데 계속 같은 환경에서 새로운 문제를 풀 때마다 `Main` 클래스 초기화를 반복해서 하자니 템플릿과 매크로가 필요했습니다.
그래서 gradle 명령어로 Main 클래스의 템플릿을 초기화하고, 파일입출력을 받되 파일 경로가 코드에 노출되지 않는 스크립트를 만들었습니다.
Main클래스 템플릿 + 초기화 스크립트
준비할 파일들은 다음과 같은 구성으로 되어있습니다.
참고로, 위 디렉터리들 중 `build`, `solve` 는 이 포스트와 관련이 없습니다. `solve` 에는 풀었던 문제들을 따로 저장했습니다.
파일 이름에서 눈치챘을 수 있었을 것입니다. `BOJ.java`는 백준 풀이용 템플릿이고, `Programmers.java`는 프로그래머스용 템플릿입니다.
우선 `BOJ.java` 파일에는 다음과 같은 내용이 들어 있습니다.
// BOJ.java
import java.io.*;
class BOJ {
private static void solve(BufferedReader br) throws IOException {
}
private static StringBuilder res;
public static void main(String args[]) throws Exception {
if (args.length > 1) fileInputOutput(args[0], args[1]);
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))) {
res = new StringBuilder();
solve(br);
bw.write(res.toString());
}
}
private static void fileInputOutput(String inputPath, String outputPath) throws IOException {
System.setIn(new FileInputStream(inputPath));
System.setOut(
new PrintStream(
new BufferedOutputStream(
new FileOutputStream(outputPath)
)));
}
}
입출력은 `BufferedReader`와 `BufferedWriter`를 통해 들어오고 내보내도록 했고, 파일입출력은 `fileInputOutput` 메소드를 참조하면 됩니다. 문제 풀이는 `solve` 메소드에서 진행하면 되고, 입력은 `BufferedReader br`을 통해 입력받으면 되며, 출력은 전역으로 선언한 `StringBuilder res`를 통해 출력하면 된다. 자세한 예시는 맨 아래에 깃허브 링크의 `app/src/solve` 디렉토리에 들어있는 몇몇 문제들을 참고해보면 됩니다.
11번째 줄에 주목해보면, `input.txt`와 `output.txt` 파일로 입출력을 내보내고 싶었습니다. 그래서 args 입력을 받을 때 파일 입출력을 하도록 코드를 작성했습니다. 그 이유는 백준에서 파일을 컴파일하는 방식에는 args에 어떠한 내용도 들어가지 않기 때문입니다. 코드를 살펴보면 알 수 있듯이, args에 `input.txt`의 경로와 `output.txt`의 경로가 들어갑니다. 이 args를 넣는 방식은 다음 gradle 스크립트를 통해 해결했습니다. run(빌드 및 실행) 동작 시에 다음과 같은 태스크를 실행하도록 작성했습니다.
run {
def resourcePath = "${project.rootDir}/app/src/main/resources"
args = [Paths.get(resourcePath, "input.txt"), Paths.get(resourcePath, "output.txt")]
}
단순히 `build.gradle`에 위 코드를 넣으면 args에 잘 들어갑니다. 혹시 이 코드를 사용하고자하는 사람이 있다면, 위 코드에서 `resourcePath`를 적절히 고쳐서 사용하면 될 것입니다.
아, 백준은 이렇게 하면 해결되는 반면에, 프로그래머스는 입출력이 상대적으로 불친절하게 되어있습니다. 예를 들면 입력을 복사해보면 탭으로 나뉘어져 있고, 배열을 대괄호`[]`로 감싸져 있고... 등등의 문제가 있었습니다. 그걸 파싱할 시간에 문제를 하나 더 푸는게 낫다는 판단 하에, 일단 Programmers는 BOJ의 코드를 복사해 놓고, `Solution` 클래스를 내부에 하나 만들어주었습니다. 자세한 코드는 아래 깃허브 링크를 참조해 주세요!
다음 gradle task 코드는 위 `BOJ.java` 코드를 `Main.java`로 옮기는 태스크입니다.
// build.gradle에 추가할 코드
tasks.register('cleanMainToBOJ', Copy) {
from './src/main/java/BOJ.java'
into './src/main/java/'
rename { String fileName -> fileName.replace('BOJ', 'Main') }
filter {
String line -> line.replace("BOJ", "Main")
}
filteringCharset = 'UTF-8'
}
구글링과 chatGPT의 답변을 종합해본 결과 위 코드처럼 태스크를 작성하는 것이 좋다고 판단했습니다.
`filter`에는 어떤 특정 단어(위에서는 `"BOJ"`)를 바꾸는 명령어가 따로 없어, 모든 줄을 체크하며 단어를 바꾸어주었습니다.
이제 디렉토리와 파일들이 모두 준비가 되었다면, 개인적으로 인텔리제이 환경을 사용하고 있기 때문에, 인텔리제이에서 gradle 설정을 해주면 됩니다.
인텔리제이 Run/Debug Configurations 설정 (gradle로 변경)
저는 모던 환경(베타버전)을 사용하고 있어서, 구버전 환경을 사용하는 사람과 UI가 조금 다를 수 있습니다. 위 화면이 나온다면, 맨 아래의 Edit Configurations... 를 눌러줍시다. 위 버튼들이 화면에 보이지 않는다면, 아래처럼 `shift` 버튼을 두번 누른 다음 Edit configurations...를 검색해줍시다.
그러면 다음과 같은 설정 창이 나오고, 왼쪽 위의 플러스(+) 버튼을 눌러 gradle를 선택해서 3개를 만든 다음, 다음과 같이 이름을 설정해줍시다.(굳이 똑같이 설정하지 않아도 됩니다.)
각 gradle 설정들 안에는 다음과 같이 설정해 줍시다.
그러고서 Apply를 눌러주면 세개의 설정이 완성됩니다! 코드를 실행하려면 당연히 `run` 을 실행하면 빌드 및 실행이 될 것이고, `clean` 시리즈를 실행하면 Main.java 파일이 해당 템플릿 파일로 변경(초기화)가 될 것입니다. 물론, 코드를 다 작성하고 나서 `run` 이 아닌 `clean` 시리즈를 실행하면 대참사(...)가 일어나니 조심합시다. 하지만 그 때는 당황하지 않고 되돌리기(`ctrl+z`)를 눌러주면 다시 복귀가 되긴 합니다. 그래도 조심합시다~~
위 내용을 종합하여 깃허브 레포를 하나 만들었습니다. 다음 레포를 클론한 뒤 인텔리제이를 통해 열면 쉽게(?) 코딩테스트 준비를 할 수 있을 것입니다!
https://github.com/tkddn204/coding-test-training-java
GitHub - tkddn204/coding-test-training-java: study
study. Contribute to tkddn204/coding-test-training-java development by creating an account on GitHub.
github.com
저처럼 알고리즘 문제풀이를 하면서 베이스 코드를 작성하는 데 어려움을 겪는 사람이 있을 수 있을거라 생각해서 이 포스트를 작성하게 되었습니다. 알고리즘 풀이 환경에 제가 쓴 정보가 조금이나마 도움이 되었으면 좋겠습니다.