관리 메뉴

c0smicb0y

시스템 프로그래밍 팀프로젝트 4 본문

진행한 프로젝트/시스템 프로그래밍

시스템 프로그래밍 팀프로젝트 4

2015. 1. 9. 01:24

이제 여러가지 기술이 들어간 산성비 게임에 대해 설명하겠다.

한컴타자연습을 해보았다면 다들 해봤을법한 게임이다.

구현은 일단 입력칸이 있고, HP가 있고, 위에서부터 랜덤한 위치에 단어가 나오면서 밑으로 떨어진다.

맞는 단어를 입력하면 그 단어가 사라지고, 결국 못맞추고 단어가 제일 아래까지 내려오면 HP가 감소하게 만들었다.



일단 화면상에 표시되는 단어들이 어디에 저장되어 있어야 할것이다. 단어가 화면에 나타나고 먼저 나타난 단어가 먼저 맨 밑까지 가서 사라지기 때문에 선입선출이 일어날 수 있는 큐를 써야할 것이다. 하지만 큐를 쓰는 부분에서 간단히 정적 배열을 통한 큐를 쓴다면 언젠가 큐의 끝부분이 나와서 더 이상 데이터를 집어넣을수 없으므로 데이터를 큐의 앞쪽으로 이동시켜야하는데 이 부분에서 성능 상의 문제가 생길 수 있다. 그래서 이럴 필요가 없는 링크드리스트를 통하여 큐를 구현하였다.

저장할 방법을 정했으니 이제 화면에 표시하는 부분에서 문제가 있었다. 커서는 하나인데 화면에 글자를 출력하면서 입력창에 입력을 하는것은 불가능하기 때문이다. 그래서 화면을 표시하는 쓰레드를 분리해서 표시하였다. 



그리고 큐를 링크드리스트로 구현하면서 동적할당을 사용하여 인터럽트를 발생시켜서 프로그램이 강제로 종료되는 경우에 메모리 할당해제가 안되고, 변경했던 터미널 설정이 원래대로 돌아가지 않는 문제가 발생하였다. 그래서 signal을 통제하는 함수를 써서 인터럽트로 인해 강제종료 될 경우에 메모리 할당을 해제하고, 커서표시를 비활성화 했었는데 이걸 다시 활성화 시키고, 콘솔 윈도우창을 닫고, 프로그램을 종료하게 handling해주었다.


1
2
3
4
5
6
7
void function(int signum)
{
    reset();        // 메모리 할당 해제
    curs_set(1);    // 커서 표시 활성화
    endwin();        // 콘솔 윈도우창 닫기
    exit(1);        // 프로그램 종료
}
cs


다음은 이렇게해서 만든 프로그램의 코드이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <curses.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
 
int hp = 100;        // 체력
int a = 0;            // 문자열 위치
int i = 0;            // for문용
int length = 0;
char hpText[3] = { 0 };
node *ptr = 0;
char enterText[20] = { 0 };
int enterHere = 0;
int sleep_time = 1;
 
void function(int signum)
{
    reset();        // 메모리 할당 해제
    curs_set(1);    // 커서 표시 활성화
    endwin();        // 콘솔 윈도우창 닫기
    exit(1);        // 프로그램 종료
}
 
// 큐를 비워주고 메모리 할당을 해제해주는 함수
void reset()
{
    node *temp = NULL;
    node *temp2 = NULL;
 
    temp = ptr;
 
    if (temp != NULL)
    {
        while (length > 0)
        {
            temp = ptr;
 
            while (temp->link)
            {
                temp2 = temp;
                temp = temp->link;
            }
 
            free(temp);
 
            if (temp2 != NULL)
                temp2->link = NULL;
 
            length--;
            temp2 = NULL;
        }
 
        ptr = NULL;
    }
}
 
// 화면에 글자를 보이게만 하는 함수
void thread_1(void *none)
{
    int t = sleep_time;
 
    while (hp > 0)
    {
        //alarm(2);
 
        node *temp = 0;
 
        addQueue(returnWord(), (rand() % 40) + 8);
        temp = ptr;
 
        while (temp)
        {
            draw(temp->row, temp->col, temp->str);
            temp = temp->link;
        }
 
        move(1712);
 
        sleep(t);
 
    }
}
 
// 자연수를 문자열로
int itoa(int n, char *str)
{
    int temp;
 
    if (n <= 0)
    {
        strcpy(str, "0");
        return 0;
    }
 
    temp = itoa(n / 10, str);
 
    *(str + temp) = 48 + (n % 10);
 
    return temp + 1;
}
 
// 입력한 문자열을 큐에서 찾아서 없애주는 함수
void findWord(char *str)
{
    node *temp = 0;
    temp = ptr;
 
    while (temp)
    {
        if (!strcmp(temp->str, str))
        {
            strcpy(temp->str, "");
            return;
        }
        else
            temp = temp->link;
    }
}
 
