D. 지뢰찾기 분석 설계 예제

Post on 03-Jan-2016

96 views 0 download

description

D. 지뢰찾기 분석 설계 예제. 0. 지뢰찾기 분석. 분석의 목적. 시스템과 사용자 사이의 인터페이스를 정의 사용자 관점에서 인식할 수 있는 것만 정의한다 시스템 내부는 언급하지 않는다 사용자는 몰라도 되고 개발자만 알면 되는 것은 언급하지 않는다 여기서 언급한 사용자는 꼭 사람만을 의미하는 것은 아님 시스템과 명령이나 데이터를 주고 받는 것 시스템 내부가 아니고 외부 환경에 속하는 것. 분석 단계의 산출물 ( 중요도 순서로 나열됨 ). 1. Use-case 모델 - PowerPoint PPT Presentation

Transcript of D. 지뢰찾기 분석 설계 예제

D1

D. 지뢰찾기 분석 설계 예제

D2

0. 지뢰찾기 분석

D3

분석의 목적• 시스템과 사용자 사이의 인터페이스를 정의

• 사용자 관점에서 인식할 수 있는 것만 정의한다

• 시스템 내부는 언급하지 않는다

• 사용자는 몰라도 되고 개발자만 알면 되는 것은 언급하지 않는다

• 여기서 언급한 사용자는 – 꼭 사람만을 의미하는 것은 아님– 시스템과 명령이나 데이터를 주고 받는 것– 시스템 내부가 아니고 외부 환경에 속하는 것

D4

분석 단계의 산출물 ( 중요도 순서로 나열됨 )

1. Use-case 모델(Use-case Diagram + Use-case Specification)

2. 보충 요구사항 명세서 (Supplementary Requirement Specification)

3. 개념 모델 (Conceptual Level Class Diagram)

4. 화면 / 메뉴 설계

5. 개발계획

6. 기타 : 용어사전 , 사용자 메뉴얼

D5

0-1. Use-case Model

D6

Use-case Diagram

플레이어

지뢰찾기

닫힌 칸을 열기

지뢰를 표시

닫힌 칸들을 열기

D7

앞의 Use-case 모델은 적절한가 ?• 무엇을 기준으로 판단할 것인가 ?

• 좋은 모델의 기준은 무엇인가 ?

D8

좋은 모델의 기준은 ?• 좋은 모델은 정보의 전달이라는 목적에 충실해야 한다

– Use-case 모델이 고객에게 전달하는 정보 : 시스템을 이렇게 만들면 되나 ?

– Use-case 모델이 개발자에게 전달하는 정보 :이러한 시스템을 만들어라

• 전달해야 하는 정보를 빠짐 없이 포함해야 한다

• 이해하기 쉽고 간결해야 한다

D9

빠진 Use-case 는 ?• 새 게임 시작하기 시나리오

• 초급 중급 고급 선택

• 색깔 소리 같은 옵션 지정

• 최고 기록 보기

• 위와 같은 것도 포함해야 하나 ?

D10

Use-case Diagram 의 목적• Use-case Diagram -> 조감도 (Bird’s Eye View)

– 시스템이 제공하는 기능을 큰 단위로 표현한 것– 모든 세세한 기능을 Use-case Diagram 으로 표현하지 말라

• 세밀한 묘사는 다른 적당한 다이어그램에서 표현하면 된다

D11

지뢰찾기의 Use-case ?• 지뢰찾기 게임이 사용자에게 제공하는 기능을 크게 분류하면 ?

D12

Use-case Diagram

플레이어

지뢰찾기

닫힌 칸을 열기

지뢰를 표시

닫힌 칸들을 열기

D13

Use-case Specification• 자세한 내용은 Use-case Specification 에서 설명한다

D14

Use-case Specification• Name : 닫힌 칸을 열기

• Description:– 지뢰가 없을 것으로 짐작되는 칸을 연다

• Actor: 플레이어

• Precondition: – 칸은 닫혀있어야 한다– 지뢰 표시가 없는 칸이어야 한다

D15

닫힌 칸을 열기• Main Flow

1. 지뢰가 없을 것으로 짐작되는 칸을 플레이어가 마우스 왼쪽 버튼으로 클릭한다

2. 칸은 열려진 상태로 표시되며 , 주변의 지뢰의 수가 칸 안에 표시된다

3. 주변의 지뢰의 수가 0 이면 • 지뢰 수 0 은 표시되지 않고• 주변의 닫힌 칸들이 모두 열려지며• 각 칸 안에 그 주변의 지뢰의 수가 표시된다 . • 이 과정은 재귀적으로 반복된다

D16

닫힌 칸을 열기• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다

D17

Use-case Specification• Name : 지뢰를 표시

• Description:– 지뢰가 있을 것으로 짐작되는 칸에 지뢰 표시를 한다

• Actor: 플레이어

• Precondition: – 칸은 닫혀있어야 한다

D18

지뢰를 표시• Main Flow:

1. 지뢰가 있을 것으로 짐작되는 칸을 플레이어가 마우스 오른쪽 버튼으로 클릭한다

2. 칸에 지뢰 표시가 되고 , 남은 지뢰 수 표시가 1 감소한다 .

3. 지뢰 표시가 된 칸을 마우스 오른쪽 버튼으로 클릭한다

4. 칸에서 지뢰 표시가 제거되고 , 남은 지뢰 수 표시가 1 증가한다

D19

지뢰를 표시• Notes:

– 지뢰 표시가 된 칸은 열 수가 없다" 닫힌 칸 열기 " 의 Precondition 참고

D20

Use-case Specification• Name : 닫힌 칸들을 열기• Description:

– 인접한 지뢰가 모두 표시되었을 경우 , 지뢰가 없는 인접한 빈 칸을 모두 동시에 연다

• Actor: 플레이어

• Precondition: – 클릭하는 칸은 열려 있어야 한다– 열려진 칸에 표시된 주변 지뢰 수 만큼

주변 칸들에 지뢰 표시들이 있어야 한다

D21

닫힌 칸들을 열기• Main Flow

1. 열려진 칸에서 마우스 왼쪽과 오른쪽 버튼을 동시에 클릭한다

