0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C言語】『ウサギと猟犬』を作ってみた

Last updated at Posted at 2025-10-25

はじめに

こんにちは 高専1年生、ロボコン部部員です
今回はイギリス発祥のボードゲーム:『ウサギと猟犬』をC言語で実装してみました
久々に作ったゲームなので見どころこそあまりありませんが基礎的でもあります
ぜひ楽しんでいってください

プレイ映像

こちらがターミナルの画像です
スクリーンショット 2025-10-25 211145.png

コード紹介

冒頭部分

#include <stdio.h>

void map_init(int *map);
int first_attack_decide(void);

void map_print(int *map);

int location_return(int *map,int indivi);

void input(int *map,int player);
int can_move_check(int *map,int player,int dest,int intivi);
void map_change(int *map,int dest,int intivi);

int game_check(int *map,int play_count);
int rabbit_win_check(int *map,int play_count);
int dog_win_check(int *map);

void game_print(int game_set);

main関数

今回のmain関数は特に、短く簡潔にすることを心掛けました
関数の呼び出しが多いので最初に下記の関数から把握することをお勧めします

この関数の呼び出す関数は、

  • map_init関数
  • first_attack_decide関数
  • map_print関数
  • input関数
  • game_check関数
  • game_print関数

の六つです

int main(void){
	int map[11] = {0};
	int player = 0;
	int game_set = 0;
	int play_count = 0;
	
	map_init(map);
	player = first_attack_decide();
	do{
		map_print(map);
		printf("\x1b[0m%2d手目\n",play_count+1);
		input(map,player);
		game_set = game_check(map,play_count);
		player = 1-player;
		play_count++;
	}while(game_set == 0);
	map_print(map);
	game_print(game_set);
	return 0;
}

map_init関数

map配列をポインタを用いて初期化する関数です
1,2,3は猟犬を表し、4はウサギを表します。
何もないマスは0となります

void map_init(int *map){
	int init_i;
	for(init_i=0; init_i<11; init_i++){
		map[init_i] = 0;
	}
	map[0] = 1;
	map[1] = 2;
	map[3] = 3;
	map[10] = 4;
}

first_attack_decide関数

先攻をplayer変数を変更することで設定します
playerが0の時はウサギ、
1の時は猟犬のターンであることを表します

int first_attack_decide(void){
	int ans;
	printf("\x1b[0m------------ウサギと猟犬------------\n\n");
	printf("先攻はどちらにしますか\n");
	printf("\x1b[34mウサギ→ 0\n");
	printf("\x1b[31m猟犬  → 1\n");
	do{
		printf("\x1b[0m入力してください:");
		scanf("%d",&ans);
	}while(ans<0 || 1<ans);
	return ans;
}

一番初めに呼び出す関数なので、ここでタイトルも表示しちゃっています

map_print関数

これはmap配列からmapのイラストを表示する関数です
マップの形が複雑だったため、ゴリ押しコードになってしまいました

void map_print(int *map){
	int print_data[45] = {
		-1,-1, 1,-2, 4,-2, 7,-1,-1,
		-1,-4,-3,-5,-3,-4,-3,-5,-1,
		 0,-2, 2,-2, 5,-2, 8,-2,10,
		-1,-5,-3,-4,-3,-5,-3,-4,-1,
		-1,-1, 3,-2, 6,-2, 9,-1,-1
	};
	char print_symb_data[5] = {'l','/','|','-',' '};
	int twice_i,print_i;
	printf("\n");
	for(twice_i=0; twice_i<2; twice_i++){
		for(print_i=0; print_i<45; print_i++){
			if(print_data[print_i] < 0){
				printf("\x1b[0m %c ",print_symb_data[print_data[print_i]+5]);
			}else{
				if(twice_i == 0){
					printf("\x1b[0m%2d ",print_data[print_i]);
				}else{
					if(map[print_data[print_i]] == 4){
						printf("\x1b[34m[○]");
					}else if(map[print_data[print_i]] == 3 || map[print_data[print_i]] == 2 || map[print_data[print_i]] == 1){
						printf("\x1b[31m[%d]",map[print_data[print_i]]);
					}else{
						printf("\x1b[0m[ ]");
					}
				}
			}
			if(print_i%9 == 8){
				printf("\n");
			}
		}
		printf("\n");
	}
}

