오목을 만들어 보겠다는 생각 자체를 하지 않았기 때문에 당연히 소스에 관심이 갔고,
소스 자체가 그다지 깔끔하지 못해서 리팩토링(refactoring)을 해 보고 싶었습니다.
(환타[지환태] 님께서도 C언어를 배운지 얼마 안 되었을 때 만들었다고 고백하셨습니다.)
처음엔 허락도 받지 않고 시작한 재구성인데 환타 님께서 관심을 가져 주셨으며,
다섯 번에 걸친 재구성(R1, R2, R3, R4, R5)과 추가 수정으로, 나름 깔끔한 코드를 만들어 봤습니다.
아래가 드디어 최종본입니다.
제가 만든 코드는 하나의 메인 C 파일과 두 헤더 H 파일로 이루어져 있습니다.
지난번 재구성에 비해 소스와 파일명이 아주 약간 달라졌습니다.
#include "five_in_a_row.h"
int main()
{
while (!five_in_a_row())
{
printf("계속하려면 아무 키나 누르십시오(종료 Esc):");
if (getch() == ESC)
break;
// If the user wants to re-match, 0 is returned; or not, 1 is returned.
}
return 0;
}
/* five_in_a_row.h
* by ZFanta & UNique
*/
#ifndef FIVE_IN_A_ROW
#define FIVE_IN_A_ROW
#include "five_in-tool.h"
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define ENTER 13
#define ESC 27
#define BOARD_SIZE 19
int x = 0, y = 0;
int oldx = 0, oldy = 0;
int board[BOARD_SIZE][BOARD_SIZE];
int turn = 1;
char who[3][3] = {"", "흑", "백"};
char stone[3][3] = {"", "○", "●"};
int count(int x, int y, int turn, int direction)
{
int n = 0;
switch(direction)
{
case 0: // 상
while(y > 0 && board[x][--y] == turn)
n++;
break;
case 1: // 우상
while(x < BOARD_SIZE && y > 0 && board[++x][--y] == turn)
n++;
break;
case 2: // 우
while(x < BOARD_SIZE && board[++x][y] == turn)
n++;
break;
case 3: // 우하
while(x < BOARD_SIZE && y < BOARD_SIZE && board[++x][++y] == turn)
n++;
break;
case 4: // 하
while(y < BOARD_SIZE && board[x][++y] == turn)
n++;
break;
case 5: // 좌하
while(x > 0 && y < BOARD_SIZE && board[--x][++y] == turn)
n++;
break;
case 6: // 좌
while(x > 0 && board[--x][y] == turn)
n++;
break;
case 7: // 좌상
while(x > 0 && y > 0 && board[--x][--y] == turn)
n++;
break;
default:
n = 0;
break;
}
return n;
}
int check(int x, int y)
{
int turn = board[x][y];
if (count(x, y, turn, 0) + count(x, y, turn, 4) > 3 ||
count(x, y, turn, 1) + count(x, y, turn, 5) > 3 ||
count(x, y, turn, 2) + count(x, y, turn, 6) > 3 ||
count(x, y, turn, 3) + count(x, y, turn, 7) > 3 )
return 1;
else
return 0;
}
int knock(int x, int y)
{
if(board[x][y] != 0)
{
gotoxy(x * 2, y);
puts(stone[board[x][y]]);
return 0;
}
else
return 1;
}
void load(int x, int y)
{
gotoxy(x * 2, y);
puts("⊙");
}
void board_write(int x, int y)
{
x *= 2;
gotoxy(x, y);
if (x == 0)
{
if (y == 0)
puts("┌");
else if (y == (BOARD_SIZE - 1))
puts("└");
else
puts("├");
}
else if (x == (BOARD_SIZE - 1) * 2)
{
if (y == 0)
puts("┐");
else if (y == (BOARD_SIZE - 1))
puts("┘");
else
puts("┤");
}
else
{
if (y == 0)
puts("┬");
else if (y == (BOARD_SIZE - 1))
puts("┴");
else
puts("┼");
}
}
void draw()
{
int i, j;
for (i = 0; i < BOARD_SIZE; i++)
for (j = 0; j < BOARD_SIZE; j++)
board_write(i, j);
}
int move()
{
char input = 0;
input = getch();
if(input != ENTER)
{
oldx = x;
oldy = y;
if(input == UP && y > 0)
y--;
else if(input == DOWN && y < BOARD_SIZE - 1)
y++;
else if(input == LEFT && x > 0)
x--;
else if(input == RIGHT && x < BOARD_SIZE - 1)
x++;
if(knock(oldx, oldy))
board_write(oldx, oldy);
load(x, y);
}
else if(board[x][y] == 0)
{
board[x][y] = turn;
gotoxy(x * 2, y);
puts(stone[turn]);
if(check(x, y))
return 0;
turn ^= 3;
}
return 1;
}
int five_in_a_row()
{
int i, j;
system("CLS"); // Clear and start new game.
draw();
for (i = 0; i < BOARD_SIZE; i++)
for (j = 0; j < BOARD_SIZE; j++)
board[i][j] = 0;
load(x, y);
while (move());
system("CLS");
printf("%s 승리.\n", who[turn]); // Mark who won
return 0; // If one game successfully ended, return 0.
}
#endif
A infinite number of monkeys typing into GNU emacs would never make a good program.
— Linus Benedict Torvalds(1969-12-28 ~), Linux 1.3.53 CodingStyle documentation