Sablog Models/자작자작
환타 오목 게임 재구성: 최종본.
어리
2009. 11. 12. 13:24
지환태 님의 오목 게임 소스를 처음 접한 것은 올해 중순이었을 겁니다.
오목을 만들어 보겠다는 생각 자체를 하지 않았기 때문에 당연히 소스에 관심이 갔고,
소스 자체가 그다지 깔끔하지 못해서 리팩토링(refactoring)을 해 보고 싶었습니다.
(환타[지환태] 님께서도 C언어를 배운지 얼마 안 되었을 때 만들었다고 고백하셨습니다.)
처음엔 허락도 받지 않고 시작한 재구성인데 환타 님께서 관심을 가져 주셨으며,
다섯 번에 걸친 재구성(R1, R2, R3, R4, R5)과 추가 수정으로, 나름 깔끔한 코드를 만들어 봤습니다.
아래가 드디어 최종본입니다.
제가 만든 코드는 하나의 메인 C 파일과 두 헤더 H 파일로 이루어져 있습니다.
지난번 재구성에 비해 소스와 파일명이 아주 약간 달라졌습니다.
그러나 다행히도 포스팅할 것은 아직 많이 남아 있다죠.
오목을 만들어 보겠다는 생각 자체를 하지 않았기 때문에 당연히 소스에 관심이 갔고,
소스 자체가 그다지 깔끔하지 못해서 리팩토링(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
/* five_in-tool.h (for five_in_a_row.h) * supports gotoxy(x, y) and getch() */ #include <stdio.h> #include <windows.h> void gotoxy(int x, int y) { COORD XY = {x, y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), XY); } #ifndef GETCH // getch() support start #if defined(_MSC_VER) && (1000 < _MSC_VER < 1500) _CRTIMP _getch(); #define getch() _getch() #elif defined(__GNUC__) || defined(__GNUG__) #include <TERMIOS.H> int getch() { char ch; struct termios buffer, status; tcgetattr( STDIN_FILENO, &buffer ); status = buffer; status.c_lflag &= ~(ECHO | ICANON); tcsetattr( STDIN_FILENO, TCSANOW, &status ); read( 0, &ch, 1 ); tcsetattr( STDIN_FILENO, TCSANOW, &buffer ); return ch; } #else #include <conio.h> #endif #endif // getch() support end
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
그러나 다행히도 포스팅할 것은 아직 많이 남아 있다죠.