はじめに
こんにちは 高専1年、ロボコン部部員です
今回はC言語でスライドパズルを作ったので共有します
いつもより綺麗に作ることができたのでぜひ楽しんでいってください
プレイ画像
コード解説
冒頭部分
マクロでは
- ONE_SIDE → マップの一辺
- DIFF→ マップのシャッフル回数
を表しています
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#define ONE_SIDE 4
#define DIFF 10
int squared(int num);
void map_init(int *map);
void map_print(int map[ONE_SIDE * ONE_SIDE]);
void main_input(int *map);
int input(void);
int can_move(int *map,int ans);
void map_change(int *map,int ans);
int emp_cell_return(int map[ONE_SIDE * ONE_SIDE]);
int game_check(int map[ONE_SIDE * ONE_SIDE]);
void last_print(void);
※conio.hというのはwindowsの環境依存ですのでお気を付けください
main関数
ゲームの基本進行と関数の呼び出しを行います
int main(void){
int map[ONE_SIDE * ONE_SIDE] = {0};
map_init(map);
do{
map_print(map);
main_input(map);
}while(game_check(map) == 0);
last_print();
map_print(map);
return 0;
}
squared関数
マクロで定義されたONE_SIDEを二乗するためだけに作られた関数です
int squared(int num){
return num * num;
}
map_init関数
map配列の初期化を行います
ここでマクロ:DIFFの情報からマップをシャッフルします
見たことのない関数が呼び出されていますが
後で説明しますので心配ありません
void map_init(int *map){
int init_i;
int ans;
int randnum[4] = {ONE_SIDE,-ONE_SIDE,1,-1};
for(init_i=0; init_i<squared(ONE_SIDE); init_i++){
map[init_i] = init_i+1;
}
map[squared(ONE_SIDE)-1] = 0;
for(init_i=0; init_i<DIFF; init_i++){
do{
ans = randnum[rand()%4];
}while(can_move(map,ans) == 0);
map_change(map,ans);
}
}
map_print関数
map配列からマップを表示します
void map_print(int map[ONE_SIDE * ONE_SIDE]){
int print_i;
printf("\n");
for(print_i=0; print_i<squared(ONE_SIDE); print_i++){
if(map[print_i] == 0){
printf("[ ]");
}else{
printf("[%2d]",map[print_i]);
}
if(print_i%ONE_SIDE == ONE_SIDE-1){
printf("\n");
}
}
printf("\n");
}
main_input関数
実際に入力させる機構の軸となる関数です
can_move関数やmap_change関数はmap_init関数でも使う必要があったため、
入力の工程を入れるための、この関数が必要になったのです
void main_input(int *map){
int ans;
do{
ans = input();
}while(can_move(map,ans) == 0);
map_change(map,ans);
}
input関数
ここでプレイヤーに実際に入力してもらいます
int input(void){
int ans = _getch();
if(ans == 0 || ans == 0xE0){
ans = _getch();
}
switch(ans){
case 0x48:
return -ONE_SIDE;
break;
case 0x50:
return ONE_SIDE;
break;
case 0x4D:
return 1;
break;
case 0x4B:
return -1;
break;
}
}
※_getch関数はconio.hによるもの、つまりはこちらもwindowsの環境依存です
お気を付けください
can_move関数
動かせる方向だったならば1を、そうでなければ0を返す関数です
emp_cell_return関数から得られる、『空白マス』の位置から判断します
int can_move(int *map,int ans){
int emp_cell = emp_cell_return(map);
int NG[4] = {0};
int check_i;
if(0<=emp_cell && emp_cell<=ONE_SIDE-1){
NG[0] = ONE_SIDE;
}else if(ONE_SIDE*(ONE_SIDE-1)<=emp_cell && emp_cell<=squared(ONE_SIDE)-1){
NG[1] = -ONE_SIDE;
}
if(emp_cell%ONE_SIDE == 0){
NG[2] = 1;
}else if(emp_cell%ONE_SIDE == ONE_SIDE-1){
NG[3] = -1;
}
for(check_i=0; check_i<4; check_i++){
if(NG[check_i] == ans){
return 0;
}
}
return 1;
}
map_change関数
実際にmap配列を変更する関数です
void map_change(int *map,int ans){
int emp_cell = emp_cell_return(map);
map[emp_cell] = map[emp_cell - ans];
map[emp_cell - ans] = 0;
}
emp_cell_return関数
『空白マス』の位置を返す関数です
int emp_cell_return(int map[ONE_SIDE * ONE_SIDE]){
int check_i;
for(check_i=0; check_i<squared(ONE_SIDE); check_i++){
if(map[check_i] == 0){
return check_i;
}
}
return 0;
}
game_check関数
ゲームクリアしたかどうかを判断する関数です
クリアしたときには1を、そうでないときは0を返します
int game_check(int map[ONE_SIDE * ONE_SIDE]){
int check_i;
for(check_i=0; check_i<squared(ONE_SIDE)-1; check_i++){
if(map[check_i] != check_i+1){
return 0;
}
}
return 1;
}
last_print関数
クリアしたことを表示するためだけの関数です
これ要るんでしょうか…?
void last_print(void){
printf("\x1b[33mクリア!おめでと!!\x1b[0m\n");
}
さいごに
ここまで読んでくださりありがとうございました
参考になると嬉しいです