// 노드 생성
node *makeNode()
{
    node *temp = 0;
 
    temp = (node *)malloc(sizeof(*temp));
    temp->link = 0;
}
 
// 한 줄씩 밑으로 내려오게 해 주는 코드
void makePlusOne()
{
    node *temp = ptr->link;
 
    while (temp)
    {
        temp->row += 1;
        temp = temp->link;
    }
}
 
// 큐에 하나씩 넣는 함수
void addQueue(char *str, int col)
{
    node *temp = 0;
    node *temp2 = 0;
 
    if (ptr == 0)
    {
        ptr = makeNode();
        strcpy(ptr->str, str);
        ptr->row = 1;
        ptr->col = col;
    }
    else
    {
        temp = makeNode();
        strcpy(temp->str, str);
        temp->row = 1;
        temp->col = col;
        temp->link = ptr;
        ptr = temp;
        makePlusOne();
    }
 
    length++;
 
    if (length > 15)
    {
        while (temp->link)
        {
            temp2 = temp;
            temp = temp->link;
        }
 
        hp -= strlen(temp->str);
 
        hpText[2] = '\0';
 
        itoa(hp, hpText);
        move(1755);
        addstr("    ");
        move(1755);
        addstr(hpText);
 
        free(temp);
        temp2->link = 0;
 
        length--;
    }
}
 
// 단어 데이터베이스에서 글자를 골라서 리턴해주는 부분
char *returnWord()
{
    char *database[] = { "Apple""Jung""Cocaine""Hello""Elite""Fail""Game",
                         "Halo""Icon""Jail""Knight""Lake""Monkey""Nope" };
 
    if (a == 13)
        a = 0;
    else
        a++;
 
    return database[a];
}
 
// row행 col열에 문자열 str을 출력해주는 부분
void draw(int row, int col, char *str)
{
    move(row, 0);
    addstr("                                                       ");
    move(row, col);
    addstr(str);
    refresh();
}
 
void startGame()
{
    pthread_t t1;
 
    clear();
 
    draw(160"   -------------------------------------------------------- ");
    draw(170"  | Enter :                                     | HP :     |");
    draw(180"   -------------------------------------------------------- ");
 
    itoa(hp, hpText);
    move(1755);
    addstr("    ");
    move(1755);
    addstr(hpText);
 
    pthread_create(&t1, NULL, thread_1, NULL);
 
    while (hp > 0)
    {
        for (enterHere = 0; enterHere < 20;)
        {
            int c = getch();
 
            if (c == '\n')
            {
                enterText[enterHere] = '\0';
                findWord(enterText);
 
                for (i = 0; i < 20; i++)
                {
                    enterText[i] = '\0';
                }
 
 
                draw(170"  | Enter :                                     | HP : ");
                move(1712);
 
                break;
            }
            else if (c == 127)
            {
                if (enterHere > 0)
                {
                    enterText[--enterHere] = '\0';
                    move(1712);
                    addstr("                    ");
                    move(1712);
                    addstr(enterText);
                }
                else
                {
                    move(1712);
                    addstr("                    ");
                }
            }
            else
            {
                enterText[enterHere++] = c;
                move(1712);
                addstr(enterText);
            }
 
            refresh();
        }
    }
 
    pthread_join(&t1, NULL);
 
    reset();
    clear();
}
 
cs


그래서 만들어진 최종 프로그램의 시연 동영상이다.



출력되는 단어를 파일입출력을 통해 표시하게 했으면 더 좋았을건데 시간이 없어서 그러진 못했다. 다른 팀들은 대부분 소켓통신을 통한 프로그램을 만들었던데 소켓통신이 약간 어려워서 그런지 기본구현에도 다들 애를 먹었는지 대부분 그냥 소켓통신이 되는 프로그램이라는 느낌밖에 주지못했다. 우리팀도 소켓통신을 넣을려고 했는데 아무리 생각해봐도 만들려고 하는 것에 필요없는 기능같아서 과감히 뺀 덕분에 독창적으로 이것저것 구현할 수 있었다. 그리고 팀프로젝트를 할 때마다 느끼는 점인데 개인프로젝트보다 다섯배정도 어려운것 같다. 단순히 다른팀원의 코드를 알아보는게 힘들어서가 아니라 다른팀원을 관리하는게 더 어려워서 그렇다. 결국 사람 문제인것 같다. 소프트웨어 설계 시간에도 사람을 다루는 기술로 몇시간정도 수업을 했었다. 공돌이한테는 커뮤니케이션은 참 어렵다. 그것도 개인주의 성향이 강한 컴공에서는 말이다. 그래도 파탄나지 않고 순조롭게 진행되어서 다행이다.

Comments