| [ QuizWit ] in KIDS 글 쓴 이(By): parsec ( 먼 소 류 ) 날 짜 (Date): 2003년 3월 14일 금요일 오후 10시 15분 19초 제 목(Title): 장서가 프로그램 정리+업글 P.S. : find_dabb routine 수정 (옛날에 썼던 curses는 다시 보니 마우스 입력 처리하는 루틴이 없었던 것 같고 ncurses를 써야 마우스로 컨트롤을 할 수 있을 것 같은데 이건 튜토리얼부터 구해 봐야겠군요^^) ---- 사람이 있는 쪽에서 여러개의 책장을 밀 수 있게 고쳤습니다. 모든 기능을 테스트해본 것은 아니므로 스펙에 어긋나는 점이 있을지도 모르겠습니다. outsider님의 원래 스펙과 어긋나는 점이 있으면 지적해 주세요. ^^ -------------------------- study.c --------------------------- /*---------------------------------------------------------------- study.c Simulation of the problem of a study which is full of sliding bookcases except some space for moving around. This problem was first raised by "outsider" of "Kids" BBS(kids.kornet.net) in tribute to "dabb" of the same BBS. ref) /boardlist.html?Article=QuizWit&Num=7691 ----------------------------------------------------------------*/ #include <stdio.h> #include <unistd.h> #define ROOM_HEIGHT 4 #define ROOM_WIDTH 4 #define IMG_HEIGHT (ROOM_HEIGHT*3+2) #define IMG_WIDTH (ROOM_WIDTH*6+4) #define NONE 0 #define NORTH 1 #define SOUTH 2 #define EAST 3 #define WEST 4 #define FIX 0 #define VER 1 #define HOR 2 #define ANY 3 typedef struct bookcase { int id; int face; int dir; int x; int y; struct bookcase *next; } t_bookcase; int room[ROOM_HEIGHT][ROOM_WIDTH]; int path[ROOM_HEIGHT][ROOM_WIDTH]; int case_count=0; void draw_case(t_bookcase *bc); void move_case(int pos_x, int pos_y, int dest_x, int dest_y); int get_caseid(int pos_x, int pos_y); t_bookcase* get_casep(int cid); void set_case(int pos_x, int pos_y, int face, int dir); void set_dabb(int pos_x, int pos_y); t_bookcase* find_dabb(void); void reset_case(int caseid); void draw_study(void); void draw_door(void); void set_door(int pos); void init_study(void); void init_img(void); void draw_prompt(void); int get_command(void); int isconnected(int pos_x, int pos_y, int dest_x, int dest_y); int four_search(int pos_x, int pos_y, int dest_x, int dest_y); int ispushable(int pos_x, int pos_y, int delta); char cmdbuf[80]; int cmdbufidx; unsigned char cmd; int pos; int dest; int face; int dir; int door_pos; unsigned char img_buf[IMG_HEIGHT][IMG_WIDTH+1]; t_bookcase *head = NULL; t_bookcase *curr = NULL; void init_study(void) { int i; for(i=0; i<ROOM_HEIGHT*ROOM_WIDTH; i++) room[i/ROOM_WIDTH][i%ROOM_WIDTH] = 0; } void init_img(void) { int i; for(i=0; i<IMG_HEIGHT*IMG_WIDTH; i++) img_buf[i/IMG_WIDTH][i%IMG_WIDTH] = ' '; strncpy(&img_buf[0][0],"┌",2); strncpy(&img_buf[0][IMG_WIDTH-2],"┐",2); strncpy(&img_buf[IMG_HEIGHT-1][0],"└",2); strncpy(&img_buf[IMG_HEIGHT-1][IMG_WIDTH-2],"┘",2); for(i=1;i<IMG_HEIGHT-1; i++) { strncpy(&img_buf[i][0],"│",2); strncpy(&img_buf[i][IMG_WIDTH-2],"│",2); img_buf[i][IMG_WIDTH] = '\0'; } for(i=2;i<IMG_WIDTH-2; i+=2) { strncpy(&img_buf[0][i],"─",2); strncpy(&img_buf[IMG_HEIGHT-1][i],"─",2); } } int get_caseid(int pos_x, int pos_y) { return room[pos_x-1][pos_y-1]; } t_bookcase* get_casep(int caseid) { if (head == NULL) return NULL; curr = head; while(curr->next != NULL && curr->id != caseid) curr = curr->next; return curr; } void set_case(int pos_x, int pos_y, int face, int dir) { if(pos_x<1 || pos_x>ROOM_WIDTH || pos_y<1 || pos_y>ROOM_HEIGHT) return; if(case_count < ROOM_HEIGHT*ROOM_WIDTH && room[pos_x-1][pos_y-1] == 0) { case_count++; curr = head; if(curr != NULL) { while(curr->next != NULL) curr = curr->next; curr->next = (t_bookcase *)malloc(sizeof(t_bookcase)); curr = curr->next; } else { curr = (t_bookcase *)malloc(sizeof(t_bookcase)); head = curr; } curr->id = case_count; room[pos_x-1][pos_y-1] = curr->id; curr->face = face; curr->dir = dir; curr->x = pos_x; curr->y = pos_y; curr->next=NULL; } } void set_dabb(int pos_x, int pos_y) { set_case(pos_x, pos_y, NONE, ANY); } t_bookcase * find_dabb(void) { if(head == NULL) return NULL; else { curr = head; do { if(curr->face == NONE && curr->dir == ANY) return curr; curr = curr->next; } while(curr != NULL); return NULL; } } void set_door(int pos) { if (pos<1) pos = 1; if (pos>ROOM_WIDTH) pos = ROOM_WIDTH; door_pos = pos-1; } void reset_case(int caseid) { t_bookcase *temp; if (head == NULL) return; curr = head; if(head->id == caseid) { head = curr->next; room[curr->x-1][curr->y-1]=0; free(curr); case_count --; curr = head; } else { while(curr->next != NULL && curr->next->id != caseid) curr = curr->next; if(curr->next == NULL) return; temp = curr->next; curr->next = temp->next; curr = curr->next; room[temp->x-1][temp->y-1] = 0; free(temp); case_count --; } while(curr != NULL) { curr->id --; room[curr->x-1][curr->y-1]=curr->id; curr = curr->next; } } int four_search(int pos_x, int pos_y, int dest_x, int dest_y) { if(pos_x == dest_x && pos_y == dest_y) return 1; if(pos_x < 1 || pos_x > ROOM_WIDTH || pos_y < 1 || pos_y > ROOM_HEIGHT) return 0; if(path[pos_x-1][pos_y-1] == 0) { path[pos_x-1][pos_y-1] = 1; if(four_search(pos_x, pos_y+1, dest_x, dest_y)==1) return 1; if(four_search(pos_x, pos_y-1, dest_x, dest_y)==1) return 1; if(four_search(pos_x+1, pos_y, dest_x, dest_y)==1) return 1; if(four_search(pos_x-1, pos_y, dest_x, dest_y)==1) return 1; } return 0; } int isconnected(int pos_x, int pos_y, int dest_x, int dest_y) { int i, j; for(i=0; i<ROOM_WIDTH; i++)for(j=0; j<ROOM_HEIGHT; j++) path[i][j] = (room[i][j]==0)? 0 : 2; path[pos_x-1][pos_y-1] = 0; if(four_search(pos_x, pos_y, dest_x, dest_y)==1) return 1; else return 0; } int ispushable(int pos_x, int pos_y, int delta) { int tpx, tpy, tdx, tdy, i, absd; absd = (delta>0)? delta : -delta; switch(get_casep(get_caseid(pos_x, pos_y))->dir) { case HOR: tpy = pos_y; i=0; do { i++; tpx = pos_x+((delta>0)?i:-i); if(tpx <= 0 || tpx > ROOM_WIDTH) return 0; } while(tpx+((delta>0)?1:-1) > 0 && tpx+((delta>0)?1:-1) <= ROOM_WIDTH && room[tpx+((delta>0)?1:-1)-1][pos_y-1] != 0); for(i=1; i<=absd; i++) if(room[tpx+((delta>0)?i:-i)-1][tpy-1] != 0) return 0; return 1; break; case VER: tpx = pos_x; i=0; do { i++; tpy = pos_y+((delta>0)?i:-i); if(tpy <= 0 || tpx > ROOM_HEIGHT) return 0; if(get_casep(get_caseid(tpx,tpy))->dir != VER) return 0; } while(tpy+((delta>0)?1:-1) > 0 && tpy+((delta>0)?1:-1) <= ROOM_HEIGHT && room[pos_x-1][tpy+((delta>0)?1:-1)-1] != 0); for(i=1; i<=absd; i++) if(room[tpx-1][tpy+((delta>0)?i:-i)-1] != 0) return 0; return 1; break; } } void move_case(int pos_x, int pos_y, int dest_x, int dest_y) { int dx, dy, i; int tpx, tpy, tdx, tdy; t_bookcase * bcp; t_bookcase * tbcp; t_bookcase * dabbp; if(pos_x<1 || pos_x>ROOM_WIDTH || pos_y<1 || pos_y>ROOM_HEIGHT || dest_x<1|| dest_x>ROOM_WIDTH || dest_y<1|| dest_y>ROOM_HEIGHT) return; dx = dest_x - pos_x; dy = dest_y - pos_y; bcp = get_casep(get_caseid(pos_x, pos_y)); dabbp = find_dabb(); if(dabbp != NULL && isconnected(bcp->x, bcp->y, dabbp->x, dabbp->y) == 0) { printf("cannot push or pull\n"); return; } else if(dabbp == NULL) printf("no librarian specified\n"); if( (bcp != NULL && room[dest_x-1][dest_y-1] == 0) && ( ((bcp->dir==HOR && bcp->y==dest_y) || (bcp->dir==VER && bcp->x==dest_x)) || bcp->dir == ANY) ) { if(bcp->dir == HOR) for(i=1; i<=abs(dx); i++) if(room[pos_x+((dx>0)?i:-i)-1][pos_y-1] != 0) { printf("illegal move.\n"); return; } if(bcp->dir == VER) for(i=1; i<=abs(dy); i++) if(room[pos_x-1][pos_y+((dy>0)?i:-i)-1] != 0) { printf("illegal move.\n"); return; } if(bcp->dir == ANY) if(isconnected(pos_x, pos_y, dest_x, dest_y)==0) { printf("illegal move.\n"); return; } room[pos_x-1][pos_y-1] = 0; room[dest_x-1][dest_y-1] = bcp->id; bcp->x = dest_x; bcp->y = dest_y; if(bcp->face == NONE && bcp->dir == ANY) { printf("moved librarian :(%d,%d) -> (%d,%d)\n", pos_x, pos_y, dest_x, dest_y); } else { printf("moved bookcase %2d:(%d,%d) -> (%d,%d)\n", bcp->id, pos_x, pos_y, dest_x, dest_y); } } else if(bcp != NULL && ((bcp->dir == HOR && bcp->y == dest_y) || (bcp->dir == VER && bcp->x == dest_x))) { if(ispushable(pos_x, pos_y, (bcp->dir==HOR?dx:dy))==0) { printf("cannot push %d:(%d,%d).\n", bcp->id, bcp->x,bcp->y); return; } switch(bcp->dir) { case HOR: tpy=pos_y; tdy=dest_y; i=0; do { i++; tpx = pos_x+((dx>0)?i:-i); } while(room[tpx-1][tpy-1] != 0); do { i--; tpx = pos_x+((dx>0)?i:-i); tdx = tpx + dx; tbcp = get_casep(get_caseid(tpx,tpy)); room[tpx-1][tpy-1] = 0; room[tdx-1][tdy-1] = tbcp->id; tbcp->x = tdx; printf("moved bookcase %2d:(%d,%d)->(%d,%d)\n", tbcp->id, tpx, tpy, tdx, tdy); } while(tpx != pos_x); break; case VER: tpx=pos_x; tdx=dest_x; i=0; do { i++; tpy = pos_y+((dy>0)?i:-i); } while(room[tpx-1][tpy-1] != 0); do { i--; tpy = pos_y+((dy>0)?i:-i); tdy = tpy + dy; tbcp = get_casep(get_caseid(tpx,tpy)); room[tpx-1][tpy-1] = 0; room[tdx-1][tdy-1] = tbcp->id; tbcp->y = tdy; printf("moved bookcase %2d:(%d,%d)->(%d,%d)\n", tbcp->id, tpx, tpy, tdx, tdy); } while(tpy != pos_y); break; } } else printf("illegal move.\n"); } void draw_case(t_bookcase *bc) { int i, j, k; i = (bc->y-1)*3+1; j = (bc->x-1)*6+2; if(bc->face == NONE && bc->dir == ANY) { strncpy(&img_buf[i+1][j+2],"藏",2); return; } strncpy(&img_buf[i][j], "┌─┐",6); strncpy(&img_buf[i+1][j],"│ │",6); strncpy(&img_buf[i+2][j],"└─┘",6); switch(bc->face) { case NORTH: strncpy(&img_buf[i][j+2], "━",2); break; case SOUTH: strncpy(&img_buf[i+2][j+2], "━",2); break; case EAST: strncpy(&img_buf[i+1][j+4], "┃",2); break; case WEST: strncpy(&img_buf[i+1][j], "┃",2); break; } switch(bc->dir) { case FIX: strncpy(&img_buf[i+1][j+2],"X",2); break; case HOR: strncpy(&img_buf[i+1][j+2],"↔",2); break; case VER: strncpy(&img_buf[i+1][j+2],"↕",2); break; } } void draw_door(void) { int i = door_pos*6+2; strncpy(&img_buf[IMG_HEIGHT-1][i],"┤ ├",6); } void draw_study(void) { int i,j; t_bookcase * bcp; init_img(); for(i=1; i<=ROOM_WIDTH; i++) for(j=1;j<=ROOM_HEIGHT;j++) { bcp = get_casep(get_caseid(i,j)); if(bcp != NULL) draw_case(bcp); } draw_door(); printf(" "); for(i=0; i<ROOM_WIDTH; i++) printf(" %2d",i+1); printf("\n"); for(i=0; i<IMG_HEIGHT; i++) printf("%c %s\n", (i%3==2 && i!=0)?'A'+i/3:' ', img_buf[i]); } void draw_prompt(void) { printf("\n\n"); printf("> "); } void draw_help(void) { printf("enter <cmd> <options>\n\n"); printf("cmd: h=help(print this hint),\n"); printf(" q=quit, m=move, s=set_bookcase, r=remove_bookcase,\n"); printf(" p=place_man, d=place_door,\n"); printf(" c=clear all\n"); printf("options:\n"); printf(" move: m <pos> <dest>\n"); printf(" set: <pos> <face> <dir>\n"); printf(" reset: <pos>\n"); printf(" p: <pos>\n"); printf(" d: <num>\n\n"); printf(" pos/dest: Xn : X=A/B/C/... n=1/2/3/...\n"); printf(" num: n : n=1/2/3/...\n"); printf(" face: n=north, s=south, e=east, w=west\n"); printf(" dir: f=fix, v=vetical, h=horizontal\n"); } unsigned char get_cmd(void); int get_pos(void); int get_dest(void); int get_face(void); int get_dir(void); int get_command(void) { gets(cmdbuf); } char fnamebuf[80]; int decode_command(void) { cmdbufidx = 0; cmd = get_cmd(); switch(cmd) { case 'q': case 'Q': return -1; case 'm': case 'M': pos = get_pos(); dest = get_dest(); move_case(pos/16, pos%16, dest/16, dest%16); break; case 's': case 'S': pos = get_pos(); face = get_face(); dir = get_dir(); set_case(pos/16, pos%16, face, dir); break; case 'r': case 'R': pos = get_pos(); reset_case(get_caseid(pos/16, pos%16)); break; case 'p': case 'P': pos = get_pos(); set_dabb(pos/16, pos%16); break; case 'd': case 'D': pos = get_num(); set_door(pos); break; case 'c': case 'C': while(head != NULL) reset_case(1); break; case 'h': case 'H': draw_help(); break; default: break; } return 0; } unsigned char get_cmd(void) { unsigned char c; while (isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(isalpha(cmdbuf[cmdbufidx])) c = cmdbuf[cmdbufidx++]; while (!isspace(cmdbuf[cmdbufidx])) cmdbufidx++; return c; } int get_num(void) { int c=0; while (isspace(cmdbuf[cmdbufidx])) cmdbufidx++; while(isdigit(cmdbuf[cmdbufidx])) c = c*10 + cmdbuf[cmdbufidx++]-'0'; while (!isspace(cmdbuf[cmdbufidx])) cmdbufidx++; return c; } int get_pos(void) { int p; while (isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(islower(cmdbuf[cmdbufidx])) p = cmdbuf[cmdbufidx++]-'a'+1; else if(isupper(cmdbuf[cmdbufidx])) p = cmdbuf[cmdbufidx++]-'A'+1; else p = 0; if(isdigit(cmdbuf[cmdbufidx])) p |= (get_num() << 4); else p = 0; while (!isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(p >= 0xF0 || ((p & 0x0F) > ROOM_WIDTH)) p=0; return p; } int get_dest(void) { int d; while (isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(islower(cmdbuf[cmdbufidx])) d = cmdbuf[cmdbufidx++]-'a'+1; else if(isupper(cmdbuf[cmdbufidx])) d = cmdbuf[cmdbufidx++]-'A'+1; else d = 0; if(isdigit(cmdbuf[cmdbufidx])) d |= (get_num() <<4 ); else d = 0; while (!isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(d >= 0xF0 || ((d & 0x0F) > ROOM_WIDTH)) d=0; return d; } int get_face(void) { int f; char c; while (isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(isalpha(cmdbuf[cmdbufidx])) c = cmdbuf[cmdbufidx++]; while (!isspace(cmdbuf[cmdbufidx])) cmdbufidx++; switch(c) { case 'n': case 'N': f = NORTH; break; case 's': case 'S': f = SOUTH; break; case 'e': case 'E': f = EAST; break; case 'w': case 'W': f = WEST; break; default: cmd = 'x'; break; } return f; } int get_dir(void) { int d; char c; while (isspace(cmdbuf[cmdbufidx])) cmdbufidx++; if(isalpha(cmdbuf[cmdbufidx])) c = cmdbuf[cmdbufidx++]; while (!isspace(cmdbuf[cmdbufidx])) cmdbufidx++; switch(c) { case 'f': case 'F': d = FIX; break; case 'v': case 'V': d = VER; break; case 'h': case 'H': d = HOR; break; default: cmd = 'x'; break; } return d; } #define DO_COMMAND(str) strcpy(cmdbuf, (str)); decode_command() int main(void) { FILE * fp; char namestr[80]; int cmd_ret; if(fp=fopen("study.init", "r")) { while(fgets(cmdbuf, 80, fp)) decode_command(); fclose(fp); } sprintf(namestr,"st%ld.log", getpid()); fp=fopen(namestr, "w"); init_study(); draw_study(); draw_prompt(); get_command(); while(decode_command() != -1) { fputs(cmdbuf, fp); fputc('\n',fp); draw_study(); draw_prompt(); get_command(); } fclose(fp); return 0; } -------------------------- end of study.c ------------------------ ... May the source be with you! |