2. 인접한 8개의 칸들 중 지뢰 표시가 되어 있지 않은 칸들 이 열려진다 . 열려진 각 칸들에는 인접한 지뢰의 수가 표시된다 .

3. 열려진 칸의 주변 지뢰의 수가 0 이면• 지뢰 수 0 은 표시되지 않고• 주변의 칸 모두 열려지며• 각 칸 안에 그 주변의 지뢰의 수가 표시된다 . • 이 과정은 재귀적으로 반복된다

D22

닫힌 칸들을 열기• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다

D23

0-2. 보충 요구사항

D24

보충 요구사항• 모든 것을 Use-case 형태에 맞춰서 표현할 필요없다

• 사용자와 시스템 사이의 작업 시나리오 절차들은 Use-case 형태로 표현하는 것이 적당하다

• 기타 요구사항으로 표현하는 편이 더 단순한 것들도 있다

D25

보충 요구사항

• 난이도– 초급 : 9 행 9 열의 칸 , 10 개의 지뢰– 중급 : 16 행 16 열의 칸 , 40 개의 지뢰– 고급 : 16 행 30 열의 칸 , 99개의 지뢰

• 화면에 남은 지뢰수가 표시된다– 남은 지뢰수 = 전체 지뢰 수 – 지뢰 표시의 수

• 화면에 초시계가 표시된다– 첫 칸을 연 때부터 초시계가 시작하고– 성공하거나 실패한 순간 초시계가 정지한다

• 난이도 별로 최단시간 성공 기록을 유지한다

D26

0-3. 개념모델 (Conceptual Model)

D27

개념모델• Use-case 모델의 이해를 돕기 위해 작성

• Use-case 모델에 등장하는 개념들의 관계를 표현한다

• 용어 사전과 비슷한 역할을 한다

D28

지뢰찾기의 개념모델• 개념모델의 목적은 시스템 설계가 아니고 관련 개념의 이해이다

– 모듈 설계와 다르다

• 다음의 개념들을 이해하기 쉽게 표현하기 위한 모델이다– 지뢰 , 이웃칸 , 지뢰표시 , 칸의 상태 …

• 사용자와 개발자들이 위 개념들을 잘 알고 있다면 , 개념모델은 생략 가능하다– 지뢰 찾기의 경우 사실 개념 모델은 필요없다

• 금융 정보시스템을 개발하는 경우라면 , 관련 개념들이 이해하기 매우 어려울 것이므로 개념모델이 꼭 필요할 것이다 .

D29

지뢰찾기의 개념모델

+cellState : CellState+/nearbyMineCount : int

Cell+rowCount : int+columnCount : int

Minefield

1 *

Mine

1

0..1

Flag

1

0..1

+CLOSED+OPENED

<<enumeration>>CellState

3,5,8

+neighbor

3,5,8

D30

0-4. 화면 / 메뉴 설계

D31

화면설계

진행화면 성공 실패

D32

메뉴설계

D33

0-5. 개발 계획

D34

점진적 개발• 크고 복잡한 시스템을 한 번에 완성하는 것은 매우 어렵다

– 작게 쪼개어 하나씩 만들어 가는 것이 좋다

• Use-case 단위로 만들어 나간다– 중요한 Use-case 를 먼저 선택하여 – 설계 , 구현 , 테스트하여 완성하고 – 그 다음 Use-case 를 선택하여 만들어 나간다

D35

Use-case 단위로 점진적 개발 • Use-case 의 우선순위 별로 점진적 개발

1. 닫힌 칸을 열기 2. 지뢰를 표시3. 닫힌 칸들을 열기

• 1차 개발– 닫힌 칸을 열기

• 2차 개발– 지뢰를 표시– 닫힌 칸들을 열기

D36

1-1. 1차개발 : 분석

D37

1차개발 개요• 가장 중요한 use-case 인 " 닫힌 칸을 열기 " 를 구현한다

• 1차개발의 완료는 빠르면 빠를 수록 좋다– 실행하고 테스트 해 볼 수 있는 1차 버전은 , 고객으로부터

요구사항 수집하는데 , 개발자가 시스템을 이해하고 개발하는데 , 아주 큰 도움이 된다

• 1차개발을 빠르게 완료하기 위하여 , use-case 를 단순하게 수정하고 구현하는 것도 좋다 .– 단순하게 수정된 내용은 2차 개발에서 보충 구현한다 .

D38

1-1-1. Use-case 모델

D39

Use Case Diagram

플레이어

지뢰찾기

닫힌 칸을 열기

지뢰를 표시

닫힌 칸들을 열기

D40

Use Case Specification ( 단순화됨 )• Name : 닫힌 칸을 열기

• Description:– 지뢰가 없을 것으로 짐작되는 칸을 연다

• Actor: 플레이어

• Precondition: – 칸은 닫혀있어야 한다

D41

닫힌 칸을 열기• Main Flow

1. 지뢰가 없을 것으로 짐작되는 칸을 플레이어가 마우스 왼쪽 버튼으로 클릭한다

2. 칸은 열려진 상태로 표시되며 , 주변의 지뢰의 수가 칸 안에 표시된다

D42

닫힌 칸을 열기• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다

D43

1-1-2. 보충 요구사항

D44

보충 요구사항

• 난이도– 초급 : 9 행 9 열의 칸 , 10 개의 지뢰

D45

1-1-3. 화면 설계

D46

화면설계

진행화면

성공하거나 실패했을 경우위와 같은 대화상자가 출력된다

D47

메뉴설계

D48

1-2. 1차개발 : 아키텍처 설계

D49

아키텍처 설계의 목적• 주요 클래스 사이의 인터페이스를 정의

– 시스템을 몇 개의 주요 클래스로 나누고 – 그들 사이의 인터페이스를 정의한다

• 주요 클래스 사이의 상호작용만 정의한다

• 주요 클래스 내부는 언급하지 않는다– 주요 클래스 내부는 상세 설계 단계에서

• 설계에서 아키텍처 설계 단계가 가장 중요하다

D50

