언어/C

[코딩자율학습] 15일차 동물카드 뒤집기 프로젝트

홍시_코딩기록 2024. 3. 24. 19:18
#include <stdio.h>
#include <time.h> // 헤더 파일 추가
#include <stdlib.h> // 헤더 파일 추가

// 전역변수
int arrayAnimal[4][5]; //카드 배열 선언, 카드 20장인 2차원 배열 선언
char* strAnimal[10];  //카드에 표시할 동물 이름 배열 (동물 이름 10개)
int checkAnimal[4][5]; //카드 뒷면, 앞면 확인 배열 선언

// 함수 선언
void initAnimalArray(); //카드 배열 초기화 함수, 게임을 시작하면 카드는 모두 뒷면, 배열의 모든 요소에 같은 값을 넣음.
void initAnimalName(); //동물 이름 배열 초기화
void shuffleAnimal(); //카드 섞기 함수 선언
int getEmptyPosition(); //카드 지도에서 빈 공간 찾기 함수 선언. 카드 번호 반환으로 int
int conv_pos_x(int x); //x좌표 변환 함수 선언
int conv_pos_y(int y); //y좌표 변환 함수 선언
void printAnimals(); // 카드 지도 출력 함수 선언
void printQuestion(); //문제 출력 함수 선언
int foundAllAnimals();



int main(void) {

	srand(time(NULL)); //난수 초기화
	initAnimalArray(); //카드 배엺 함수 호출
	initAnimalName();  //이름 배열 함수 호출
	shuffleAnimal(); //카드 섞기 함수 호출
	int failCount = 0; 

	while (1) { //게임 끝날떄까지 반복
		int select1 = 0; // 사용자가 선택한 첫 번째 번호 저장 
		int select2 = 0; // 사용자가 선택한 두 번째 번호 저장 
		printAnimals(); // 카드 지도 출력 함수 호출
		printQuestion(); // 문제 출력 함수 호출
		printf("\n뒤집을 카드 2장을 고르세요.(예: 12 4) -> ");
		scanf_s("%d %d", &select1, &select2); // 카드 번호 입력받기
		if (select1 == select2) { // 같은 카드 선택 시 무효 처리
			continue; // 반복문 시작 지점으로 돌아가기
		}

		// 입력받은 카드 번호를 x, y 좌표로 변환
		int firstSelect_x = conv_pos_x(select1);
		int firstSelect_y = conv_pos_y(select1);
		int secondSelect_x = conv_pos_x(select2);
		int secondSelect_y = conv_pos_y(select2);
		// 두 카드가 같은 동물이고 뒷면인 경우
		if ((checkAnimal[firstSelect_x][firstSelect_y] == 0
			&& checkAnimal[secondSelect_x][secondSelect_y] == 0)
			&& (arrayAnimal[firstSelect_x][firstSelect_y] ==
				arrayAnimal[secondSelect_x][secondSelect_y])) {
			printf("\n\n빙고! %s 발견\n\n", strAnimal[arrayAnimal[firstSelect_x][firstSelect_y]]);
			checkAnimal[firstSelect_x][firstSelect_y] = 1;
			checkAnimal[secondSelect_x][secondSelect_y] = 1;
		}
		else { // 두 카드가 다른 동물이거나 앞면인 경우
			printf("\n\n땡! 서로 다른 동물 카드거나 이미 뒤집힌 카드입니다.\n");
			printf("%d : %s\n", select1, strAnimal[arrayAnimal[firstSelect_x][firstSelect_y]]);
			printf("%d : %s\n", select2, strAnimal[arrayAnimal[secondSelect_x][secondSelect_y]]);
			printf("\n");
			failCount++; // 실패 횟수 1 증가
		}
		if (foundAllAnimals() == 1) { // 모든 동물을 찾았는지 여부, 1 : 참, 0 : 거짓
			printf("\n\n축하합니다! 모든 동물을 다 찾았습니다.\n");
			printf("총 %d번 실패했습니다.\n", failCount);
			break;
		}
	}
	return 0;
}

void initAnimalArray() {  // arrayAnimal 배열은 2차우너 배열이니까 이중반복문을 사용해서 arrayAnimal[0][0] ~ [3][4]까지 20개 요소에 -1 저장
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 5; j++) {
			arrayAnimal[i][j] = -1; // 카드 뒷면 설정
		}
	}
}

