이번 포스팅의 목적은 스도쿠 게임을 만드는 과제를 하면서 배운 점들을 정리하도록 하겠다 ㅎ!
포스팅 방식은 스도쿠 게임을 구현할 때 진행했던 순서대로 하나씩 회고하겠다~
스도쿠 게임 기획 (사실상 구현의 시작이자, 꽃)
우선, 스도쿠 게임 기획을 진행했다.
스도쿠 게임은 9X9 스도쿠 판에서 게임이 진행되며,
규칙은 다음과 같다.
- 9개의 가로줄, 세로줄에 1 ~ 9까지의 숫자를 하나씩만 넣는다.
- 3X3 단위로 9등분 한 격자보드에도 1 ~ 9 숫자를 하나씩만 넣을 수 있다.
- 스도쿠의 모든 칸을 다 채우면 게임이 종료된다.
기획에서 스도쿠 게임에 존재하는 기능들을 나열했고,
게임 진행에 따른 기능을 정리했다.
그럼, 이제 기획에서 구성한 기능들을 통해
스도쿠 게임을 설계해보자. (사용자 관점에서 설계를 진행했음 ㅎㅎ)
해당 기획은 완벽한 답이 아니고, 좋은 방법 중 하나이다.
스도쿠 게임 설계
스도쿠 게임이 처음 실행되면,
사용자로부터 "난이도 입력"을 받는다.
- 1 입력 시 : 27개의 빈칸
- 2 입력 시 : 36개의 빈칸
- 3 입력 시 : 45개의 빈칸
입력 받은 "난이도"에 따라 스도쿠 보드판을 만들어 보여준다
그리고, 사용자로부터 "가로줄 번호" -> "세로줄 번호" -> "칸에 넣을 데이터 값 (1 ~ 9)" 를 입력받는다. (스도쿠 게임 진행용 변수)
이제, 사용자가 입력한 게임 변수가 유효한지에 대한 예외처리를 진행한다.
- 빈칸이고, 스도쿠 규칙에 맞다
- 그외의 것들
빈칸이고, 스도쿠 규칙에 맞다면, 사용자 입력을 받아서 스도쿠 게임 보드판(puzzle_board)를 업데이트 한다.
그외의 것들 (빈칸이 아니거나 스도쿠 규칙에 맞지 않다면) 이면, 사용자 입력을 무시한다.
업데이트 받은 보드판이 게임을 더 진행할 수 있는 지를 판단한다.
(업데이트 받은 보드판의 빈칸 갯수를 센다. - Model 클래스)
- 업데이트 한 보드판의 빈칸이 존재한다
- 업데이트 한 보드판의 빈칸이 존재하지 않는다
업데이트 받은 보드판의 빈칸이 존재한다면, 다시 사용자로부터 "가로줄 번호" -> "세로줄 번호" -> "칸에 넣을 데이터 값"을 입력받는다.
업데이트 받은 보드칸의 빈칸이 존재하지 않는다면, 게임을 종료한다.
해당 설계는 노트 필기로 진행되었으며,
설계 -> 코드 구현이 완료하고 회고 포스팅을 하는 중임을 참고하자.
설계를 진행하고, 다음은 MVC 아키텍처 설계를 진행했다.
(아키텍처 설계는 교수님이 주신대로 진행되었으며,
스스로 아키텍처 설계는 똑같이 진행하면 된다. - MVC 아키텍처를 이해하는 순서를 참고하라는 말)
스도쿠 게임 MVC 아키텍처 설계
아래는 스도쿠 게임의 MVC 아키텍처 설계한 사항이다.
교수님께서 설계한 아키텍처로써, 교수님만의 아키텍처 설계 방법을 이해할 수 있었다.
(어떤 설계가 답이 아니라, 좋은 설계 방법 중 하나라고 생각하자.)
# 아키텍처 상세 설명 - 교수님이 적어주신 아키텍처 상세 설명
아키텍처 설계할 때 다음과 같이 설계를 진행하는 걸 알 수 있다. ㅎㅎ
설계 시 다음과 같이 구조적으로 아키텍처를 설계해보자 ~
설계한 MVC 아키텍처에 대해서 간략하게 설명하도록 하겠다.
우선, Model 클래스로 "Sudoku" 를 설계했다.
Sudoku 클래스에서 스도쿠 퍼즐 보드를 생성하고,
생성한 퍼즐 보드를 return 해준다.
그리고, 게임 운영 시 생성한 퍼즐 보드판을 업데이트 한다.
(게임에 필요한 스도쿠 퍼즐 보드를 생성하고, 게임을 진행하는 클래스~)
ViewIn 클래스로 "PlayerInput" 를 설계했다.
PlayerInput 클래스에서 사용자의 초기 스도쿠 난이도 입력과
사용자가 게임 진행 시 필요한 게임 진행용 변수를 입력받았다.
(게임에 필요한 사용자 입력을 받는 클래스~)
ViewOut 클래스로 "SudokuWriter" 를 설계했다.
SudokuWriter 클래스에서 자바 GUI Application을 보여주고,
스도쿠 게임 진행 시 보여지는 보드판을 그려주도록 JPenal 함수로써 설계했다.
(ViewOut 클래스는 Model 클래스로부터 업데이트 된 보드판의 정보를 받아서 출력을 진행했다.)
(스도쿠 게임 보드판을 그려주는 ViewOut 클래스~)
Controller 클래스로 "SudokuController"를 설계했다.
SudokuController 클래스에서 PlayerInput 클래스로부터 난이도를 입력받고,
입력 받아진 데이터를 받아서 Model 클래스에 넘겨주어 게임에 진행할 스도쿠 보드판을 생성했다.
PlayerInput 클래스로부터 사용자의 스도쿠 게임 진행 변수인 (가로줄, 세로줄, 넣을 데이터) 를 입력받아 받아진 데이터를
Model 클래스에 넘겨주어 기존에 있던 스도쿠 보드판을 업데이트 해준다.
(스도쿠 게임을 통제하는 Controller 클래스~)
Starter 클래스로 "SudokuStarter" 클래스를 설계했다.
해당 클래스는 Java main 메소드로써, Java Application을 실행한다.
Controller에서 생성메서드가 복잡할 경우?
Starter 클래스에서 객체를 관리해 보내주기도 한다~ (주사위 굴리기 게임 & 상자속 공굴리기 애니메이션 등등)
(Java Application을 실행되도록 해주는 Starter 클래스~)
Starter 클래스가 Controller의 역할을 같이 할 수 있다는 걸 알고만 있어도 충분하다.
MVC 아키텍처 설계는 답이 있지않고, 좋은 방법들 중 상황에 적합한 아키텍처를 사용하는 것이다. - 인생에 답이 없듯, 설계에도 정답이 없다.
코드 구현
이제, 설계는 끝이났고,
설계한 MVC 아키텍처를 기반으로
클래스들을 생성하고 코드를 작성하면 된다.
대체로 Model, View 클래스를 우선적으로 구현한 뒤 Controller 클래스를 구현한다고 한다~
(이 또한, 정답이 아니고, 좋은 방법 중 하나이다~)
코드 구현에 대한 상세 설명은 별도로 하지 않겠다,
아키텍처 설계에서 모든 클래스에 대한 상세 설명을 해주었으니,
그대로 코드로 구현했을 뿐이다 ㅎㅎ
Model 클래스 구현
import java.util.Random;
import java.util.stream.IntStream;
public class SudokuModel {
private int[][] solution = new int[9][9];
private int hole_count;
private int[][] puzzle_board = new int[9][9];
/** 객체 초기화 메소드
*
* @param count - 빈칸의 개수
*/
// 생성 메서드 - 변수 초기화 & Controller 메인 메서드로 전달
public SudokuModel(int count) {
createSolutionBoard();
hole_count = count;
createPuzzleBoard(count);
}
/*
* Return 메서드
*/
/** 퍼즐 보드 배열을 리턴 한다. (겜 근황 출력)
*
* @return 퍼즐 보드 배열
*/
public int[][] getPuzzleBoard() {
return puzzle_board;
}
/** 빈칸의 개수를 리턴 한다. (겜 종료)
*
* @return 빈칸의 개수
*/
public int countHoles() {
return hole_count;
}
/*
* TO DO 1. (스도쿠 보드판 만들기)
*/
// [배점 = 0.5/2.0]
/** 해답 스도쿠 보드인 solution 배열을 무작위로 섞어서 만든다. */
private void createSolutionBoard() {
// 1~9 범위의 무작위 시퀀스 {n1,n2,n3,n4,n5,n6,n7,n8,n9}를 만들고,
// 이를 문서에 첨부한 그림 1과 같이 solution 배열에 배치 한다.
// 일반 스도쿠 퍼즐보드 판 생성 - 스도쿠 형성 구조를 구글링 ㅎ 해서 반복구간 알아냄 ㅎㅎ
int [] arr_num = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// 1행 시작
for(int i = 0; i <= 2; i++) {
for(int j = 0; j <=8 ; j++) {
// 1
if (i == 1 && j < 6) {
solution[i][j] = solution[0][j+3];
}
else if (i == 1 && j >= 6) {
solution[i][j] = solution[0][j-6];
}
// 2
else if (i == 2 && j < 3) {
solution[i][j] = solution[0][j+6];
}
else if (i == 2 && j >= 3) {
solution[i][j] = solution[0][j-3];
}
else {
solution[i][j] = arr_num[j];
}
}
}
int [] arr_num_2 = {2, 3, 1, 5, 6, 4, 8, 9, 7};
// 3행 시작
for(int i = 3; i <= 5; i++) {
for(int j = 0; j <=8 ; j++) {
// 1
if (i == 4 && j < 6) {
solution[i][j] = solution[3][j+3];
}
else if (i == 4 && j >= 6) {
solution[i][j] = solution[3][j-6];
}
// 2
else if (i == 5 && j < 3) {
solution[i][j] = solution[3][j+6];
}
else if (i == 5 && j >= 3) {
solution[i][j] = solution[3][j-3];
}
else {
solution[i][j] = arr_num_2[j];
}
}
}
int [] arr_num_3 = {3, 1, 2, 6, 4, 5, 9, 7, 8};
// 4행 시
for(int i = 6; i <= 8; i++) {
for(int j = 0; j <=8 ; j++) {
// 1
if (i == 7 && j < 6) {
solution[i][j] = solution[6][j+3];
}
else if (i == 7 && j >= 6) {
solution[i][j] = solution[6][j-6];
}
// 2
else if (i == 8 && j < 3) {
solution[i][j] = solution[6][j+6];
}
else if (i == 8 && j >= 3) {
solution[i][j] = solution[6][j-3];
}
else {
solution[i][j] = arr_num_3[j];
}
}
}
// 문서에 첨부한 그림 2와 같이 가로줄 바꾸기와 세로줄 바꾸기를 무작위로 한다.
// 무작위로 줄 바꾸기를 한다는 말은 바꿀지 말지를 무작위로 결정한다는 의미이다.
// 가로줄 바꾸기
shuffleRibbons();
// 세로줄 바꾸기
transpose();
shuffleRibbons();
transpose();
// 테스트용 메소드
// showBoard(solution);
// 스도쿠 게임판 테스트용 메소드
// showBoard(puzzle_board);
}
/** 0~n-1 범위의 정수 수열을 무작위로 섞은 배열을 리턴 한다.
*
* @param n - 수열의 길이
* @return 0~n-1 범위의 정수를 무작위로 섞어 만든 배열
*/
private int[] generateRandomPermutation(int n) {
Random random = new Random();
int[] permutation = new int[n];
for (int i = 0; i < n; i++) {
int d = random.nextInt(i+1);
permutation[i] = permutation[d];
permutation[d] = i;
}
return permutation;
}
/** 문서에 첨부한 그림 2와 같은 전략으로 solution 배열의 가로줄을 무작위로 섞는다. */
private void shuffleRibbons() {
int[][] shuffled = new int[9][9];
int[] random_index;
for (int i = 0; i < 3; i++) {
random_index = generateRandomPermutation(3);
for (int j = 0; j < 3; j++)
shuffled[i*3+random_index[j]] = solution[i*3+j];
}
solution = shuffled;
}
/** solution 배열의 행과 열을 바꾼다. */
private void transpose() {
int[][] transposed = new int[9][9];
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
transposed[i][j] = solution[j][i];
solution = transposed;
}
/** 2차원 배열 b를 콘솔 윈도우에 보여준다. (테스트용 메소드)
*
* @param b - 2차원 배열
*/
public void showBoard(int[][] b) {
System.out.println("스도쿠 보드");
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++)
System.out.print(b[i][j] + " ");
System.out.println();
}
}
/*
* TO DO 2.
*/
// [배점 = 0.5/2.0]
/** solution 배열에서 count 만큼 무작위로 빈칸을 채워 puzzle_board 배열을 만들어 리턴한다.
*
* @param count - 빈칸의 개수
*/
private void createPuzzleBoard(int count) {
// 답지 복제
// 2차원 배열 복제 - 2차원은 다르게 복제해야댐 ㅎㅎ
for(int i=0; i<puzzle_board.length; i++){
System.arraycopy(solution[i], 0, puzzle_board[i], 0, solution[0].length);
}
// solution 보드를 그대로 puzzle_board에 복제한다.
// 무작위로 빈칸을 선정한다. 빈칸은 구별을 위해서 0으로 채운다.
// new Random().nextInt(n) 메소드를 호출하면
// 0~n-1 범위의 정수 중에서 무작위로 하나를 고를 수 있다.
for (int i = 1; i <= count; i ++) {
int hole_low = new Random().nextInt(8);
int hole_col = new Random().nextInt(8);
if(puzzle_board[hole_low][hole_col] != 0) {
puzzle_board[hole_low][hole_col] = 0;
}
else {
i = i - 1;
}
}
}
/*
* TO DO 3.
*/
// [배점 0.5/2.0]
/** row번 가로줄, col번 세로줄에 digit을 채울 수 있는지 검사하여,
* 가능하면 채우고 true를 리턴하고, 불가능하면 false를 리턴 한다.
*
* @param digit - 빈칸에 채울 수 (1~9 중 하나)
* @param row - 가로줄 번호
* @param col - 세로줄 번호
* @return 퍼즐 보드 조건에 만족하여 빈칸을 채웠으면 true, 만족하지 않으면 false
*/
public boolean check(int digit, int row, int col) {
showBoard(puzzle_board);
showBoard(solution);
if(puzzle_board[row-1][col-1] == 0 && solution[row-1][col-1] == digit) {
puzzle_board[row-1][col-1] = digit;
hole_count = hole_count - 1;
return true;
}
else {
return false;
}
}
}
ViewIn 클래스 구현
import javax.swing.*;
public class SudokuViewIn {
/** 플레이어에게 난이도를 선택하게 하여 난이도에 따라 빈칸의 개수를 정하여 리턴한다.
*
* @return 빈칸의 개수
*/
public int selectLevel() {
String message = "난이도 숫자 입력 = 초급 1, 중급 2, 고급 3";
String input = JOptionPane.showInputDialog(message);
// 사용자 난이도 입력 예외처리
while (! (input.equals("1") || input.equals("2") || input.equals("3")))
input = JOptionPane.showInputDialog(message);
int level = Integer.parseInt(input);
if (level == 1)
return 27;
else if (level == 2)
return 36;
else // level must be 3
return 45;
}
// 사용자 스도쿠 게임의 입력 예외처리
// (여기선, 가로줄 & 세로줄 & 넣을 데이터 모두 예외처리함)
/** 1~9 범위의 수를 플레이어에게서 입력받아서 정수로 리턴한다.
*
* @param message - 인풋 메시지 윈도우에 보여줄 메시지 문자열
* @return 인풋 받은 1~9 범위의 정수
*/
public int selectNumber(String message) {
String input = JOptionPane.showInputDialog(message);
while (! (input.equals("1") || input.equals("2") || input.equals("3") ||
input.equals("4") || input.equals("5") || input.equals("6") ||
input.equals("7") || input.equals("8") || input.equals("9")))
input = JOptionPane.showInputDialog(message);
return Integer.parseInt(input);
}
}
ViewOut 클래스 구현
import java.awt.*;
import javax.swing.*;
// JPanel 클래스 상속받음.
public class SudokuViewOut extends JPanel {
private SudokuModel sudoku;
private final int SIZE = 40;
private final int PANEL_SIZE = SIZE * 11;
/** JPanel 객체 초기화 메소드
*
* @param s - 윈도우에 그릴 Sudoku 객체
*/
// 생성 메소드
public SudokuViewOut(SudokuModel s) {
sudoku = s;
JFrame f = new JFrame();
f.getContentPane().add(this);
f.setLocation(160, 200);
f.setTitle("Sudoku");
f.setSize(PANEL_SIZE, PANEL_SIZE+28);
f.setVisible(true);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, PANEL_SIZE, PANEL_SIZE);
int digit;
// 스도쿠 판 좌표
int x = SIZE;
int y = SIZE;
/*
* 스도쿠 판 (한칸 씩) 그리기
*/
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
g.setColor(Color.gray);
g.drawRect(x, y, SIZE, SIZE);
g.setColor(Color.black);
digit = sudoku.getPuzzleBoard()[i][j];
if (digit != 0)
g.drawString(digit + "", x+15, y+25);
x += SIZE;
}
x = SIZE;
y += SIZE;
}
/*
* 스도쿠 판 3 X 3 판으로 9등분하기
*/
x = SIZE;
y = SIZE;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
g.setColor(Color.black);
g.drawRect(x, y, SIZE*3, SIZE*3);
x += SIZE * 3;
}
x = SIZE;
y += SIZE * 3;
}
/*
* 가로줄 번호
*/
x = SIZE - 25;
y = SIZE;
for (int i = 1; i <= 9; i++) {
g.setColor(Color.blue);
g.drawString(i + "", x, y+25);
y += SIZE;
}
/*
* 세로줄 번호
*/
x = SIZE;
y = SIZE - 10;
for (int i = 1; i <= 9; i++) {
g.setColor(Color.blue);
g.drawString(i + "", x+15, y);
x += SIZE;
}
}
}
Controller 클래스 구현
public class SudokuController {
private SudokuModel sudoku;
private SudokuViewIn reader;
private SudokuViewOut writer;
/** Sudoku, PlayerInput, SudokuWriter 객체를 생성하여 필드 변수에 지정한다. */
// 생성 메서드
public SudokuController() {
reader = new SudokuViewIn();
int hole_count = reader.selectLevel();
/*
* 객체를 활용하는 좋은 사례 중 하나임 ㅎㅎ
*/
// Model 객체를 선언해
// ViewOut 클래스로 Model 객체 보내줌.
sudoku = new SudokuModel(hole_count);
writer = new SudokuViewOut(sudoku);
}
/*
* TO DO 4.
*/
// [배점 0.5/2.0]
/** 스도쿠 퍼즐 게임을 진행한다. */
public void playSudokuPuzzle() {
while(true) {
if(sudoku.countHoles() != 0) {
// 스도쿠 보드판 다시 그리기
writer.repaint();
// 사용자 스도쿠 게임 데이터 입력
int userInputRow = reader.selectNumber("가로줄 번호를 입력하세요.");
int userInputCol = reader.selectNumber("세로줄 번호를 입력하세요.");
int userInputDigit = reader.selectNumber("숫자를 입력하세요.");
// 사용자가 입력한 데이터 스도쿠에 대입 - 불가 시 false, 가능 시 true
if(sudoku.check(userInputDigit, userInputRow, userInputCol)) {
// 한번 선언된 객체는 프로그램이 실행 종료할 때까지 유효하다.
// 객체가 업데이트 되면, 반영된다.
/*
* 자바 객체 새로운 앎. - 블로그 포스 (자바 과제를 하며,, 객체를 깨닫다)
*/
// 아래 코드를 사용하면, ViewOut 페이지가 여러 개 출력된다. (블로그 작성 참고)
// writer = new SudokuViewOut(sudoku);
// sudoku.showBoard(sudoku.getPuzzleBoard());
}
}
else {
break;
}
}
}
}
Starter 클래스 구현
public class SudokuStarter {
public static void main(String[] args) {
new SudokuController().playSudokuPuzzle();
}
}
트러블 슈팅 - 과제하면서 어려웠던 점
1. 스도쿠 보드판 만들기
스도쿠 게임 보드판을 만들어야 하기에, 스도쿠 보드판의 원리대로
보드판의 원소들을 배치했어야 되었다.
그러기위해 보드판에 대한 규칙을 찾아보았지만,
일일히 하나씩 대입하는 방법밖에 생각이 나지 않았고,
생각이 나도 비효율적이라 시도를 하지 않았다.
결국, 구현이 완료하고 보면, 처음 유추한 방법으로 코드를 구현하는게 그나마 효율적이었다.
일단, 구현해보고, 거기서 수정하는 식으로 코드를 작성하는 것.
추론하면서 코드를 구현하는 행위,
완벽함은 없다는 생각으로 코드를 구현하는 행위가 프로젝트에 대한 시야를 넓혀준다.
(처음엔 원래 어설프게 하는 법이다~)
다음과 같은 지혜를 깨닫게 해주는 좋은 시도였다.
2. 2차원 배열 복제
아래를 통해 배열이 복제 될 줄 알았지만...!
디버깅을 통해 복제가 제대로 되지 않다는 걸 확인했다
puzzle_board = solution.clone();
아래와 같이 2차원 배열은 for문을 사용해
따로 복제를 진행한다.
for(int i=0; i<puzzle_board.length; i++){
System.arraycopy(solution[i], 0, puzzle_board[i], 0, solution[0].length);
}
자바가 배열 객체를 선언할 때는
call-by-reference (참조에 의한 호출) 에 의해 선언이 된다.
그래서, 복제를 하더라도, 똑같은 곳을 가르키기 때문에 이를 고려해서 별도의 복제 과정을 거친다.
3. 디버깅
디버깅은 코드를 실행할 때 에러가 발생하지 않지만,
실행 결과가 코드 작성한 것과 다를 때 필요하다.
디버깅을 통해 어느 부분에서 데이터가 잘못들어가고, 데이터가 잘못 입력되고, 데이터가 잘못 예외처리가 되었는지를 확인할 수 있기 떄문이다.
그렇지만, 디버깅을 한다는 건, 코드가 어떻게 읽히는지를 잘 이해하고,
코드가 읽었을 것 같은 곳에 테스트 출력 코드를 두고 테스팅하는 것이다.
(어디에 두는 게 정답이 정해져있지 않고, 작성한 코드별로 적합한 출력 코드를 작성해 디버깅을 진행한다.)
이번에, 디버깅을 하면서 2차원 배열복제가 되지않는다는 걸 알아냈고,
구성한 제어식이 제대로 통과하지 못한다는 걸 알아냈다.
특히, 제어식 디버깅은 제어식 통과유무를 확인 후 -> 제어 변수의 값을 확인해 제대로 값을 넣었는지 테스트를 한다는 점에서
어렵지만, 독특하다.
(결국, 디버깅을 해보면서, 답이 없지만, 상황에 적절한 디버깅을 한다는 사실을 깨달았다 ㅎㅎ)
4. 객체
한번 선언된 객체는 연결되어 있다?
한 클래스내에서 선언한 객체는 연결되어져 있다.
그래서, 객체 내역을 업데이트하면, 클래스내에서의 모든 같은 객체 업데이트 된다.
이 부분에 대해선 질문을 하여, 클래스 내에서 객체의 개념을 제대로 이해해볼 것이다. ㅎㅎ
(코드 구현논리상 선언된 객체는 업데이트 시 모든 같은 객체들은 업데이트 됨.)
public void playSudokuPuzzle() {
while(true) {
if(sudoku.countHoles() != 0) {
// 스도쿠 보드판 다시 그리기
writer.repaint();
// 사용자 스도쿠 게임 데이터 입력
int userInputRow = reader.selectNumber("가로줄 번호를 입력하세요.");
int userInputCol = reader.selectNumber("세로줄 번호를 입력하세요.");
int userInputDigit = reader.selectNumber("숫자를 입력하세요.");
// 사용자가 입력한 데이터 스도쿠에 대입 - 불가 시 false, 가능 시 true
if(sudoku.check(userInputDigit, userInputRow, userInputCol)) {
// 한번 선언된 객체는 프로그램이 실행 종료할 때까지 유효하다.
// 객체가 업데이트 되면, 반영된다.
/*
* 자바 객체 새로운 앎. - 블로그 포스 (자바 과제를 하며,, 객체를 깨닫다)
*/
// 아래 코드를 사용하면, ViewOut 페이지가 여러 개 출력된다. (블로그 작성 참고)
// writer = new SudokuViewOut(sudoku);
// sudoku.showBoard(sudoku.getPuzzleBoard());
}
}
else {
break;
}
}
}
ViewOut 클래스에 Model 클래스 업데이트 된 사항을 다시 넣어줄 필요가 없다.
(생성 메소드에서 ViewOut 클래스의 인자로 Model 클래스를 넣어주었기 떄문~~ || 생성메소드에서 변수를 초기화 뿐만아니라,
객체를 관리하고 통제한다.)
'CS 대학강의' 카테고리의 다른 글
[CS 1-2 | 오픈소스 SW 기초] 가상화 & 리눅스 컨테이너 with Docker 6주차 (0) | 2022.10.20 |
---|---|
[CS 1-2 | 프로그램 설계 방법론] Java로 병원 입원 관리 서비스 제작 (0) | 2022.10.20 |
[CS 1-2 | 프로그램 설계 방법론] 배열 객체 & MVC 아키텍처 설계 실제 프로그램에 적용해보기 9주차 (2) | 2022.10.15 |
[CS 1-2 | 오픈소스 SW 기초] 네트워크 통신 | 소켓 통신 5주차 (0) | 2022.10.13 |
[CS 1-2 | 이산수학] 행렬의 연산 10주차 (0) | 2022.10.12 |