아키텍처 설계의 산출물 ( 중요도 순서로 나열됨 )

1. Class Diagram– 주요 클래스를 그린 클래스 다이어그램 – Specification Level Class Diagram

2. Sequence Diagram– 주요 클래스 사이의 상호 작용을 설계– Specification Level Sequence Diagram– Use-case specification 에서 주요 이벤트 각각에 대하여 seque

nce diagram 이 그려져야 한다

3. Activity Diagram or Statechart Diagram

D51

작업 1: 주요 클래스 식별• 시스템을 주요 클래스로 나눈다

• 시스템을 주요 클래스로 잘 나누는 것은 설계자의 경험과 능력에 의존한다

• 클래스는 단순하게 요약 설명될 수 있는 분명한 역할이 있어야 한다

• 클래스들 사이의 관계는 상호 의존성이 낮을 수록 좋다

• 개념 설계의 클래스가 아키텍처 설계의 주요 클래스가 되어야 하는 것은 아니다– 그럴 수도 있고 아닐 수도 있다

D52

아키텍처• MVC 구조

– 문서 중심 어플리케이션의 설계에 적합함 예 : 워드프레세서 , 그래픽 에디터

– Model : 어플리케이션의 주요 데이터를 담당– View : 사용자 인터페이스를 담당– Controller : 처리 절차를 담당

• 3 계층 구조– 데이터베이스 기반 정보 시스템 설계에 적합함– Presentation 계층 : 사용자 인터페이스를 담당– Business Logic 계층 : 업무 로직을 담당– Data 계층 : 데이터를 담당

D53

주요 클래스와 모듈• 주요 클래스는 모듈을 대표한다

• 모듈 내부에서만 접근되는 여러 클래스들이 있을 것이다

주요 클래스 1

내부 클래스 1

내부 클래스 2

주요 클래스 2 내부 클래스 3

내부 클래스 4

모듈

D54

모듈간 상호의존성• 여러 모듈이 공통으로 접근하는 자료구조가 있으면 안됨

자료구조

모듈 1주요 로직자료구조 처리 로직

모듈 3주요 로직자료구조 처리 로직

모듈 2주요 로직자료구조 처리 로직

D55

Abstract Data Type• 바람직한 구조

모듈 1주요 로직

모듈 3주요 로직

모듈 2주요 로직

자료구조

ADT자료구조 처리로직

D56

Abstract Data Type• 자료구조 + 함수

• 함수는 자료구조에 직접 접근해야 하는 처리 로직을 구현 한 것

• 외부에서는 자료구조에 직접 접근할 수 없고 이 함수만 호출할 수 있다

• 외부에 자료구조는 노출되지 않는다 (encapsulation)

• ADT 개념을 확장한 것이 객체지향 언어의 Class

D57

주요 모듈의 크기• 주요 모듈이란 일종의 서브시스템 (subsystem) 을 말한다

• 주요 모듈의 크기는 한 사람이 상세 설계 및 구현을 담당하기에 적당한 크기

• 너무 작고 세밀하게 나누지 말라

• 자세한 것은 상세설계 단계에서 설계한다

D58

작업 1: 주요 클래스 식별• 지뢰찾기는 비교적 단순한 로직이므로 주요 클래스도 단순하다

• Minesweeper : 게임 로직을 담당

• UI : 사용자 인터페이스를 담당

Minesweeper UI

D59

작업 2: 시스템 내부 절차 식별• Use-case specification 의 절차를 수행하기 위해 시스템 내부에서

수행해야 하는 일을 순서대로 적는다

• 너무 자세하면 안되고 주요 아키텍처 수준의 절차이어야 한다

D60

닫힌 칸을 열기 use-case• Main Flow

1. 지뢰가 없을 것으로 짐작되는 칸을 플레이어가 마우스 왼쪽 버튼으로 클릭한다

2. 칸은 열려진 상태로 표시되며 , 주변의 지뢰의 수가 칸 안에 표시된다

D61

닫힌 칸을 열기 use-case• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다

D62

닫힌 칸을 열기 절차1. 지뢰가 없을 것으로 짐작되는 칸을 플레이어가 마우스 왼쪽

버튼으로 클릭한다a. 마우스 입력을 받는다b. 눌려진 칸을 찾는다

2. 칸은 열려진 상태로 표시되며 , 주변의 지뢰의 수가 칸 안에 표시된다c. 칸을 열린 상태로 바꾼다d. 주변 지뢰 수를 계산한다e. 주변 지뢰수와 칸의 상태를 그린다

D63

닫힌 칸을 열기 절차• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

c-1. 지뢰가 있는 칸이면 게임 실패c-2. 게임실패 메시지를 출력하고 게임종료

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다e-1. 모든 칸이 열려졌으면 게임성공e-2. 게임성공 메시지를 출력하고 게임종료

D64

작업 3: 클래스에 역할 할당• UI

a. 마우스 입력을 받는다b. 눌려진 칸을 찾는다e. 주변 지뢰수와 칸의 상태를 그린다c-2. 게임실패 메시지를 출력하고 게임종료e-2. 게임성공 메시지를 출력하고 게임종료

• Minesweeper c. 칸을 열린 상태로 바꾼다d. 주변 지뢰 수를 계산한다c-1. 지뢰가 있는 칸이면 게임 실패e-1. 모든 칸이 열려졌으면 게임성공

D65

작업 4: 역할을 메소드에 할당• UI

– OnLBottonDowna. 마우스 입력을 받는다b. 눌려진 칸을 찾는다

– DrawGamee. 주변 지뢰수와 칸의 상태를 그린다

– GameFailurec-2. 게임실패 메시지를 출력하고 게임종료

– GameSuccesse-2. 게임성공 메시지를 출력하고 게임종료

D66

작업 4: 역할을 메소드에 할당• Minesweeper

– OpenCellc. 칸을 열린 상태로 바꾼다c-1. 지뢰가 있는 칸이면 게임 실패e-1. 모든 칸이 열려졌으면 게임성공

– GetAdjacentMineCountd. 주변 지뢰 수를 계산한다

D67

작업 5: 메소드 보완• 필요한 메소드를 추가한다