void initAnimalName() { //strAnimal 배열에 동물 이름 10개를 저장함. 배열의 각 요소에는 동물 이름 문자열이 저장되는 것이 아니라 문자열이 저장된 메모리 공간의 시작 주소가 저장
	strAnimal[0] = "원숭이";
	strAnimal[1] = "하마";
	strAnimal[2] = "댕댕";
	strAnimal[3] = "고양이";
	strAnimal[4] = "돼지";
	strAnimal[5] = "코끼리";
	strAnimal[6] = "푸바오";
	strAnimal[7] = "러바오";
	strAnimal[8] = "타조";
	strAnimal[9] = "호랭";
}

void shuffleAnimal() { 
	for (int i = 0; i < 10; i++) { // 10번 반복
		for (int j = 0; j < 2; j++) { //동물 이름 배치하는 작업 2번 반복
			int pos = getEmptyPosition(); //카드 지도에서 빈 공간 찾기 함수, 빈 공간을 찾아서 해당 위치를 반환. 이 값을 받아 동물 이름 배치하므로 pos 변수에 저장.
			int x = conv_pos_x(pos); // 카드번호를 x 좌표로 변환하는 함수 호출
			int y = conv_pos_y(pos);
			arrayAnimal[x][y] = i; //카드 배열에 동물 번호 저장
		}
	}
}

int getEmptyPosition() { //카드 지도에서 빈공간찾기 함수
	while (1) {
		int randPos = rand() % 20; //무작위로 뽑은 카드 번호 반환(0~19)
		int x = conv_pos_x(randPos); //반환한 카드 번호를 x좌표로 변환
		int y = conv_pos_y(randPos); //y좌표
		if (arrayAnimal[x][y] == -1) { //해당위치 비었는지 확인
			return randPos;
		}
	}
	return 0;
}

int conv_pos_x(int x) { 
	return x / 5; //x좌표, 카드 번호를 5로 나눈 몫
}

int conv_pos_y(int y) {
	return y % 5; //
}

void printAnimals() { //동물 위치 출력 함수
	printf("\n=====동물 위치를 보여줍니다. ====\n\n");
	for (int i = 0; i < 4; i++) { //이중 반복문으로 arrayAnimal 배열 접근
		for (int j = 0; j < 5; j++) {
			printf("%8s", strAnimal[arrayAnimal[i][j]]); //카드 지도 좌표로 동물이름 출력
		}
		printf("\n");
	}
	printf("\n========================================\n");
}

void printQuestion() { //카드 지도 출력 함수
	printf("\n(문제)\n\n");
	int seq = 0; //변수 선언 및 초기화
	for (int i = 0; i < 4; i++) { //이중 반복문으로 카드 지도에 접근
		for (int j = 0; j < 5; j++) {
			if (checkAnimal[i][j] != 0) { //카드가 앞면일 떄
				printf("%8s", strAnimal[arrayAnimal[i][j]]);
			}
			else {
				printf("%8d", seq);
			}
			seq++; //다음 카드로 넘어가기
		}
		printf("\n");
	}
}

int foundAllAnimals() { //게임 종료 확인 함수
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 5; j++) {
			if (checkAnimal[i][j] == 0) {
				return 0; //뒤집지 않은 카드가 있음.
			}
		}
	}
	return 1;//모든 카드 뒤집음.
}

 

 

- 휴.. 겨우 끝냈다. 카드뒤집기 게임 하지마. 그냥 가위바위보 하고 놀아

 

포인터 배열

char형 포인터 변수는 char형 값이 저장된 메모리 주소를 저장한 변수라는 뜻. char * cPtr = “테스트”; ’테스트’라는 문자열을 어떤 메모리 공간에 저장하고 그 공간의 시작 주소를 cPtr 변수에 저장하는 것. 일너 포인터 변수가 요소로 있는 배열을 포인터 배열이라고 함. 포인터 배열은 요소의 값이 메모리 주소인 배열을 의미함.

 

 

x, y좌표를 바로 반환하면 안되는 이유
getEmptyPosition() 함수와 shuffleAnimal()함수에서 모두 conv_pos_x() 함수와 conv_pos_y()함수를 사용함. 중복 작업을 줄이려면 함수의 반환형을 int형 말고 구조체를 사용해야하지만 구조체를 배우지 않았기에 int형으로 함수의 반환값을 넘기는 방식을 사용함.