location_return関数

map配列と探したい数値から
その数値のある位置を返す関数です
主にウサギや猟犬の位置を調べるのに使います

int location_return(int *map,int intivi){
	int exp_i;
	for(exp_i=0; exp_i<11; exp_i++){
		if(map[exp_i] == intivi){
			return exp_i;
		}
	}
	return 0;
}

input関数

ここで入力させるのは、

  • 猟犬の番の時には、「どの個体を動かすか
  • どこに動かすか

の二つです

  • can_move_check関数で『入力されたマスに移動できるかどうか』をチェックしています
  • また、入力されたマスに移動するようmap配列を変化させる、
    map_change配列も呼び出しています
void input(int *map,int player){
	int intivi = 4;
	int dest;
	
	if(player == 0){
		printf("\x1b[34mウサギ:\n");
	}else{
		printf("\x1b[31m猟犬:\n\x1b[0mどれを動かしますか(1~3)\n");
		do{
			printf("\x1b[0m入力してください:");
			scanf("%d",&intivi);
		}while(intivi<1 || 3<intivi);
	}
	
	do{
		do{
			printf("\x1b[0mどこに移動しますか:");
			scanf("%d",&dest);
		}while(dest<0 || 10<dest);
	}while(can_move_check(map,player,dest,intivi) == 0);
	map_change(map,dest,intivi);
}

can_move_check関数

ここでは現在地とmap配列の情報、目的地から
『現在地→目的地の移動が可能か』を審査します

猟犬のターンでは特に、後ろに戻れないようにしていますね

int can_move_check(int *map,int player,int dest,int intivi){
	int can_move_data[22] = {107,108,109,78,89,74,85,96,75,95,45,56,41,52,63,51,53,12,23,10,20,30};
	int location = location_return(map,intivi);
	int check_i;
	if(map[dest] != 0){
		return 0;
	}else{
		for(check_i=0; check_i<22; check_i++){
			if(can_move_data[check_i] == location*10 + dest){
				if(player == 1){
					if((dest+2)/3 >= (location+2)/3){
						return 1;
					}
				}else{
					return 1;
				}
			}else if(can_move_data[check_i] == dest*10 + location){
				return 1;
			}
		}
		return 0;
	}
	return 0;
}

map_change関数

実際にmap配列を変更する関数です

void map_change(int *map,int dest,int intivi){
	int location = location_return(map,intivi);
	map[location] = 0;
	map[dest] = intivi;
}

game_check関数

ゲームの勝敗を決める、

  • rabbit_win_check関数
  • dog_win_check関数

を呼び出し、勝敗を実際にmain関数に送る仕事をします

int game_check(int *map,int play_count){
	int rabbit_win = rabbit_win_check(map,play_count);
	int dog_win = dog_win_check(map);
	
	if(rabbit_win == 1){
		return 1;
	}else if(dog_win == 1){
		return 2;
	}
	return 0;
}

rabbit_win_check関数

ウサギが勝つと1,勝たないと0を返す関数です
『千日手』の処理はここで実装しています

int rabbit_win_check(int *map,int play_count){
	int check_i;
	if(play_count >= 19){
		return 1;
	}
	for(check_i=0; check_i<3; check_i++){
		if((location_return(map,4)+2)/3 >= (location_return(map,check_i+1)+2)/3){
			return 0;
		}
	}
	return 1;
}

dog_win_check関数

猟犬が勝つと1,勝たないと0を返す関数です
全マスを調べ、ウサギがそのマスから移動できるかできないかを明確にします

int dog_win_check(int *map){
	int check_i;
	for(check_i=0; check_i<11; check_i++){
		if(can_move_check(map,0,check_i,4) == 1){
			return 0;
		}
	}
	return 1;
}

game_print関数

game_set変数の値からゲームの試合を表示します

void game_print(int game_set){
	if(game_set == 1){
		printf("\x1b[0mウサギが逃げた!ウサギの勝利\n");
	}else if(game_set == 2){
		printf("\x1b[0mウサギは動けない!猟犬の勝利\n");
	}
}

さいごに

ここまで読んでくださりありがとうございました
改善点などあれば教えていただけるととても嬉しいです

0
1
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?