• Sequence diagram 을 그려보는 것이 바람직하다

• 상호작용을 가능한 단순하게 만든다

D68

Player

:Minesweeper:UI

OnLButtonDown(x,y)OpenCell(row,col)

GameFailure()[지뢰가 있는 칸이면]

GameSuccess()[모든 칸이 열려졌으면]

DrawGame()

GetAdjacentMineCount(row,col)

D69

작업 5: 메소드 보완• 꼭 필요한 절차가 빠졌다

• 무엇이 빠졌는가 ?– 구현해 볼 때까지는 알 수 없나 ?

• 시퀀스 다이어그램으로 꼼꼼히 시뮬레이션 하면서 빠진 절차를 밝혀 내야 한다

D70

+OnLButtonDown(in x : int, in y : int)+DrawGame()+GameFailure()+GameSuccess()

UI

+OpenCell(in row : int, in col : int)+GetAdjacentMineCount(in row : int, in col : int) : int

Minesweeper

D71

작업 5: 메소드 보완• UI 가 칸의 상태를 그리려면 Minesweeper 로부터 상태값을

받아와야 한다

• Minesweeper 가 UI 의 DrawGame() 을 호출할 필요가 없다– 칸을 연 후 다시 그려야 하는 것은 당연하다– UI 가 Minesweeper 의 OpenCell() 을 호출한 후

스스로 DrawGame() 을 호출하면 된다

• 성공과 실패 여부를 UI 가 Minesweeper 로부터 얻어가도록 수정– 호출이 단방향일 수 있다면 구조가 더 단순해진다

D72

: UI : Minesweeper

OnLButtonDown(x, y)OpenCell(row, col)

IsSuccess()

IsFailure()

DrawGame()

GetCellState(row, col)

GetAdjacentMineCount(row, col)

D73

작업 5: 메소드 보완• 초기화 / 마무리 메소드를 추가한다

D74

: UI : Minesweeper

OnNewGame()InitGame(rowCnt, colCnt, mineCnt)

DrawGame()

D75

작업 6: 클래스 다이어그램

+OnNewGame()+OnLButtonDown(in x : int, in y : int)+DrawGame()

UI

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCell(in row : int, in col : int)+IsSuccess()+IsFailure()+GetCellState(in row : int, in col : int) : CellState+GetAdjacentMineCount(in row : int, in col : int) : int

Minesweeper

+OPENED+CLOSED

<<enumeration>>CellState

D76

1-3. 1차개발 : 상세 설계

D77

1-3-1. 1차개발 : Minesweeper 상세설계

D78

상세 설계• 주요 클래스 내부 로직을 설계한다

– 아키텍처 설계에서 주요 클래스의 메소드 목록이 정의되었다– 주요 클래스의 메소드들의 내부 로직을 설계한다

• 주요 클래스 내부에서 사용될 내부 클래스들을 식별한다

• 내부 클래스에 역할을 할당한다

• 주요 클래스의 메소드 각각에 대하여 시퀀스 다이어그램이 그려져야 한다

D79

작업 1: 내부 클래스 식별• 개념 모델을 참고하여 내부 클래스를 만든다

• 개념 모델의 클래스가 주요 클래스나 내부 클래스가 아닐 수 있다

D80

+cellState : CellState+/nearbyMineCount : int

Cell+rowCount : int+columnCount : int

Minefield

1 *

Mine

1

0..1+CLOSED+OPENED

<<enumeration>>CellState

3,5,8

+neighbor

3,5,8

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCell(in row : int, in col : int)+IsSuccess() : bool+IsFailure() : bool+GetCellState(in row : int, in col : int) : CellState+GetAdjacentMineCount(in row : int, in col : int) : int

Minesweeper

1

1

D81

작업 2: 클래스에 역할 할당• Minesweeper : 지뢰찾기 게임의 로직을 담당

– 게임 성공과 실패를 판단– 칸을 열 수 있는 지 없는 지를 판단– 주변의 모든 칸도 저절로 열려야 하는 지 판단 ( 이 기능은 현재

반복에서 구현하지 않는다 )

• Minefield : 자료구조를 담당– 칸 , 지뢰 , 깃발의 목록 자료구조 – 게임의 로직과 자료구조를 분리

• Cell : 칸 ADT– 자료구조는 가능한 노출되지 않는 편이 좋다

• Mine: 지뢰 ADT

D82

작업 3: 상세로직 시퀀스 다이어그램• 주요 클래스의 메소드 각각에 대하여 시퀀스 다이어그램을 그린다

– Minesweeper 모듈의 주요 클래스는 Minesweeper – Minesweeper 클래스의 메소드 각각에 대하여

상세로직 시퀀스 다이어그램을 그린다

• 상세로직 시퀀스 다이어그램을 그리면서– 내부 클래스에 할당된 역할에 따라

내부 클래스에 메소드를 만든다

D83

: UI : Minesweeper : Minefield : Cel mine : Mine

InitGame(rowCnt, colCnt, mineCnt)

InitMinefield(rowCnt, colCnt, mineCnt)

Cell()

Mine()

PutMine(mine)

D84

: UI : Minesweeper : Minefield cell : Cell

GetCellState(row, col)

cell:=GetCell(row, col)

state:=GetState()

state

D85

: UI : Minesweeper : Minefield cell : Cell

OpenCell(row, col)

cell:=GetCell(row, col)

GetState()

Open()

IsMined()

AreAllMinesFound()

D86

: UI : Minesweeper : Minefield cell : Cell

cell:=GetCell(row, col)

IsMined()

GetAdjacentMineCount(row, col)

D87

작업 4: 클래스 다이어그램• 시퀀스 다이어그램을 그리며 만든 메소드를 클래스 다이어그램으로

정리한다

D88

+Cell()+PutMine(in mine : Mine)+GetState() : CellState+IsMined() : bool+Open()

Cell

+InitMinefield(in rowCnt : int, in colCnt : int, in mineCnt : int)+GetCell(in row : int, in col : int) : Cell+AreAllMinesFound() : bool

Minefield

1

*

+Mine()

Mine

1

0..1

+CLOSED+OPENED

