はじめに
こんにちは 高専1年のロボコン部部員です
今回は完成したハノイの塔を共有します
かなり単純なコードですが
いつもより綺麗にまとめることができたのでぜひ見ていってください
プレイ画像
コード解説
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);
}
さいごに
ここまで読んでくださりありがとうございました
勉強の参考にしていただけると幸いです
ハノイの塔を自動で解いてくれるコンピュータを考え中です