Contents
1. 소개글 ¶
데블스캠프2002때 소개했었던 StructuredProgramming 기법을 처음부터 끝까지 진행하는 모습을 보여드립니다. 중간에 버그가 발생하고, 그 버그를 수정한 소스를 그대로 실어봅니다. 그대로 따라해보셔도 좋을듯. 단, 중간 삽질과 컴파일 에러에 겁먹지만 않으신다면. ^^;
Spec 과 Test Case 는 RandomWalk2 에 있습니다.
2. 개발원리 ¶
StructuredProgramming 기법으로 StepwiseRefinement 하였습니다. 문제를 TopDown 스타일로 계속 재정의하여 뼈대를 만든 다음, Depth First (트리에서 깊이 우선) 로 가장 작은 모듈들을 먼저 하나하나 구현해 나갔습니다. 중반부터는 UnitTest 코드를 삽입하기를 시도, 중후반부터는 UnitTest Code를 먼저 만들고 프로그램 코드를 나중에 작성하였습니다.
3. Version 0.1 - 프로그램의 가장 추상적 단계 ¶
말 그대로. 전형적인 '프로그램' 입니다. '입력을 받고, 처리해서 출력한다.' 라는;
~cpp int main () { Input (); Process (); Output (); return 0; } void Input () { } void Process () { } void Output () { }
Process () 는 그리 명확하지 못하다고 생각, 약간 더 구체적으로 이름을 바꿨습니다.
~cpp int main () { Input (); ScheduledWalk (); Output (); return 0; } void ScheduledWalk () { }
4. Version 0.2 - Refinement ¶
위까진 프로그램의 트리중 1차 레벨이겠고, 이를 조금씩 재정의해나갔습니다. 컴파일 에러는 거의 뭐 무시를..~ 어차피 뼈대이므로. 컴파일 에러나 무한루프 등이 문제가 발생하는 경우엔 일단 void 형으로 리턴값을 적거나 return false; 식으로 채워넣습니다. 일단은 뼈를 잡는게 더 중요하므로.
~cpp void Input() { InputBoardSize(); InputStartRoachPosition(); InputRoachJourney(); } void InputBoardSize() { } void InputStartRoachPosition() { } void InputRoachJourney() { } void ScheduledWalk() { while (!IsFinished()) { Move(); } } BOOL IsFinished() { return IsJourneyEnd() || IsAllBoardChecked(); } void Move() { } void Output() { OutputMoveCount(); OutputBoardStatus(); } void OutputMoveCount() { } void OutputBoardStatus() { }
5. Version 0.3 - Refinement More ¶
이정도까지 진행되는데 한 15분정도 걸렸군요. 아마 연습이 충분하다면 10분내로도 가능할듯.~이 코드는 아무런 하는 일이 없으니까요.~
~cpp typedef int BOOL; void Input(); void InputBoardSize(); void InputStartRoachPosition(); void InputRoachJourney(); void ScheduledWalk(); BOOL IsFinished(); BOOL IsJourneyEnd(); BOOL IsAllBoardChecked(); void MoveNext(); void Output(); void OutputMoveCount(); void OutputBoardStatus(); int main() { Input(); ScheduledWalk(); Output(); return 0; } void Input() { InputBoardSize(); InputStartRoachPosition(); InputRoachJourney(); } void InputBoardSize() { } void InputStartRoachPosition() { } void InputRoachJourney() { } void ScheduledWalk() { while (!IsFinished()) { MoveNext(); } } BOOL IsFinished() { return IsJourneyEnd() || IsAllBoardChecked(); } BOOL IsJourneyEnd() { return false; } BOOL IsAllBoardChecked() { return false; } void MoveNext() { } void Output() { OutputMoveCount(); OutputBoardStatus(); } void OutputMoveCount() { } void OutputBoardStatus() { }
여기까지가 지난번 데블스캠프2002 때 그렸었던 HIPO 뼈대를 코드로 옮긴 것입니다.
이 답이 완벽한 답은 아니며, HIPO 이후 바로 프로그램 완성까지의 길에는 약간 거리가 있습니다. (왜냐. 이 Top-Down Design 의 결과가 완벽하다라고 말할수는 없으니까요. 하지만, 문제와 전반적 프로그램 디자인, 큰 밑그림을 그리고 이해하는데 도움을 줌에는 분명합니다. )
이 답이 완벽한 답은 아니며, HIPO 이후 바로 프로그램 완성까지의 길에는 약간 거리가 있습니다. (왜냐. 이 Top-Down Design 의 결과가 완벽하다라고 말할수는 없으니까요. 하지만, 문제와 전반적 프로그램 디자인, 큰 밑그림을 그리고 이해하는데 도움을 줌에는 분명합니다. )
(Hierarchy Input-Process-Output) 의 경우엔 다음과 같습니다. (그림 첨부 필요)
6. Version 0.4 - Implementation : Input ¶
10분 휴식 - 1시 55분까지. 커피 보충등등;
이정도면 처음에 생각해둔 뼈대가 나왔다고 생각됩니다. (즉, 추후 더 세분화시켜서 나눌 수 있긴 하지만, 이정도에서도 바로 구현으로 들어가는데 별 문제가 없을 것이라고 생각될정도)
이정도면 처음에 생각해둔 뼈대가 나왔다고 생각됩니다. (즉, 추후 더 세분화시켜서 나눌 수 있긴 하지만, 이정도에서도 바로 구현으로 들어가는데 별 문제가 없을 것이라고 생각될정도)
그럼. 하나씩 구현을 해 들어갑니다.
어떤 함수 또는 모듈 부터 구현을 해야 할까 궁리했었습니다. 어차피 각 모듈부분에선 그 인자를 구체적으로 명시시키지 않았습니다. 이쯤에서 DFD를 그리고 데이터의 흐름에 대해 표현할 수도 있겠지만, 저는 일단 소스 자체에 촛점을 맞췄습니다. 그래서 필요하면 인자를 하나씩 더 추가하고, 필요없어졌다 싶음 인자를 삭제하는 식으로 접근했습니다. 그래서 따로 HIPO 다이어그램에 Argument 를 넘기는 부분을 표현해두지 않았습니다. (워낙 자주 소스를 고친 관계로. 하지만, 시간이 많이 걸린 일은 아니였습니다.~)
구현 순서에 대해서 원칙이 있으면 좋을것이란 판단하에 다음과 같은 원칙을 세웠습니다.
- 순차적으로 - 왼쪽 -> 오른쪽 순서로. 실행 순서에 따라 구현한다. (실행 순서와 상관없이 독립적으로 따로 생각하여 구현할 수 있습니다. 이는 UnitTest 참조)
- Depth-Module First. -> 깊이가 가장 깊이에 있는 것들이 쉬운 문제일 것이라 판단, 깊이가 깊은 모듈부터 구현하기로 했습니다. (일장일단인데, 그 대신 잘못 접근하면 Bottom-Up 이 되어버릴 수도 있기 때문에.. 이 경우 해당 함수가 하는 일을 명확하게 해줄 필요가 있다고 생각됩니다. 전체 구조 내에서의 역할을 잊어선 안되겠죠.)
~cpp void InputBoardSize() { }
이 함수가 하는 일은 말 그대로 Board 의 Size 를 Input. 판 크기를 입력받는 부분입니다. scanf 나 cin 등으로 간단하게 구현할 수 있겠죠.
~cpp void InputBoardSize() { int boardRow; int boardCol; scanf("%d%d", &boardRow, &boardCol); printf ("%d, %d \n", boardRow, boardCol); }
이 부분에 대해선 다른 Visual C++ 을 연뒤, 따로 구현해보고 잘 작동하면 본 소스에 붙일 수 있습니다. 입력이 잘 받아지는군요. 이 입력에 대해서 데이터를 넘겨주고 넘겨주고 해야겠군요.
입력데이터를 받아서 처리하는 방법에는 두가지가 있겠습니다. 하나는 리턴값을 넘겨주는 방법, 하나는 인자로 해당 변수의 포인터 또는 레퍼런스를 받은뒤, 그 변수의 값을 변화시켜주는 방법. (scanf 함수가 그러한 방법이지요.) 여기선 간단하게 리턴값을 넘겨주는 방법을 이용했습니다. int 형 두개 변수를 리턴하는 것이라면 구조체를 이용하는 것이 더 간단하리라는 판단에서입니다.
~cpp typedef struct __IntegerPair { // return 을 하기 위한 구조체 선언 int n1; int n2; } IntPair; IntPair InputBoardSize(); // void InputBoardSize() 에서 IntPair InputBoardSize() 로 리턴값이 바뀌었습니다. 어차피 처음에 만든 프로토타입들은 말 그대로 '뼈' 이기에. IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardRow, &boardCol); size.n1 = boardRow; size.n2 = boardCol; 0 return size; }
리턴값이 잘 넘어오는지 테스트해볼까요?
~cpp #include <stdio.h> typedef int BOOL; typedef struct __IntegerPair { int n1; int n2; } IntPair; IntPair InputBoardSize(); void Input(); IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardRow, &boardCol); size.n1 = boardRow; size.n2 = boardCol; return size; } void Input() { IntPair testReceiver; testReceiver = InputBoardSize(); printf ("Board Size value : %d, %d \n", testReceiver.n1, testReceiver.n2); }
Input 에서 테스트해본 결과 값이 잘 출력되는군요. 그럼, 계속해서 Input의 다른 함수들인 InputStartRoachPosition(), InputRoachJourney() 에 대해 계속 구현을 해보죠.
~cpp IntPair InputStartRoachPosition() { IntPair position; int startRow; int startCol; scanf("%d%d", &startRow, &startCol); position.n1 = startRow; position.n2 = startCol; return position; }
InputRoachJourney() 는 String 문자열인 관계로 좀 다르게 구현했습니다. 아까 말한, 메모리 포인터를 넘겨서 값을 저장하는 방식에 속합니다. 배열은 또다른 포인터와 다름없기에, 이렇게 쓸 수 있습니다.
~cpp void InputRoachJourney(PSTR journey) { scanf ("%s", journey); }
사실 이 방법은 위험합니다. char [] 일 journey 의 사이즈를 모르고 있기 때문이죠. 만일 journey 에서 입력받은 여정의 크기가 클 경우 메모리에러를 발생시킬 수 있습니다. 하지만, 일단은 성능은 따지지 않고 '가장 간단하게 돌아가는 소스' 를 생각하기 위해 그냥 저렇게 남겨둬봅니다. 원래라면 배열의 최대값보다 더 큰 여정이 나왔을 경우의 처리 등을 생각해야 합니다. 단, 이 문제에 대해선 InputRoachJourney () 함수 내로 지역화가 어느정도 가능합니다. 여기서는 Structured Programming 식으로 접근하려는 것이 목적이여서, 세부적인 문제에 대해서는 좀 덜 신경썼습니다.
Input 부분 Implementation 1차 완료된 모습은 이러했습니다.
~cpp #include <stdio.h> typedef char* PSTR; const int MAX_JOURNEY_LENGTH = 1000; typedef struct __IntegerPair { int n1; int n2; } IntPair; void Input(); IntPair InputBoardSize(); IntPair InputStartRoachPosition(); void InputRoachJourney(PSTR journey); void Input() { IntPair testReceiver; testReceiver = InputBoardSize(); printf ("Board Size value : %d, %d \n", testReceiver.n1, testReceiver.n2); testReceiver = InputStartRoachPosition(); printf ("Start Position value : %d, %d \n", testReceiver.n1, testReceiver.n2); char testJourney[MAX_JOURNEY_LENGTH]=""; InputRoachJourney(testJourney); printf ("Journey : %s \n", testJourney); } IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardRow, &boardCol); size.n1 = boardRow; size.n2 = boardCol; return size; } IntPair InputStartRoachPosition() { IntPair position; int startRow; int startCol; scanf("%d%d", &startRow, &startCol); position.n1 = startRow; position.n2 = startCol; return position; } void InputRoachJourney(PSTR journey) { scanf ("%s", journey); }
현재 실제 구현부분의 프로세스는 다음과 같습니다. 이 작업들이 어느정도 노가다작업화(?) 되어가는 모습이 보일겁니다.
1. 구현하려는 함수 선택
2. 구현. 필요한 변수가 생길때마다 하나씩 인자로 넘겨받기.
3. return 값에 대해 설정. 때에 따라 구조체의 선언.
4. 함수 호출뒤 return 값에 대해서 printf나 cout 등으로 결과값을 확인해보기.
2. 구현. 필요한 변수가 생길때마다 하나씩 인자로 넘겨받기.
3. return 값에 대해 설정. 때에 따라 구조체의 선언.
4. 함수 호출뒤 return 값에 대해서 printf나 cout 등으로 결과값을 확인해보기.
다음은 Input 함수 안에서 얻어낸 데이터들을 main 함수까지 끌어올립니다. 이제 ScheduedWalk 모듈에 입력된 데이터를 보내줄 준비가 되었습니다.
~cpp #include <stdio.h> typedef int BOOL; typedef char* PSTR; const int MAX_JOURNEY_LENGTH = 1000; typedef struct __IntegerPair { int n1; int n2; } IntPair; typedef struct __InputDataStructure { IntPair boardSize; IntPair roachPosition; char journey[MAX_JOURNEY_LENGTH]; } InputData; InputData Input(); IntPair InputBoardSize(); IntPair InputStartRoachPosition(); void InputRoachJourney(PSTR journey); int main() { InputData inputData; inputData = Input(); // For Input() Testing.... printf ("Board Size value : %d, %d \n", inputData.boardSize.n1, inputData.boardSize.n2); printf ("Start Position value : %d, %d \n", inputData.roachPosition.n1, inputData.roachPosition.n2); printf ("Journey : %s \n", inputData.journey); ScheduledWalk(); Output(); return 0; } InputData Input() { InputData inputData; inputData.boardSize = InputBoardSize(); inputData.roachPosition = InputStartRoachPosition(); InputRoachJourney(inputData.journey); return inputData; } IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardRow, &boardCol); size.n1 = boardRow; size.n2 = boardCol; return size; } IntPair InputStartRoachPosition() { IntPair position; int startRow; int startCol; scanf("%d%d", &startRow, &startCol); position.n1 = startRow; position.n2 = startCol; return position; } void InputRoachJourney(PSTR journey) { scanf ("%s", journey); }
이로서 Input 부분을 일단 완성했습니다.
7. Version 0.5 - Implementation : ScheduledWalk ¶
다음 모듈 - ScheduledWalk() 관련. Depth First 에 입각하여. 그리고 이쯤에서 TestDrivenDevelopment 를 약간 가미해봅시다.
(관련 페이지 참조, 또는 TestFirstProgramming, UnitTest)
(관련 페이지 참조, 또는 TestFirstProgramming, UnitTest)
해당 함수 모듈이 완료되었을 것이라 가정하고 코드를 작성해봅니다. 여기서는 IsFinished() 에 일단 주목. (가장 깊은 단계인 IsJourneyEnd 와 IsAllBoardChecked 를 실행해주는 부분이므로)
~cpp BOOL IsFinished() { // 일종의 Test Code. 프로그램이 완료되었다고 했을때 제가 원하는 상황입니다. char journey = "111122222"; // 여정데이터를 '111122222' 를 받았다 가정하고 int currentPosition = 1; // 현재의 여정실행 위치는 두번째(0,1,..) 즉, '1' 입니다. 전체 사이즈는 9. assert (IsJourneyEnd(journey, currentPosition) == false); // 즉, 이 경우면 여정은 끝나지 않았음을 '단언' 합니다. // return IsJourneyEnd() || IsAllBoardChecked(); return true; } BOOL IsJourneyEnd() { // 아직 구현 안했습니다. return true; } BOOL IsAllBoardChecked() { // 아직 구현 안됨. return true; }
실행해보면, assert 부분에서 에러가 날 겁니다. 그러면서 assert 부분과 관련한 코드 라인을 표시해줍니다. 즉, 제가 원하는 상황을 가정하고 Test 코드를 만든뒤, 그 Test 를 통과할때까지 코드를 작성하면 되겠죠. 추후 뭔가가 작동이 이상하다라고 한다면,
- 일단 해당 문제일 모듈을 체크한다.
- Test Code 를 확인해본다.
- 실제 함수 모듈을 확인해본다.
코드를 작성합니다.
~cpp BOOL IsJourneyEnd(PSTR journey, int currentPosition) { return strlen(journey) <= (UINT)currentPosition; }
테스트를 점차 늘려갑니다.
~cpp BOOL IsFinished() { char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 1; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 9; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 10; assert (IsJourneyEnd(journey, currentPosition) == true); // return IsJourneyEnd() || IsAllBoardChecked(); return true; }
IsAllBoardChecked 에 대해서도 테스트를 넣어주고, 구현을 합니다.
~cpp BOOL IsFinished() { /* ---------------- IsJourney Test Case ---------------- char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 1; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 9; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 10; assert (IsJourneyEnd(journey, currentPosition) == true); ---------------- IsJourney Test Case ---------------- */ /* ---------------- IsAllBoardChecked Test Case ---------------- int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 1; } } assert (IsAllBoardChecked(board, 10, 10) == true); board[0] = 0; assert (IsAllBoardChecked(board, 10, 10) == false); ---------------- IsAllBoardChecked Test Case ---------------- */ char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 10; // for true condition int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 1; } } int maxRow = 10; int maxCol = 10; return IsJourneyEnd(journey, currentPosition) || IsAllBoardChecked(board, maxRow, maxCol); } BOOL IsJourneyEnd(PSTR journey, int currentPosition) { return strlen(journey) < (UINT)currentPosition; } BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { if (board[i*maxRow+j] <= 0) return false; } } return true; }
2시 34분중; 잠시 사정생김.
3시. 작업 재개.
MoveNext 에 대해서 재정의를 해봅시다.
~cpp void MoveNext() { GetMoveVector(); MoveRoach(); IncrementBoardBlockCount(); } void GetMoveVector() { } void MoveRoach() { } void IncrementBoardBlockCount() { }
Prototype 쪽 표현시 텝으로 깊이를 주어봤습니다. 소스 스타일에 대해서는 이해하기 좋은 스타일로 표현을.~
~cpp #include <stdio.h> #include <string.h> #include <assert.h> typedef int BOOL; typedef char* PSTR; typedef unsigned int UINT; const int MAX_JOURNEY_LENGTH = 1000; typedef struct __IntegerPair { int n1; int n2; } IntPair; typedef struct __InputDataStructure { IntPair boardSize; IntPair roachPosition; char journey[MAX_JOURNEY_LENGTH]; } InputData; InputData Input(); IntPair InputBoardSize(); IntPair InputStartRoachPosition(); void InputRoachJourney(PSTR journey); void ScheduledWalk(); BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol); BOOL IsJourneyEnd(PSTR journey, int currentPosition); BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol); void MoveNext(); void GetMoveVector(); void MoveRoach(); void IncrementBoardBlockCount(); void Output(); void OutputMoveCount(); void OutputBoardStatus(); . . .
이 이후부터 해당 함수 구현에 대한 프로세스는 다음과 같습니다.
1. 크거나 그 기능이 애매 또는 모호한 함수/모듈에 대해서 재정의 하기.
2. 해당 모듈이 완성되었다는 가정 하에 Test Case 를 생각해보기.
3. Test Case 작성.
4. 구현. Test Case 통과 여부 확인하기.
5. Test Case 를 늘려보기. (이 사이즈에 따라 구현의 난이도가 있습니다. 테스트와 다음 테스트 작성과의 시간이 길어질수록 어렵습니다. 그 만큼 생각을 추상적으로 한다는 뜻일 수 있으니까요.)
2. 해당 모듈이 완성되었다는 가정 하에 Test Case 를 생각해보기.
3. Test Case 작성.
4. 구현. Test Case 통과 여부 확인하기.
5. Test Case 를 늘려보기. (이 사이즈에 따라 구현의 난이도가 있습니다. 테스트와 다음 테스트 작성과의 시간이 길어질수록 어렵습니다. 그 만큼 생각을 추상적으로 한다는 뜻일 수 있으니까요.)
GetMoveVector 에 대해 구현합니다.
~cpp void MoveNext() { testGetMoveVector(); /* GetMoveVector(journey, currnetPosition); MoveRoach(); IncrementBoardBlockCount(); */ } IntPair GetMoveVector(char* journey, int currentPosition) { IntPair moveVector; // vector - row move vector, col move vector. int MOVE_VECTOR_PAIR_ROW[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; int MOVE_VECTOR_PAIR_COL[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; int moveVectorPairIndex = journey[currentPosition] - '0'; moveVector.n1 = MOVE_VECTOR_PAIR_ROW[moveVectorPairIndex]; moveVector.n2 = MOVE_VECTOR_PAIR_COL[moveVectorPairIndex]; return moveVector; } void testGetMoveVector() { char journey[MAX_JOURNEY_LENGTH] = "247"; IntPair nextMoveVector; nextMoveVector = GetMoveVector(journey, 0); assert (nextMoveVector.n1 == 0); assert (nextMoveVector.n2 == 1); nextMoveVector = GetMoveVector(journey, 1); assert (nextMoveVector.n1 == 1); assert (nextMoveVector.n2 == 0); nextMoveVector = GetMoveVector(journey, 2); assert (nextMoveVector.n1 == -1); assert (nextMoveVector.n2 == -1); }
MoveRoach 에 대한 Test Case 의 작성.
~cpp void MoveRoach() { } void testMoveRoach() { IntPair currentRoachPosition; IntPair moveVector; currentRoachPosition.n1 = 0; currentRoachPosition.n2 = 0; // case move type '2': moveVector.n1 = 0; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 1); // One More Time..~ moveVector.n1 = 0; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 2); }
Test Case 에 대해 만족하는 가장 간단한 MoveRoach 를 일단 구현해봅니다. 본래의 Requirement 의 경우 해당 판의 최대범위를 넘어가면
반대편으로 워프를 해야 하지만, 이에 대해서 아직 구현을 하지 않으면 되죠. 추후 이에 대한 Test Case를 작성하고 구현하면 됩니다.
반대편으로 워프를 해야 하지만, 이에 대해서 아직 구현을 하지 않으면 되죠. 추후 이에 대한 Test Case를 작성하고 구현하면 됩니다.
~cpp IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector) { IntPair updatedRoachPosition; updatedRoachPosition.n1 = currentRoachPosition.n1 + moveVector.n1; updatedRoachPosition.n2 = currentRoachPosition.n2 + moveVector.n2; return updatedRoachPosition; }그리고 해당 테스트를 만족하는지 실행해봅니다.
그러면 이제 아까 고려하지 않았던 사항인 판의 범위를 넘겼을 때에 대한 워프부분에 대해 Test Case 를 추가해봅니다.
~cpp void testMoveRoach() { . . . // Checking Boundary Warp. int maxCol = 10; int maxRow = 10; currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; moveVector.n1 = 1; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxCol, maxRow); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); }비슷한 방법으로 IncrementBoardBlockCount 를 구현합니다.
~cpp void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol) { assert (roachPosition.n1 < maxRow); assert (roachPosition.n2 < maxCol); board[roachPosition.n1*maxRow + roachPosition.n2]++; } void testIncrementBoardBlockCount() { int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 0; } } IntPair currentRoachPosition; currentRoachPosition.n1 = 1; currentRoachPosition.n2 = 1; IncrementBoardBlockCount(board, currentRoachPosition, 10, 10); assert (board[1*10+1] == 1); }
3시 52분부터 4시까지 휴식;
4시 5분. 재개~
4시 5분. 재개~
전체 MoveNext 에 대해서 Test Case를 작성합니다. 그러면서 필요한 인자들을 생각해내고, 채워갑니다. MoveNext 에서 필요한 인자들은 GetMoveVector 와 MoveRoach, IncrementBoardBlockCount 에서 필요한 인자들의 총 집합이 됩니다.
~cpp IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol) { testGetMoveVector(); testMoveRoach(); testIncrementBoardBlockCount(); IntPair updatedRoachPosition; /* 아직 구현 부분은 없습니다. */ return updatedRoachPosition; } void testMoveNext() { IntPair currentRoachPosition; char journey[] = "222"; int maxRow = 10; int maxCol = 10; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; int currentJourneyPosition = 0; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); assert (board[0*maxRow+0] == 1); }
MoveNext 부분 test case 를 pass 하기 위해 실제 구현을 합니다. 이미 구현해둔 GetMoveVector, MoveRoach, IncrementBoardBlockCount 들을 조합하는 일만 하면 됩니다.
~cpp IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol) { testGetMoveVector(); testMoveRoach(); testIncrementBoardBlockCount(); IntPair updatedRoachPosition; IntPair moveVector = GetMoveVector(journey, currentJourneyPosition); updatedRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxRow, maxCol); IncrementBoardBlockCount(board, updatedRoachPosition, maxRow, maxCol); return updatedRoachPosition; } void testMoveNext() { IntPair currentRoachPosition; char journey[] = "333"; int maxRow = 10; int maxCol = 10; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; int currentJourneyPosition = 0; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); assert (board[0*maxRow+0] == 1); currentJourneyPosition = 1; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 1); assert (currentRoachPosition.n2 == 1); assert (board[1*maxRow+1] == 1); currentJourneyPosition = 2; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 2); assert (currentRoachPosition.n2 == 2); assert (board[2*maxRow+2] == 1); }
대망의 ScheduledWalk (). 여기서 잠시 테스트에 따른 구현을 했는데도 에러가 나네요. 왜 그럴까?
{{{~cpp int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey) { testIsFinished(); testMoveNext(); int currentJourneyPosition = 0; IntPair currentRoachPosition = startRoachPosition; int totalMoveCount = 0; IncrementBoardBlockCount(board, currentRoachPosition, maxRow, maxCol); while (!IsFinished(journey, currentJourneyPosition, board, maxRow, maxCol)) { currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); totalMoveCount++; currentJourneyPosition++; } return totalMoveCount; } void testScheduledWalk() { char journey[MAX_JOURNEY_LENGTH] = "22222"; // 여정을 '22222' 를 받았다고 가정했습니다. int maxCol = 10; // 판 사이즈는 10, 10 int maxRow = 10; IntPair startRoachPosition; startRoachPosition.n1 = 0; // Roach 의 시작 포인트는 0,0 startRoachPosition.n2 = 0; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); // 전체 이동 기대수는 printf ("total move count : %d \n", totalMoveCount); assert (totalMoveCount == 5); // 5 가 나와야 합니다. 근데 여기까지 작성한 바로는 6이 나오죠. } 왜 그럴까요? 버그가 무엇인가를 먼저 파악해봐야 하겠죠. 1. ScheduledWalk 에서의 오류는 totalMoveCount 의 값이 다르다는 것이다. 2. totalMoveCount 의 값이 다르다는 것은 while 루프 조건이 틀리다는 뜻이다. 3. while 루프 조건이 틀리다는 뜻은 IsFinished() 가 올바르지 않았다라는 뜻이다. 4. IsFinished() 가 잘못되었다는 뜻은 IsJourneyEnd, IsAllBoardChecked 둘 중 하나 이상이 잘못되었다는 뜻이다. 하지만, 위의 모듈들은 Test Case를 다 만족을 시켜줬습니다. 그럼 Test Case 자체를 의심해봐야겠죠? {{{~cpp void testIsJourney() { char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 1; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 9; // <---- 전체 배열은 9개. 0번부터 시작하므로 8번까지여야 함. assert (IsJourneyEnd(journey, currentPosition) == false); // <--- 고로 이건 true! currentPosition = 10; assert (IsJourneyEnd(journey, currentPosition) == true); } }}} 그렇다면, 틀린 생각을 맞다라고 가정하고 만들어진 IsJourneyEnd 또한 틀린 함수가 되겠군요. 이를 수정하고, 해당 소스도 수정합니다. 그리고 계속 프로그램을 돌려봅니다. 그리고 Test Case를 추가합니다. {{{~cpp void testScheduledWalk() { char journey[MAX_JOURNEY_LENGTH] = "22222"; int maxCol = 10; int maxRow = 10; IntPair startRoachPosition; startRoachPosition.n1 = 0; startRoachPosition.n2 = 0; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); printf ("total move count : %d \n", totalMoveCount); assert (totalMoveCount == 5); assert (board[0*maxRow+0] == 1); assert (board[0*maxRow+1] == 1); assert (board[0*maxRow+2] == 1); assert (board[0*maxRow+3] == 1); assert (board[0*maxRow+4] == 1); assert (board[0*maxRow+5] == 1); } }}} === Version 0.6 - Implementation : Output & 전체적 === 여기까지 완료되었다면 ScheduledWalk 도 완료이군요. 그럼 Output 을 간단하게 구현합니다. 아직 Acceptance TestCase 를 거치지 않은 1차 완료 버전은 다음과 같습니다. {{{~cpp #include <stdio.h> #include <string.h> #include <assert.h> typedef int BOOL; typedef char* PSTR; typedef unsigned int UINT; const int MAX_JOURNEY_LENGTH = 1000; typedef struct __IntegerPair { int n1; // Row 와 관계된것들. int n2; // Col 와 관계된것들. } IntPair; typedef struct __InputDataStructure { IntPair boardSize; IntPair roachPosition; char journey[MAX_JOURNEY_LENGTH]; } InputData; InputData Input(); IntPair InputBoardSize(); IntPair InputStartRoachPosition(); void InputRoachJourney(PSTR journey); void testInput(); void InitializeArray(int* board, int maxRow, int maxCol); int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey); BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol); BOOL IsJourneyEnd(PSTR journey, int currentPosition); BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol); void testIsJourney(); void testIsAllBoardCheck(); IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol); IntPair GetMoveVector(char* journey, int currentPosition); IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol); void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol); void testGetMoveVector(); void testMoveRoach(); void testIncrementBoardBlockCount(); void testIsFinished(); void testMoveNext(); void testScheduledWalk(); void Output(int totalMoveCount, int* board, int maxRow, int maxCol); void OutputMoveCount(int totalMaxCount); void OutputBoardStatus(int* board, int maxRow, int maxCol); int main() { /* ------------- excute test code ------------- testInput(); testScheduledWalk(); ------------- excute test code ------------- */ InputData inputData = Input(); int maxRow = inputData.boardSize.n1; int maxCol = inputData.boardSize.n2; int* board = new int[maxRow * maxCol]; InitializeArray(board, maxRow, maxCol); IntPair startRoachPosition = inputData.roachPosition; char journey[MAX_JOURNEY_LENGTH]=""; strcpy(journey, inputData.journey); int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); Output(totalMoveCount, board, maxRow, maxCol); delete board; return 0; } void InitializeArray(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } } InputData Input() { InputData inputData; inputData.boardSize = InputBoardSize(); inputData.roachPosition = InputStartRoachPosition(); InputRoachJourney(inputData.journey); InputEndCode(); return inputData; } void testInput() { InputData inputData; inputData = Input(); // For Input() Testing.... printf ("Board Size value : %d, %d \n", inputData.boardSize.n1, inputData.boardSize.n2); printf ("Start Position value : %d, %d \n", inputData.roachPosition.n1, inputData.roachPosition.n2); printf ("Journey : %s \n", inputData.journey); } IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardRow, &boardCol); size.n1 = boardRow; size.n2 = boardCol; return size; } IntPair InputStartRoachPosition() { IntPair position; int startRow; int startCol; scanf("%d%d", &startRow, &startCol); position.n1 = startRow; position.n2 = startCol; return position; } void InputRoachJourney(PSTR journey) { scanf ("%s", journey); } void InputEndCode() { int endCode; scanf("%d", &endCode); } int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey) { testIsFinished(); testMoveNext(); int currentJourneyPosition = 0; IntPair currentRoachPosition = startRoachPosition; int totalMoveCount = 0; IncrementBoardBlockCount(board, currentRoachPosition, maxRow, maxCol); while (!IsFinished(journey, currentJourneyPosition, board, maxRow, maxCol)) { currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); totalMoveCount++; currentJourneyPosition++; } return totalMoveCount; } void testScheduledWalk() { char journey[MAX_JOURNEY_LENGTH] = "22222"; int maxCol = 10; int maxRow = 10; IntPair startRoachPosition; startRoachPosition.n1 = 0; startRoachPosition.n2 = 0; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); printf ("total move count : %d \n", totalMoveCount); assert (totalMoveCount == 5); assert (board[0*maxRow+0] == 1); assert (board[0*maxRow+1] == 1); assert (board[0*maxRow+2] == 1); assert (board[0*maxRow+3] == 1); assert (board[0*maxRow+4] == 1); assert (board[0*maxRow+5] == 1); } void testIsFinished() { // Test Data. char journey[MAX_JOURNEY_LENGTH] = "22"; int currentPosition = 0; int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 0; } } int maxRow = 10; int maxCol = 10; int roachPositionRow = 0; int roachPositionCol = 0; assert(IsFinished(journey, currentPosition, board, maxRow, maxCol) == false); } BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol) { testIsJourney(); testIsAllBoardCheck(); return IsJourneyEnd(journey, currentPosition) || IsAllBoardChecked(board, maxRow, maxCol); } BOOL IsJourneyEnd(PSTR journey, int currentPosition) { return strlen(journey) <= (UINT)currentPosition; } void testIsJourney() { char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 1; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 9; assert (IsJourneyEnd(journey, currentPosition) == true); currentPosition = 10; assert (IsJourneyEnd(journey, currentPosition) == true); } BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { if (board[i*maxRow+j] <= 0) return false; } } return true; } void testIsAllBoardCheck() { int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 1; } } assert (IsAllBoardChecked(board, 10, 10) == true); board[0] = 0; assert (IsAllBoardChecked(board, 10, 10) == false); } IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol) { testGetMoveVector(); testMoveRoach(); testIncrementBoardBlockCount(); IntPair updatedRoachPosition; IntPair moveVector = GetMoveVector(journey, currentJourneyPosition); updatedRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxRow, maxCol); IncrementBoardBlockCount(board, updatedRoachPosition, maxRow, maxCol); return updatedRoachPosition; } void testMoveNext() { IntPair currentRoachPosition; char journey[] = "333"; int maxRow = 10; int maxCol = 10; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[i*maxRow+j] = 0; } } currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; int currentJourneyPosition = 0; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); assert (board[0*maxRow+0] == 1); currentJourneyPosition = 1; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 1); assert (currentRoachPosition.n2 == 1); assert (board[1*maxRow+1] == 1); currentJourneyPosition = 2; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 2); assert (currentRoachPosition.n2 == 2); assert (board[2*maxRow+2] == 1); } IntPair GetMoveVector(char* journey, int currentJourneyPosition) { IntPair moveVector; // vector - row move vector, col move vector. int MOVE_VECTOR_PAIR_ROW[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; int MOVE_VECTOR_PAIR_COL[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; int moveVectorPairIndex = journey[currentJourneyPosition] - '0'; moveVector.n1 = MOVE_VECTOR_PAIR_ROW[moveVectorPairIndex]; moveVector.n2 = MOVE_VECTOR_PAIR_COL[moveVectorPairIndex]; return moveVector; } void testGetMoveVector() { char journey[MAX_JOURNEY_LENGTH] = "247"; IntPair nextMoveVector; nextMoveVector = GetMoveVector(journey, 0); assert (nextMoveVector.n1 == 0); assert (nextMoveVector.n2 == 1); nextMoveVector = GetMoveVector(journey, 1); assert (nextMoveVector.n1 == 1); assert (nextMoveVector.n2 == 0); nextMoveVector = GetMoveVector(journey, 2); assert (nextMoveVector.n1 == -1); assert (nextMoveVector.n2 == -1); } IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol) { IntPair updatedRoachPosition; updatedRoachPosition.n1 = (currentRoachPosition.n1 + moveVector.n1) % maxRow; updatedRoachPosition.n2 = (currentRoachPosition.n2 + moveVector.n2) % maxCol; return updatedRoachPosition; } void testMoveRoach() { IntPair currentRoachPosition; IntPair moveVector; currentRoachPosition.n1 = 0; currentRoachPosition.n2 = 0; // case move type '2': moveVector.n1 = 0; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, 10, 10); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 1); // One More Time..~ moveVector.n1 = 0; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, 10, 10); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 2); // Checking Boundary Warp. int maxCol = 10; int maxRow = 10; currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; moveVector.n1 = 1; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); } void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol) { assert (roachPosition.n1 < maxRow); assert (roachPosition.n2 < maxCol); board[roachPosition.n1*maxRow + roachPosition.n2]++; } void testIncrementBoardBlockCount() { int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 0; } } IntPair currentRoachPosition; currentRoachPosition.n1 = 1; currentRoachPosition.n2 = 1; IncrementBoardBlockCount(board, currentRoachPosition, 10, 10); assert (board[1*10+1] == 1); } void Output(int totalMoveCount, int* board, int maxRow, int maxCol) { OutputMoveCount(totalMoveCount); OutputBoardStatus(board, maxRow, maxCol); } void OutputMoveCount(int totalMaxCount) { printf ("%d\n", totalMaxCount); printf ("\n"); } void OutputBoardStatus(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { printf ("%d ", board[maxRow*i+j]); } printf ("\n"); } } }}} === Test & 버그 분석 === 자. 이제 슬슬 ["RandomWalk2/TestCase"] 에 있는 ["AcceptanceTest"] 의 경우가 되는 예들을 하나하나 실행해봅니다. {{{~cpp F:\WorkingTemp\ScheduledWalk\Debug>ScheduledWalk 5 5 0 0 22224444346 999 11 2 1 1 1 2 1 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 본래 기대값 : 2 1 1 1 1 1 0 0 0 2 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 }}} 오호라 버그이군요. 결과 자체에 촛점을 맞춰봅시다. 마지막 6에 대한 이동이 마치 1에 대한 이동처럼 되어버렸군요. 일단, 바로 의심되는 것으로는 6번에 대한 이동부분. 이동방향벡터를 결정해주는 루틴을 찾아보면 GetMoveVector 이므로 이부분이 첫번째 의심을 받겠군요. {{{~cpp IntPair GetMoveVector(char* journey, int currentJourneyPosition) { IntPair moveVector; // vector - row move vector, col move vector. int MOVE_VECTOR_PAIR_ROW[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; int MOVE_VECTOR_PAIR_COL[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; int moveVectorPairIndex = journey[currentJourneyPosition] - '0'; moveVector.n1 = MOVE_VECTOR_PAIR_ROW[moveVectorPairIndex]; moveVector.n2 = MOVE_VECTOR_PAIR_COL[moveVectorPairIndex]; return moveVector; } }}} 음.. Vector 자체로는 별 문제없어 보이네요. 그렇다면 다음은 실제 Roach를 이동시키는 Position 과 관련된 MoveRoach 부분을 살펴보죠. (여기서는 반드시 이동방향을 결정하는 함수와 실제 이동시키는 함수에 촛점을 맞춰야 합니다. board 배열의 값이 update 가 되기 위해선 어떠어떠한 값에 영향을 받는지를 먼저 머릿속에 그려야 겠죠.) 그림이 안 그려지는 경우에는 Debugger 와 Trace, break point 를 이용할 수 있습니다. 하지만, 구조화를 잘 시켜놓았을 경우 해당 문제발생시 버그 예상부분이 어느정도 그림이 그려집니다. {{{~cpp IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol) { IntPair updatedRoachPosition; updatedRoachPosition.n1 = (currentRoachPosition.n1 + moveVector.n1) % maxRow; updatedRoachPosition.n2 = (currentRoachPosition.n2 + moveVector.n2) % maxCol; return updatedRoachPosition; } }}} 이 부분에 대해서 퍽 하고 깨우침을 얻었는데; (아이디어가 떠오르지 않을때 이 부분이 잘못되었음을 알려면 Debugger 를 써야겠죠.) 바로 index가 -1 이 되었을 경우이죠. 그러므로 Modular 연산으로 계산할 수 없다. row 1, col 0 에서 row 0, col -1 을 더했을 경루를 생각한다면 row 1, col -1 입니다. -1 에 대해 modular 5를 한다면? 다름아닌 4가 나옵니다. 즉, 1, 4 가 되어버리죠. 일단 main ()을 test code 실행 모드로 바꾸고. {{{~cpp int main() { /* ------------- excute test code ------------- testInput(); testScheduledWalk(); ------------- excute test code ------------- */ /* InputData inputData = Input(); int maxRow = inputData.boardSize.n1; int maxCol = inputData.boardSize.n2; int* board = new int[maxRow * maxCol]; InitializeArray(board, maxRow, maxCol); IntPair startRoachPosition = inputData.roachPosition; char journey[MAX_JOURNEY_LENGTH]=""; strcpy(journey, inputData.journey); int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); Output(totalMoveCount, board, maxRow, maxCol); delete board; */ testScheduledWalk(); return 0; } }}} MoveRoach 코드를 일단은 가장 쉬운 코드로 고쳐봤습니다. {{{~cpp IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol) { IntPair updatedRoachPosition; updatedRoachPosition.n1 = (currentRoachPosition.n1 + moveVector.n1); updatedRoachPosition.n2 = (currentRoachPosition.n2 + moveVector.n2); if (updatedRoachPosition.n1 >= maxRow) updatedRoachPosition.n1 = 0; else if (updatedRoachPosition.n1 < 0) updatedRoachPosition.n1 = maxRow-1; if (updatedRoachPosition.n2 >= maxCol) updatedRoachPosition.n2 = 0; else if (updatedRoachPosition.n2 < 0) updatedRoachPosition.n2 = maxCol-1; return updatedRoachPosition; } }}} 일단 assert 문 걸어놓은 부분에 대해선 ok. {{{~cpp 5 5 0 0 22224444346 999 11 2 1 1 1 1 1 0 0 0 2 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 Press any key to continue }}} 일단 Test Case 하나에 대해선 ok. 계속 테스트를 해 나갑니다. ["RandomWalk2/TestCase"] 에 대해서도 ok. ["RandomWalk2/TestCase2"] 의 Test1,2,3 에 대해서 ok. 오. 그럼 더이상의 테스트가 의미가 없을까요? 여기에 복병이 있었으니.. Test4 에 대해서는 {{{~cpp 5 4 0 0 2224444666 999 10 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 1 1 1 1 }}} 그리고 잘못된 연산 오류. 원하는 기대값은 {{{~cpp 10 1 1 1 1 0 0 0 0 1 0 0 1 0 1 0 1 1 1 1 0 }}} ["RandomWalk2/TestCase"] 에서 멈췄다면 큰일날 뻔 했군요. 테스트는 자주 해줄수록 그 프로그램의 신용도를 높여줍니다. 일종의 Quality Assurance 라고 해야겠죠. 일단 아웃풋 만을 두고 본다면, 배열 자체의 행과 열의 크기가 뒤집혔군요. 그렇다면 그에 따른 에러 가능성 높음. 그렇다고 한다면, 배열에 값을 증가시키는 IncrementBoardBlockCount() 에 에러가능성이 높겠습니다. {{{~cpp void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol) { assert (roachPosition.n1 < maxRow); assert (roachPosition.n2 < maxCol); board[roachPosition.n1*maxRow + roachPosition.n2]++; // <--- maxRow 가 아닌 maxCol 이여야 한다. } }}} 음? 이런 계산이 이 프로그램 내에서 굉장히 많이 나오죠. 2차원 동적배열을 1차원 배열로 구현해줬기 때문에. 오호라.. (그 밖에 1차원 배열로 계산했었던 부분들을 찾기 위해 Search 에서 '*maxRow+' 로 검색해봤습니다. 13군데 나오더군요;;) 여기서 얻을 수 있는 교훈 - 이런 변환 부분은 차라리 함수로 만들자는 겁니다. -_-; 이 경우 OO Language 라면 1차원 배열을 이용한 2차원 배열 클래스를 만들어 쓰는 것이 가장 편합니다. 문제를 해당 배열 클래스 내로 지역화 시킬 수 있죠. 여기서는 일단 C로 만들었다고 가정하고 배제합니다. {{{~cpp int _2to1(int row, int col, int maxCol) { return maxCol*row + col; } }}} 중간에 ["NewTestsForOldBugs"] 을 읽음. === 최종 테스트들을 만족시키는 코드 === 최종 테스트 (["RandomWalk2/TestCase"], ["RandomWalk2/TestCase2"]) 를 만족시키는 코드. {{{~cpp #include <stdio.h> #include <string.h> #include <assert.h> typedef int BOOL; typedef char* PSTR; typedef unsigned int UINT; const int MAX_JOURNEY_LENGTH = 1000; typedef struct __IntegerPair { int n1; // Row 와 관계된것들. int n2; // Col 와 관계된것들. } IntPair; typedef struct __InputDataStructure { IntPair boardSize; IntPair roachPosition; char journey[MAX_JOURNEY_LENGTH]; } InputData; InputData Input(); IntPair InputBoardSize(); IntPair InputStartRoachPosition(); void InputRoachJourney(PSTR journey); void InputEndCode(); void testInput(); void InitializeArray(int* board, int maxRow, int maxCol); int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey); BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol); BOOL IsJourneyEnd(PSTR journey, int currentPosition); BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol); void testIsJourney(); void testIsAllBoardCheck(); IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol); IntPair GetMoveVector(char* journey, int currentPosition); IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol); void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol); void testGetMoveVector(); void testMoveRoach(); void testIncrementBoardBlockCount(); void testIsFinished(); void testMoveNext(); void testScheduledWalk(); void Output(int totalMoveCount, int* board, int maxRow, int maxCol); void OutputMoveCount(int totalMaxCount); void OutputBoardStatus(int* board, int maxRow, int maxCol); int _2to1(int row, int col, int maxCol) { return maxCol*row+col; } int main() { /* ------------- excute test code ------------- testInput(); testScheduledWalk(); ------------- excute test code ------------- */ InputData inputData = Input(); int maxRow = inputData.boardSize.n1; int maxCol = inputData.boardSize.n2; int* board = new int[maxRow * maxCol]; InitializeArray(board, maxRow, maxCol); IntPair startRoachPosition = inputData.roachPosition; char journey[MAX_JOURNEY_LENGTH]=""; strcpy(journey, inputData.journey); int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); Output(totalMoveCount, board, maxRow, maxCol); delete board; return 0; } void InitializeArray(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[_2to1(i,j,maxCol)] = 0; } } } InputData Input() { InputData inputData; inputData.boardSize = InputBoardSize(); inputData.roachPosition = InputStartRoachPosition(); InputRoachJourney(inputData.journey); InputEndCode(); return inputData; } void testInput() { InputData inputData; inputData = Input(); // For Input() Testing.... printf ("Board Size value : %d, %d \n", inputData.boardSize.n1, inputData.boardSize.n2); printf ("Start Position value : %d, %d \n", inputData.roachPosition.n1, inputData.roachPosition.n2); printf ("Journey : %s \n", inputData.journey); } IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardCol, &boardRow); size.n1 = boardRow; size.n2 = boardCol; return size; } IntPair InputStartRoachPosition() { IntPair position; int startRow; int startCol; scanf("%d%d", &startRow, &startCol); position.n1 = startRow; position.n2 = startCol; return position; } void InputRoachJourney(PSTR journey) { scanf ("%s", journey); } void InputEndCode() { int endCode; scanf("%d", &endCode); } int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey) { testIsFinished(); testMoveNext(); int currentJourneyPosition = 0; IntPair currentRoachPosition = startRoachPosition; int totalMoveCount = 0; IncrementBoardBlockCount(board, currentRoachPosition, maxRow, maxCol); while (!IsFinished(journey, currentJourneyPosition, board, maxRow, maxCol)) { currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); totalMoveCount++; currentJourneyPosition++; } return totalMoveCount; } void testScheduledWalk() { char journey[MAX_JOURNEY_LENGTH] = "22222"; int maxCol = 10; int maxRow = 10; IntPair startRoachPosition; startRoachPosition.n1 = 0; startRoachPosition.n2 = 0; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[_2to1(i,j,maxCol)] = 0; } } int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); printf ("total move count : %d \n", totalMoveCount); assert (totalMoveCount == 5); assert (board[_2to1(0,0,maxCol)] == 1); assert (board[_2to1(0,1,maxCol)] == 1); assert (board[_2to1(0,2,maxCol)] == 1); assert (board[_2to1(0,3,maxCol)] == 1); assert (board[_2to1(0,4,maxCol)] == 1); assert (board[_2to1(0,5,maxCol)] == 1); } void testIsFinished() { // Test Data. char journey[MAX_JOURNEY_LENGTH] = "22"; int currentPosition = 0; int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 0; } } int maxRow = 10; int maxCol = 10; int roachPositionRow = 0; int roachPositionCol = 0; assert(IsFinished(journey, currentPosition, board, maxRow, maxCol) == false); } BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol) { testIsJourney(); testIsAllBoardCheck(); return IsJourneyEnd(journey, currentPosition) || IsAllBoardChecked(board, maxRow, maxCol); } BOOL IsJourneyEnd(PSTR journey, int currentPosition) { return strlen(journey) <= (UINT)currentPosition; } void testIsJourney() { char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 1; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 9; assert (IsJourneyEnd(journey, currentPosition) == true); currentPosition = 10; assert (IsJourneyEnd(journey, currentPosition) == true); } BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { if (board[_2to1(i,j,maxCol)] <= 0) return false; } } return true; } void testIsAllBoardCheck() { int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 1; } } assert (IsAllBoardChecked(board, 10, 10) == true); board[0] = 0; assert (IsAllBoardChecked(board, 10, 10) == false); } IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol) { testGetMoveVector(); testMoveRoach(); testIncrementBoardBlockCount(); IntPair updatedRoachPosition; IntPair moveVector = GetMoveVector(journey, currentJourneyPosition); updatedRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxRow, maxCol); IncrementBoardBlockCount(board, updatedRoachPosition, maxRow, maxCol); return updatedRoachPosition; } void testMoveNext() { IntPair currentRoachPosition; char journey[] = "333"; int maxRow = 10; int maxCol = 10; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[_2to1(i,j,maxCol)] = 0; } } currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; int currentJourneyPosition = 0; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); assert (board[_2to1(0,0,maxCol)] == 1); currentJourneyPosition = 1; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 1); assert (currentRoachPosition.n2 == 1); assert (board[_2to1(1,1,maxCol)] == 1); currentJourneyPosition = 2; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 2); assert (currentRoachPosition.n2 == 2); assert (board[_2to1(2,2,maxCol)] == 1); } IntPair GetMoveVector(char* journey, int currentJourneyPosition) { IntPair moveVector; // vector - row move vector, col move vector. int MOVE_VECTOR_PAIR_ROW[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; int MOVE_VECTOR_PAIR_COL[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; int moveVectorPairIndex = journey[currentJourneyPosition] - '0'; moveVector.n1 = MOVE_VECTOR_PAIR_ROW[moveVectorPairIndex]; moveVector.n2 = MOVE_VECTOR_PAIR_COL[moveVectorPairIndex]; return moveVector; } void testGetMoveVector() { char journey[MAX_JOURNEY_LENGTH] = "247"; IntPair nextMoveVector; nextMoveVector = GetMoveVector(journey, 0); assert (nextMoveVector.n1 == 0); assert (nextMoveVector.n2 == 1); nextMoveVector = GetMoveVector(journey, 1); assert (nextMoveVector.n1 == 1); assert (nextMoveVector.n2 == 0); nextMoveVector = GetMoveVector(journey, 2); assert (nextMoveVector.n1 == -1); assert (nextMoveVector.n2 == -1); } IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol) { IntPair updatedRoachPosition; updatedRoachPosition.n1 = (currentRoachPosition.n1 + moveVector.n1); updatedRoachPosition.n2 = (currentRoachPosition.n2 + moveVector.n2); if (updatedRoachPosition.n1 >= maxRow) updatedRoachPosition.n1 = 0; else if (updatedRoachPosition.n1 < 0) updatedRoachPosition.n1 = maxRow-1; if (updatedRoachPosition.n2 >= maxCol) updatedRoachPosition.n2 = 0; else if (updatedRoachPosition.n2 < 0) updatedRoachPosition.n2 = maxCol-1; return updatedRoachPosition; } void testMoveRoach() { IntPair currentRoachPosition; IntPair moveVector; currentRoachPosition.n1 = 0; currentRoachPosition.n2 = 0; // case move type '2': moveVector.n1 = 0; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, 10, 10); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 1); // One More Time..~ moveVector.n1 = 0; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, 10, 10); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 2); // Checking Boundary Warp. int maxCol = 10; int maxRow = 10; currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; moveVector.n1 = 1; moveVector.n2 = 1; currentRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); } void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol) { assert (roachPosition.n1 < maxRow); assert (roachPosition.n2 < maxCol); board[roachPosition.n1*maxCol + roachPosition.n2]++; } void testIncrementBoardBlockCount() { int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 0; } } IntPair currentRoachPosition; currentRoachPosition.n1 = 1; currentRoachPosition.n2 = 1; IncrementBoardBlockCount(board, currentRoachPosition, 10, 10); assert (board[1*10+1] == 1); } void Output(int totalMoveCount, int* board, int maxRow, int maxCol) { OutputMoveCount(totalMoveCount); OutputBoardStatus(board, maxRow, maxCol); } void OutputMoveCount(int totalMaxCount) { printf ("%d\n", totalMaxCount); printf ("\n"); } void OutputBoardStatus(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { printf ("%d ", board[maxCol*i+j]); } printf ("\n"); } } }}} 여기서 약간 더 나가서. 현재 테스트 코드와 메인 코드가 섞여있어서 상당히 소스가 복잡해보입니다. 그리고 AcceptanceTest 에 대해서는 자동화되지 않았습니다. === 마무리 소스 === ==== main.cpp ==== {{{~cpp #include "ScheduledWalkTestCase.h" #include "ScheduledWalk.h" int main() { /* ------------- Acceptance Test ------------- AcceptanceTestAll (); ------------- Acceptance Test ------------- */ AcceptanceTestAll (); // <--- For Acceptance Test UnitTestAll(); // ScheduledWalkMain(); // <--- Main Routine return 0; } void ScheduledWalkMain() { InputData inputData; IntPair startRoachPosition; int maxRow; int maxCol; int* board; char journey[MAX_JOURNEY_LENGTH]=""; int totalMoveCount = 0; inputData = Input(); maxRow = inputData.boardSize.n1; maxCol = inputData.boardSize.n2; board = CreateBoard(maxRow, maxCol); startRoachPosition = inputData.roachPosition; strcpy(journey, inputData.journey); totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); Output(totalMoveCount, board, maxRow, maxCol); DestroyBoard(board); } }}} ==== ScheduledWalk.h ==== {{{~cpp #ifndef _SCHEDULEDWALK_H_ #define _SCHEDULEDWALK_H_ #include <stdio.h> #include <string.h> #include <assert.h> typedef int BOOL; typedef char* PSTR; typedef unsigned int UINT; const int MAX_JOURNEY_LENGTH = 1000; typedef struct __IntegerPair { int n1; // Row 와 관계된것들. int n2; // Col 와 관계된것들. } IntPair; typedef struct __InputDataStructure { IntPair boardSize; IntPair roachPosition; char journey[MAX_JOURNEY_LENGTH]; } InputData; InputData Input(); IntPair InputBoardSize(); IntPair InputStartRoachPosition(); void InputRoachJourney(PSTR journey); void InputEndCode(); void InitializeArray(int* board, int maxRow, int maxCol); int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey); BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol); BOOL IsJourneyEnd(PSTR journey, int currentPosition); BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol); IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol); IntPair GetMoveVector(char* journey, int currentPosition); IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol); void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol); void Output(int totalMoveCount, int* board, int maxRow, int maxCol); void OutputMoveCount(int totalMaxCount); void OutputBoardStatus(int* board, int maxRow, int maxCol); int _2to1(int row, int col, int maxCol); int* CreateBoard(int maxRow, int maxCol); void DestroyBoard(int* board); #endif }}} ==== ScheduledWalk.cpp ==== {{{~cpp #include "ScheduledWalk.h" int _2to1(int row, int col, int maxCol) { return maxCol*row+col; } int* CreateBoard(int maxRow, int maxCol) { int* board = new int[maxRow * maxCol]; InitializeArray(board, maxRow, maxCol); return board; } void DestroyBoard(int* board) { delete board; } void InitializeArray(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[_2to1(i,j,maxCol)] = 0; } } } InputData Input() { InputData inputData; inputData.boardSize = InputBoardSize(); inputData.roachPosition = InputStartRoachPosition(); InputRoachJourney(inputData.journey); InputEndCode(); return inputData; } IntPair InputBoardSize() { IntPair size; int boardRow; int boardCol; scanf("%d%d", &boardCol, &boardRow); size.n1 = boardRow; size.n2 = boardCol; return size; } IntPair InputStartRoachPosition() { IntPair position; int startRow; int startCol; scanf("%d%d", &startRow, &startCol); position.n1 = startRow; position.n2 = startCol; return position; } void InputRoachJourney(PSTR journey) { scanf ("%s", journey); } void InputEndCode() { int endCode; scanf("%d", &endCode); } int ScheduledWalk(int* board, int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey) { int currentJourneyPosition = 0; IntPair currentRoachPosition = startRoachPosition; int totalMoveCount = 0; IncrementBoardBlockCount(board, currentRoachPosition, maxRow, maxCol); while (!IsFinished(journey, currentJourneyPosition, board, maxRow, maxCol)) { currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); totalMoveCount++; currentJourneyPosition++; } return totalMoveCount; } BOOL IsFinished(PSTR journey, int currentPosition, int* board, int maxRow, int maxCol) { return IsJourneyEnd(journey, currentPosition) || IsAllBoardChecked(board, maxRow, maxCol); } BOOL IsJourneyEnd(PSTR journey, int currentPosition) { return strlen(journey) <= (UINT)currentPosition; } BOOL IsAllBoardChecked(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { if (board[_2to1(i,j,maxCol)] <= 0) return false; } } return true; } IntPair MoveNext(IntPair currentRoachPosition, PSTR journey, int currentJourneyPosition, int* board, int maxRow, int maxCol) { IntPair updatedRoachPosition; IntPair moveVector = GetMoveVector(journey, currentJourneyPosition); updatedRoachPosition = MoveRoach(currentRoachPosition, moveVector, maxRow, maxCol); IncrementBoardBlockCount(board, updatedRoachPosition, maxRow, maxCol); return updatedRoachPosition; } IntPair GetMoveVector(char* journey, int currentJourneyPosition) { IntPair moveVector; // vector - row move vector, col move vector. int MOVE_VECTOR_PAIR_ROW[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; int MOVE_VECTOR_PAIR_COL[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; int moveVectorPairIndex = journey[currentJourneyPosition] - '0'; moveVector.n1 = MOVE_VECTOR_PAIR_ROW[moveVectorPairIndex]; moveVector.n2 = MOVE_VECTOR_PAIR_COL[moveVectorPairIndex]; return moveVector; } IntPair MoveRoach(IntPair currentRoachPosition, IntPair moveVector, int maxRow, int maxCol) { IntPair updatedRoachPosition; updatedRoachPosition.n1 = (currentRoachPosition.n1 + moveVector.n1); updatedRoachPosition.n2 = (currentRoachPosition.n2 + moveVector.n2); if (updatedRoachPosition.n1 >= maxRow) updatedRoachPosition.n1 = 0; else if (updatedRoachPosition.n1 < 0) updatedRoachPosition.n1 = maxRow-1; if (updatedRoachPosition.n2 >= maxCol) updatedRoachPosition.n2 = 0; else if (updatedRoachPosition.n2 < 0) updatedRoachPosition.n2 = maxCol-1; return updatedRoachPosition; } void IncrementBoardBlockCount(int* board, IntPair roachPosition, int maxRow, int maxCol) { assert (roachPosition.n1 < maxRow); assert (roachPosition.n2 < maxCol); board[roachPosition.n1*maxCol + roachPosition.n2]++; } void Output(int totalMoveCount, int* board, int maxRow, int maxCol) { OutputMoveCount(totalMoveCount); OutputBoardStatus(board, maxRow, maxCol); } void OutputMoveCount(int totalMaxCount) { printf ("%d\n", totalMaxCount); printf ("\n"); } void OutputBoardStatus(int* board, int maxRow, int maxCol) { for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { printf ("%d ", board[maxCol*i+j]); } printf ("\n"); } } }}} ==== ScheduledWalkTestCase.h ==== {{{~cpp #include <assert.h> #include <stdio.h> #include "ScheduledWalk.h" void testScheduledWalk1_1(); void testScheduledWalk1_2(); void testScheduledWalk1_3(); void testScheduledWalk1_4(); void testScheduledWalk2_1(); void testScheduledWalk2_2(); void testScheduledWalk2_3(); void testScheduledWalk2_4(); void testInput(); void testIsFinished(); void testIsJourney(); void testIsAllBoardCheck(); void testMoveNext(); void testGetMoveVector(); void testMoveRoach(); void testIncrementBoardBlockCount(); void testScheduledWalk(); void AcceptanceTestAll(); void UnitTestAll(); void testScheduledWalking(int maxRow, int maxCol, IntPair startRoachPosition, PSTR journey, int expectedTotalMoveCount, int* expectedBoardArray); void excuteTest (void (*func)(void), PSTR message); }}} ==== ScheduledWalkTestCase.cpp ==== {{{~cpp #include "ScheduledWalkTestCase.h" void testInput() { InputData inputData; printf ("Input data ... :"); inputData = Input(); // For Input() Testing.... printf ("Board Size value : %d, %d \n", inputData.boardSize.n1, inputData.boardSize.n2); printf ("Start Position value : %d, %d \n", inputData.roachPosition.n1, inputData.roachPosition.n2); printf ("Journey : %s \n", inputData.journey); } void testScheduledWalk() { char journey[MAX_JOURNEY_LENGTH] = "22222"; int maxCol = 10; int maxRow = 10; IntPair startRoachPosition; startRoachPosition.n1 = 0; startRoachPosition.n2 = 0; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[_2to1(i,j,maxCol)] = 0; } } int totalMoveCount = ScheduledWalk(board, maxRow, maxCol, startRoachPosition, journey); assert (totalMoveCount == 5); assert (board[_2to1(0,0,maxCol)] == 1); assert (board[_2to1(0,1,maxCol)] == 1); assert (board[_2to1(0,2,maxCol)] == 1); assert (board[_2to1(0,3,maxCol)] == 1); assert (board[_2to1(0,4,maxCol)] == 1); assert (board[_2to1(0,5,maxCol)] == 1); } void testIsFinished() { // Test Data. char journey[MAX_JOURNEY_LENGTH] = "22"; int currentPosition = 0; int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 0; } } int maxRow = 10; int maxCol = 10; int roachPositionRow = 0; int roachPositionCol = 0; assert(IsFinished(journey, currentPosition, board, maxRow, maxCol) == false); } void testIsJourney() { char journey[MAX_JOURNEY_LENGTH] = "111122222"; int currentPosition = 1; assert (IsJourneyEnd(journey, currentPosition) == false); currentPosition = 9; assert (IsJourneyEnd(journey, currentPosition) == true); currentPosition = 10; assert (IsJourneyEnd(journey, currentPosition) == true); } void testIsAllBoardCheck() { int board[10*10]; for (int i=0;i<10;i++) { for (int j=0;j<10;j++) { board[i*10+j] = 1; } } assert (IsAllBoardChecked(board, 10, 10) == true); board[0] = 0; assert (IsAllBoardChecked(board, 10, 10) == false); } void testMoveNext() { IntPair currentRoachPosition; char journey[] = "333"; int maxRow = 10; int maxCol = 10; int board[10*10]; for (int i=0;i<maxRow;i++) { for (int j=0;j<maxCol;j++) { board[_2to1(i,j,maxCol)] = 0; } } currentRoachPosition.n1 = 9; currentRoachPosition.n2 = 9; int currentJourneyPosition = 0; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 0); assert (currentRoachPosition.n2 == 0); assert (board[_2to1(0,0,maxCol)] == 1); currentJourneyPosition = 1; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 1); assert (currentRoachPosition.n2 == 1); assert (board[_2to1(1,1,maxCol)] == 1); currentJourneyPosition = 2; currentRoachPosition = MoveNext (currentRoachPosition, journey, currentJourneyPosition, board, maxRow, maxCol); assert (currentRoachPosition.n1 == 2); assert (currentRoachPosition.n2 == 2); assert (board[_2to1(2,2,maxCol)] == 1); } void testGetMoveVector() { char journey[MAX_JOURNEY_LENGTH] = "247"; IntPair nextMoveVector; nextMoveVector = GetMoveVector(journey, 0); assert (nextM