<<enumeration>>CellState

3,5,8

+neighbor

3,5,8

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCell(in row : int, in col : int)+IsSuccess() : bool+IsFailure() : bool+GetCellState(in row : int, in col : int) : CellState+GetAdjacentMineCount(in row : int, in col : int) : int

Minesweeper

1

1

D89

작업 5: 클래스 다이어그램 보완• Mine 클래스는 메소드가 없다 . 부여된 역할이 없다

• Cell 에 Mine 이 있는지 없는지 나타내는 bool 형의 멤버 변수 하나면 족하다

• Minefield 자료구조를 2차원 배열 자료구조로 만들면 neighbor 연관을 구현할 필요 없다

• GetAdjacentMineCount() 는 게임로직이라기 보다는 Minefield 자료구조에 대한 검색에 가깝다– Minefield 클래스에서 구현

D90

+Cell()+PutMine(in mine : Mine)+GetState() : CellState+IsMined() : bool+Open()

Cell

+InitMinefield(in rowCnt : int, in colCnt : int, in mineCnt : int)+GetCell(in row : int, in col : int) : Cell+AreAllMinesFound() : bool+GetAdjacentMineCount(in row : int, in col : int) : int

Minefield

1

*

+CLOSED+OPENED

<<enumeration>>CellState

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCell(in row : int, in col : int)+IsSuccess() : bool+IsFailure() : bool+GetCellState(in row : int, in col : int) : CellState+GetAdjacentMineCount(in row : int, in col : int) : int

Minesweeper

1

1

D91

작업 6: 시퀀스 다이어그램 보완• 변경된 클래스 다이어그램에 따라 시퀀스 다이어그램을 보완한다

D92

: UI : Minesweeper : Minefield : Cell

InitGame(rowCnt, colCnt, mineCnt)

InitMinefield(rowCnt, colCnt, mineCnt)

Cell()

PutMine(mine)

D93

: UI : Minesweeper : Minefield cell : Cell

GetAdjacentMineCount(row, col)

IsMined()

GetAdjacentMineCount(row, col)

cell:=GetCell(row, col)

D94

1-3-2. 1차개발 : UI 상세 설계

D95

UI 상세 설계는 생략• UI 상세 설계는 구현될 플랫폼의 UI 기술에 크게 의존한다

• 여기서는 Microsoft Visual C++ MFC 로 구현한다

D96

+OnGameNew()+DrawGame()+OnLButtonDown()

-minesweeper : MinesweeperUI

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCell(in row : int, in col : int)+IsSuccess() : bool+IsFailure() : bool+GetCellState(in row : int, in col : int) : CellState+GetAdjacentMineCount(in row : int, in col : int) : int

Minesweeper

D97

1-4. 1차개발 : 테스트 구현

D98

UI 테스트 구현• 다음과 같은 Minefield 를 구현하여 UI 를 테스트한다

D99

UI 테스트 데이터 구현• 지뢰

1

1

1 1

1 1

1

1 1 1

D100

UI 테스트 데이터 구현• 주변 지뢰 수

1 2 1 0 0 0 0 0

1 2 1 0 0 0 0 0

1 1 2 2 2 1 0 0 0

0 0 2 1 1 1 1

0 0 2 3 1 1 1

0 0 1 1 1 0 1 1 1

0 1 1 1 0 0 0 0 0

1 2 1 0 1 2 2 1

1 2 1 0 1 1

D101

model.h#ifndef MINESWEEPER_H#define MINESWEEPER_H

enum CellState {CLOSED = 0,OPENED = 1

};

class Minesweeper {public:

void InitGame(int rowCnt, int colCnt, int mineCnt);void OpenCell(int row, int col);bool IsSuccess();bool IsFailure();CellState GetCellState(int row, int col);int GetAdjacentMineCount(int row, int col);

};

#endif

D102

model.cpp#include <stdafx.h>#include <assert.h>#include "model.h"

static char mine[9][9] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0};

static char adjacentMineCnt[9][9] = { 1, 2, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 1, 1, 0, 0, 2, 0, 3, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 1, 2, 2, 1, 1, 0, 2, 1, 0, 1, 0, 0, 1};

D103

