2
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-09-28

はじめに

こんにちは 高専1年のロボコン部部員です
今回は完成したハノイの塔を共有します
かなり単純なコードですが
いつもより綺麗にまとめることができたのでぜひ見ていってください

プレイ画像

正しいスクリーンショット 2025-09-28 163422.png

コード解説

includeとマクロ、関数宣言

BLOCKSの綴りを間違えているのは気にしないでください

#include <stdio.h>

#define BROCKS 3

void first_put(int *map);
void map_making(int *map);
int last_empty(int *map,int line);

void input_take_line(int *map);
void take(int *map,int line,int lasempty);
void input_put_line(int *map,int brock);
void put(int *map,int line,int lasempty,int brock);

int clear_check(int *map);

void clear_print(int trouble);

main関数

ここで基本的なゲーム進行を行います
first_put関数、map_making関数、take_line_input関数、
clear_check関数、clear_print関数
の順で呼び出します

int main(void){
	int map[BROCKS*3] = {0};
	int clear;
	int trouble = 0;
	printf("ハノイの塔\n\n");
	first_put(map);
	do{
		map_making(map);
		take_line_input(map);
		clear = clear_check(map);
		trouble++;
	}while(clear == 0);
	clear_print(trouble);
	map_making(map);
	return 0;
}

first_put関数

map配列にマクロで指定された数だけの石を左側におきます

void first_put(int *map){
	int i;
	for(i=0; i<BROCKS; i++){
		map[i] = i+1;
	}
	for(i=0; i<BROCKS*2; i++){
		map[BROCKS+i] = 0;
	}
}

map_making関数

マップをmap配列から書き出します
石が置かれていない位置は0としてmap配列に保存していますが
それゆえに0を|に置き換えるという手間が生まれてしまいました 反省

void map_making(int *map){
	int i;
	printf(" |  | \033[31m | \033[0m\n");
	for(i=0; i<BROCKS*3; i++){
		if(i%3 == 0){
			if(map[i/3] == 0){
				printf(" | ");
			}else{
				printf("%2d ",map[i/3]);
			}
		}else if(i%3 == 1){
			if(map[BROCKS+i/3] == 0){
				printf(" | ");
			}else{
				printf("%2d ",map[BROCKS+i/3]);
			}
		}else{
			if(map[BROCKS*2+i/3] == 0){
				printf("\033[31m | \033[0m\n");
			}else{
				printf("%2d \n",map[BROCKS*2+i/3]);
			}
		}
	}
	printf(" ■  ■  ■ \n");
}

last_empty関数

こちらはかなり重要な関数です
0~2のラインとmap配列を受け取り、
map配列のそのラインにおいて最も底の空白のマスを
上から数えたマスとして返します

int last_empty(int *map,int line){
	int i;
	for(i=0; i<BROCKS; i++){
		if(map[BROCKS*line + i] != 0){
			return i-1;
		}
	}
	return BROCKS-1;
}

take_line_input関数

どのラインから石をとるかを入力させるおよびその後の処理を行います
そのラインに石があるのかを確かめる機構もここで作ってあります
ただしlast_empty関数から返される値が一番底を意味する場合は
そりゃあそのラインに石がないということになりますから、
last_empty関数を用いております

void take_line_input(int *map){
	int line;
	int lasempty;
	int brock;
	do{
		do{
			printf("どこの石をとりますか(1~3):");
			scanf("%d",&line);
			line --;
		}while(line<0 || 2<line);
		lasempty = last_empty(map,line);
	}while(lasempty >= BROCKS-1);
	take(map,line,lasempty);
}

take関数

ここで実際にmap配列を変更します

void take(int *map,int line,int lasempty){
	int brock;
	brock = map[BROCKS*line + lasempty+1];
	map[BROCKS*line + lasempty+1] = 0;
	put_line_input(map,brock);
}

put_line_input関数

どのラインに石を置くかを入力させるおよびその後の処理を行います
こちらでもlast_empty関数を用いております

void put_line_input(int *map,int brock){
	int line;
	int lasempty;
	int cannot_put;
	do{
		do{
			printf("どこに石を置きますか(1~3):");
			scanf("%d",&line);
			line --;
		}while(line<0 || 2<line);
		lasempty = last_empty(map,line);
		if(lasempty == BROCKS-1){
			cannot_put=0;
		}else{
			if(brock > map[BROCKS*line + lasempty+1]){
				cannot_put=1;
			}else{
				cannot_put=0;
			}
		}
	}while(cannot_put == 1);
	put(map,line,lasempty,brock);
}

put関数

ここで実際にmap配列を変更します

void put(int *map,int line,int lasempty,int brock){
	map[BROCKS*line + lasempty] = brock;
}

clear_check関数

クリアしているかそうでないかを返します

int clear_check(int *map){
	int i;
	
	for(i=0; i<BROCKS; i++){
		if(map[2*BROCKS + i] != i+1){
			break;
		}
	}
	if(i == BROCKS){
		return 1;
	}
	return 0;
}

clear_print関数

さいごのメッセージを書く関数です

void clear_print(int trouble){
	int shortest = 1;
	int i;
	for(i=0; i<BROCKS; i++){
		shortest *= 2;
	}
	shortest--;
	printf("クリア!\n");
	printf("かかった手数は\t%3d手でした。\n",trouble);
	printf("最善手は\t%3d手でした。\n",shortest);
}

さいごに

ここまで読んでくださりありがとうございました
勉強の参考にしていただけると幸いです
ハノイの塔を自動で解いてくれるコンピュータを考え中です

2
1
2

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
2
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?