static char opened[9][9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

void Minesweeper::InitGame(int rowCnt, int colCnt, int mineCnt) {memset(opened, 0, sizeof(char) * 9 * 9);

}

void Minesweeper::OpenCell(int row, int col) {assert( 0 <= row && row < 9 );assert( 0 <= row && col < 9 );opened[row][col] = 1;

}

bool Minesweeper::IsSuccess() {for (int r = 0; r < 9; ++r)for (int c = 0; c < 9; ++c)

if (!opened[r][c] && !mine[r][c]) return false;return true;

}

D104

bool Minesweeper::IsFailure() {for (int r = 0; r < 9; ++r)for (int c = 0; c < 9; ++c)

if (opened[r][c] && mine[r][c]) return true;return false;

}

CellState Minesweeper::GetCellState(int row, int col) {assert( 0 <= row && row < 9 );assert( 0 <= row && col < 9 );if (opened[row][col]) return OPENED;return CLOSED;

}

int Minesweeper::GetAdjacentMineCount(int row, int col) {assert( 0 <= row && row < 9 );assert( 0 <= row && col < 9 );return adjacentMineCnt[row][col];

}

D105

Model 테스트 구현• UI 를 텍스트 모드로 구현한다

D106

UI.c#include <stdio.h>#include "model.h"

Minesweeper game;

void help() { printf("o 6 3 -> 6 행 3 열의 사각형을 열기 \n"); printf("h -> 도움말 \n"); printf("x -> 게임 종료 \n"); printf("\n\n");}

void showMinefield() { int row, col; printf(" "); for (col = 0; col < 9; ++col) printf(" %d ", col); for (row = 0; row < 9; ++row) { printf("\n %d ", row); for (col = 0; col < 9; ++col) if (game.GetCellState(row, col) == CLOSED) printf(" . "); else { int n = game.GetAdjacentMineCount(row, col); if (n == 0) printf(" "); else printf(" %d ", n); } } printf("\n\n>");}

D107

void main() { char s[80]; int r, c;

game.InitGame(9, 9, 10); help(); for (;;) { showMinefield(); gets(s); switch(s[0]) { case 'o': case 'O': sscanf(s+1, "%d %d", &r, &c); game.OpenCell(r, c); if (game.IsSuccess()) { puts("You Win"); return; } if (game.IsFailure()) { puts("Game Over"); return; } break; case 'h': case 'H': help(); break; case 'q': case 'Q': return; }; }}

D108

2-1. 2차개발 분석

D109

개요• " 닫힌 칸을 열기 " 구현 보완

• " 지뢰를 표시 " 구현

D110

2-1-1. Use-case Model

D111

Use Case Diagram

플레이어

지뢰찾기

닫힌 칸을 열기

지뢰를 표시

닫힌 칸들을 열기

D112

Use Case Specification• Name : 닫힌 칸을 열기

• Description:– 지뢰가 없을 것으로 짐작되는 칸을 연다

• Actor: 플레이어

• Precondition: – 칸은 닫혀있어야 한다– 지뢰 표시가 없는 칸이어야 한다

D113

닫힌 칸을 열기• Main Flow

1. 지뢰가 없을 것으로 짐작되는 칸을 플레이어가 마우스 왼쪽 버튼으로 클릭한다

2. 칸은 열려진 상태로 표시되며 , 주변의 지뢰의 수가 칸 안에 표시된다

3. 주변의 지뢰의 수가 0 이면 • 지뢰 수 0 은 표시되지 않고• 주변의 닫힌 칸들이 모두 열려지며• 각 칸 안에 그 주변의 지뢰의 수가 표시된다 . • 이 과정은 재귀적으로 반복된다

D114

닫힌 칸을 열기• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다

D115

Use Case Specification• Name : 지뢰를 표시

• Description:– 지뢰가 있을 것으로 짐작되는 칸에 지뢰 표시를 한다

• Actor: 플레이어

• Precondition: – 칸은 닫혀있어야 한다

D116

지뢰를 표시• Main Flow:

1. 지뢰가 있을 것으로 짐작되는 칸을 플레이어가 마우스 오른쪽 버튼으로 클릭한다

2. 칸에 지뢰 표시가 되고 , 남은 지뢰 수 표시가 1 감소한다 .

3. 지뢰 표시가 된 칸을 마우스 오른쪽 버튼으로 클릭한다

4. 칸에서 지뢰 표시가 제거되고 , 남은 지뢰 수 표시가 1 증가한다

D117

지뢰를 표시• Notes:

– 지뢰 표시가 된 칸은 열 수가 없다" 닫힌 칸 열기 " 의 Precondition 참고

D118

2-1-2. 보충 요구사항

D119

보충 요구사항

• 변화 없음

D120

2-1-3. 화면 / 메뉴 설계

D121

화면 / 메뉴 설계

D122

2-2. 2차개발 설계

D123

개요• 2차 개발에서 추가된 기능을 설계 구현한다

• 1차 개발에서 설계 구현된 것을 수정한다

• 얼마나 수정되어야 하는가 ?

• 1차 개발의 설계가 우수했다면– 변경은 적을 것이고– 주로 기능 추가일 것이다

• 만약 크게 변경되어야 한다면 – 1차 개발의 설계가 무엇이 잘못되었는지 분석 반성하여야 한다– 반성의 결과는 바람직한 설계 지침으로 정리되어야 함

D124

작업 1: 시스템 내부 절차 식별• 추가된 Use-case specification 의 절차를 수행하기 위해 시스템

내부에서 수행해야 하는 일을 순서대로 적는다

D125

닫힌 칸을 열기 use-case• Main Flow

1. 지뢰가 없을 것으로 짐작되는 칸을 플레이어가 마우스 왼쪽 버튼으로 클릭한다

2. 칸은 열려진 상태로 표시되며 , 주변의 지뢰의 수가 칸 안에 표시된다

3. 주변의 지뢰의 수가 0 이면 • 지뢰 수 0 은 표시되지 않고• 주변의 닫힌 칸들이 모두 열려지며• 각 칸 안에 그 주변의 지뢰의 수가 표시된다 . • 이 과정은 재귀적으로 반복된다

D126

주변 지뢰 수 0 일 때의 절차• 주변의 닫힌 칸들을 모두 연다

• 이미 구현된 Minesweeper.OpenCell(int row, int col) 메소드를 호출하여 주변의 닫힌 칸들을 모두 연다

• 재귀적으로 구현한다

D127

지뢰를 표시 use-case• Main Flow:

1. 지뢰가 있을 것으로 짐작되는 칸을 플레이어가 마우스 오른쪽 버튼으로 클릭한다

2. 칸에 지뢰 표시가 되고 , 남은 지뢰 수 표시가 1 감소한다 .

3. 지뢰 표시가 된 칸을 마우스 오른쪽 버튼으로 클릭한다

4. 칸에서 지뢰 표시가 제거되고 , 남은 지뢰 수 표시가 1 증가한다

D128

지뢰를 표시 절차a. 오른쪽 버튼의 입력을 받는다 (UI)b. 눌려진 칸을 찾는다 (UI)c. 칸에 지뢰 표시를 토글한다 (Minesweeper)

D129

칸의 상태• Opened, Closed, Mined, Flaged

• Cell 의 상태 메소드 정리– bool IsOpened();– bool IsMined();– bool IsFlaged();

• Minesweeper 의 상태 메소드 정리– bool IsOpened();– bool IsMined();– bool IsFlaged();

D130

작업 2: 시퀀스 다이어그램으로 설계 : UI : Minesweeper : Minefield cell : Cell

OpenCell(row, col)

cell:=GetCell(row, col)

IsFlaged()

IsOpened()

IsMined()

OpenAdjacentCells(row, col)

AreAllMinesFound()

Open()

GetAdjacentMineCount(row, col)

D131

: UI : Minesweeper

OpenAdjacentCells(row, col)

OpenCell(row, col)

D132

: UI : Minesweeper : Minefield cell : Cell

FlagCell(row, col)

cell:=GetCell(row, col)

IsFlaged()

PutFlag()

RemoveFlag()

OnRButtonDown(x, y)

IsOpened()

D133

작업 3: 클래스 다이어그램

+Cell()+PutMine(in mine : Mine)+IsOpened() : bool+IsMined() : bool+Open()+PutFlag()+RemoveFlag()+IsFlaged() : bool

Cell

+InitMinefield(in rowCnt : int, in colCnt : int, in mineCnt : int)+GetCell(in row : int, in col : int) : Cell+AreAllMinesFound() : bool+GetAdjacentMineCount(in row : int, in col : int) : int

Minefield

1

*

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCell(in row : int, in col : int)+IsSuccess() : bool+IsFailure() : bool+GetAdjacentMineCount(in row : int, in col : int) : int+FlagCell(in row : int, in col : int)+IsOpened(in row : int, in col : int) : bool+IsMined(in row : int, in col : int) : bool+IsFlaged(in row : int, in col : int) : bool+OpenAdjacentCells(in row : int, in col : int)

Minesweeper

1

1

+OnGameNew()+DrawGame()+OnLButtonDown()+OnRButtonDown(in x : int, in y : int)

-minesweeper : MinesweeperUI

D134

변경 사항• 추가되는 메소드

– UI::OnRButtonDown(int x, int y);– Minesweeper::FlagCell(int row, int col);– Minesweeper::OpenAdjacentCells(int row, int col);– Cell::PutFlag();– Cell::RemoveFlag();

• 수정되는 메소드– Minesweeper::OpenCell(int row, int col);– 주변 지뢰 수가 0일 경우 OpenAdjacentCells() 호출을 하도록

수정

D135

변경 사항• Cell 의 GetState() 메소드를 다음으로 대체한다

– Cell::IsOpened()– Cell::IsFlaged()– Cell::IsMined()

• Minesweeper 의 GetCellState() 메소드를 다음으로 대체한다– Minesweeper::IsOpened()– Minesweeper ::IsFlaged()– Minesweeper ::IsMined()

D136

2-3. 2차개발 테스트 계획

D137

UI 테스트 구현• 다음과 같은 Minefield 를 구현하여 UI 를 테스트한다

D138

UI 테스트 데이터 구현• 지뢰

1

1

1 1

1 1

1

1 1 1

D139

UI 테스트 데이터 구현• 주변 지뢰 수

1 2 1 0 0 0 0 0

1 2 1 0 0 0 0 0

1 1 2 2 2 1 0 0 0

0 0 2 1 1 1 1

0 0 2 3 1 1 1

0 0 1 1 1 0 1 1 1

0 1 1 1 0 0 0 0 0

1 2 1 0 1 2 2 1

1 2 1 0 1 1

D140

model.h#ifndef MINESWEEPER_H#define MINESWEEPER_H

class Minesweeper {public: void InitGame(int rowCnt, int colCnt, int mineCnt); void OpenCell(int row, int col); void FlagCell(int row, int col); bool IsSuccess(); bool IsFailure(); int GetAdjacentMineCount(int row, int col); bool IsFlaged(int row, int col); bool IsOpened(int row, int col); bool IsMined(int row, int col);};

#endif

D141

model.cpp#include <stdafx.h>#include <assert.h>#include "model.h"

static char mine[9][9] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0};

static char adjacentMineCnt[9][9] = { 1, 2, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 1, 1, 0, 0, 2, 0, 3, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 1, 2, 2, 1, 1, 0, 2, 1, 0, 1, 0, 0, 1};

D142

static char opened[9][9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

static char flaged[9][9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

D143

void Minesweeper::InitGame(int rowCnt, int colCnt, int mineCnt) {memset(opened, 0, sizeof(char) * 9 * 9);

memset(flaged, 0, sizeof(char) * 9 * 9);}

void Minesweeper::OpenCell(int row, int col) {assert( 0 <= row && row < 9 && 0 <= row && col < 9 );

if (flaged[row][col]) return;opened[row][col] = 1;

}

bool Minesweeper::IsSuccess() {for (int r = 0; r < 9; ++r)for (int c = 0; c < 9; ++c) if (!opened[r][c] && !mine[r][c]) return false;return true;

}

bool Minesweeper::IsFailure() {for (int r = 0; r < 9; ++r)for (int c = 0; c < 9; ++c) if (opened[r][c] && mine[r][c]) return true;return false;

}

int Minesweeper::GetAdjacentMineCount(int row, int col) {assert( 0 <= row && row < 9 && 0 <= row && col < 9 );return adjacentMineCnt[row][col];

}

D144

bool Minesweeper::IsFlaged(int row, int col) {assert( 0 <= row && row < 9 && 0 <= row && col < 9 );return flaged[row][col] == 1;

}

bool Minesweeper::IsMined(int row, int col) {assert( 0 <= row && row < 9 && 0 <= row && col < 9 );return flaged[row][col] == 1;

}

bool Minesweeper::IsOpened(int row, int col) {assert( 0 <= row && row < 9 && 0 <= row && col < 9 );return opened[row][col] == 1;

}

void Minesweeper::FlagCell(int row, int col) {assert( 0 <= row && row < 9 && 0 <= row && col < 9 );

flaged[row][col] = 1;}

D145

Model 테스트• Model 은 UI 와 통합하여 테스트한다

D146

3-1. 3차개발 분석

D147

개요• " 닫힌 칸들을 열기 " 구현

D148

3-1-1. Use-case Model

D149

Use Case Diagram

플레이어

지뢰찾기

닫힌 칸을 열기

지뢰를 표시

닫힌 칸들을 열기

D150

Use-case Specification• Name : 닫힌 칸들을 열기• Description:

– 인접한 지뢰가 모두 표시되었을 경우 , 지뢰가 없는 인접한 빈 칸을 모두 동시에 연다

• Actor: 플레이어

• Precondition: – 클릭하는 칸은 열려 있어야 한다– 열려진 칸에 표시된 주변 지뢰 수 만큼

주변 칸들에 지뢰 표시들이 있어야 한다

D151

닫힌 칸들을 열기• Main Flow

1. 열려진 칸에서 마우스 왼쪽과 오른쪽 버튼을 동시에 누른다

2. 인접한 8개의 칸들 중 지뢰 표시가 되어 있지 않은 칸들 이 열려진다 . 열려진 각 칸들에는 인접한 지뢰의 수가 표시된다 .

3. 열려진 칸의 주변 지뢰의 수가 0 이면• 지뢰 수 0 은 표시되지 않고• 주변의 칸 모두 열려지며• 각 칸 안에 그 주변의 지뢰의 수가 표시된다 . • 이 과정은 재귀적으로 반복된다

D152

닫힌 칸들을 열기• Alternative Flow

A2. 지뢰가 있는 칸이었으면 지뢰가 폭발하여 게임은 실패로 종료된다

A2. 모든 칸이 열려졌으면 게임은 성공으로 종료된다

D153

3-1-2. 보충 요구사항

D154

보충 요구사항

• 난이도– 초급 : 9 행 9 열의 칸 , 10 개의 지뢰– 중급 : 16 행 16 열의 칸 , 40 개의 지뢰– 고급 : 16 행 30 열의 칸 , 99개의 지뢰

• 화면에 남은 지뢰수가 표시된다– 남은 지뢰수 = 전체 지뢰 수 – 지뢰 표시의 수

D155

3-1-3. 화면 / 메뉴 설계

D156

화면설계

진행화면 성공 실패

D157

3-2. 3차개발 설계

D158

개요• 3차 개발에서 추가된 기능을 설계 구현한다

• 2차 개발에서 설계 구현된 것을 수정한다

D159

작업 1: 시스템 내부 절차 식별• 추가된 Use-case specification 의 절차를 수행하기 위해 시스템

내부에서 수행해야 하는 일을 순서대로 적는다

D160

닫힌 칸들을 열기 절차1. 마우스 두 버튼이 동시에 눌려진 것을 감지한다2. 열린 칸이 아니면 무시3. 주변의 지뢰 수와 주변의 지뢰표시 수를 비교한다

3-1. 주변 지뢰 수 계산3-2. 주변 지뢰표시 수 계산

4. 두 수가 같으면 주변의 지뢰표시가 없고 닫혀진 모든 칸을 연다 . 5. 주변의 칸을 여는 절차는 이미 구현한 inesweeper.AdjacentCells()

를 이용한다6. 두 수가 같지 않으면 무시

D161

메소드에 역할 할당• UI::OnRButtonDown() 1

• Minesweeper::OpenCells() 2, 3, 4, 6

• Minefield::GetAdjacentMineCount() 3-1

• Minefield::GetAdjacentFlagCount() 3-2

• Minesweeper::OpenAdjacentCells() 5

D162

작업 2: 시퀀스 다이어그램으로 설계

: UI

OnRButtonDown(x, y)

OnLButtonDown()

: Minesweeper

OpenCells(row, col)

: Minefield

GetAdjacentMineCount(row, col)

GetAdjacentFlagCount(row, col)

OpenAdjacentCells(row, col)

D163

: UI : Minesweeper

GetFlagCount()

: Minefield

GetFlagCount()

DrawGame()

cell : Cell

IsFlaged()

IsSuccess()

IsFailure()

IsOpened(row, col)

IsFlaged(row, col)

IsExploded(row, col)

IsMined(row, col)

IsClosed(row, col)

cell:=GetCell(row, col)

IsFlaged()

IsMined()

D164

작업 3: 클래스 다이어그램

+Cell()+PutMine(in mine : Mine)+IsOpened() : bool+IsMined() : bool+Open()+PutFlag()+RemoveFlag()+IsFlaged() : bool

Cell

+InitMinefield(in rowCnt : int, in colCnt : int, in mineCnt : int)+GetCell(in row : int, in col : int) : Cell+AreAllMinesFound() : bool+GetAdjacentMineCount(in row : int, in col : int) : int+GetAdjacentFlagCount(in row : int, in col : int) : int+GetFlagCount() : int+IsValidIndex(in row : int, in col : int) : bool

Minefield

1

*

+InitGame(in rowCnt : int, in colCnt : int, in mineCnt : int)+OpenCells(in row : int, in col : int)+OpenAdjacentCells(in row : int, in col : int)+OpenCell(in row : int, in col : int)+FlagCell(in row : int, in col : int)+GetAdjacentMineCount(in row : int, in col : int) : int+GetFlagCount() : int+IsSuccess() : bool+IsFailure() : bool+IsOpened(in row : int, in col : int) : bool+IsMined(in row : int, in col : int) : bool+IsFlaged(in row : int, in col : int) : bool+IsClosed(in row : int, in col : int) : bool+IsExploded(in row : int, in col : int) : bool

Minesweeper

1

1

+OnGameNew()+DrawGame()+OnLButtonDown()+OnRButtonDown(in x : int, in y : int)+OnGameBasic()+OnGameIntermediate()+OnGameExtended()

-minesweeper : MinesweeperUI

D165

3-3. 3차개발 테스트 계획

D166

테스트 계획• 추가되는 기능이 매우 단순한 편

• 두 모듈 각각의 테스트는 생략하고 통합하여 테스트한다

D167

4. 4차개발

D168

개요• 화면 깜빡거림의 개선

• 마우스 왼쪽 버튼을 누를 때– 누르고 있을 때는 칸이 눌린 상태로 그려짐– 버튼이 놓여질 때 칸이 열리도록

• 두 버튼을 동시에 누를 때– 어느 버튼이 먼저 눌려졌는지 상관 없도록– 누르고 있을 때는 주변의 지뢰표시 없는 칸들이 눌린 상태로

그려짐– 버튼이 놓여질 때 칸들이 열리도록

D169

설계

OnLButtonDown/ ShowCellPressed

OnRButtonDown

OnRButtonDownOnLButtonDown

Init

LDownRDown

LRDown

Entry: ShowCellsPressed

OnLButtonUp/ OpenCell()

OnRButtonUp/ FlagCell() OnLButtonUp

OrOnRButtonUp/ OpenCells()

OnLButtonUpOr

OnRButtonUp