スライディングブロックパズルフレームワーク。


少し前に書いたやつを直して公開しました。
15パズルを題材にしたソースは結構あって参考には困らなかったのですが
ピース数固定のものしか見かけなかったので可変可能な構造としてみました。


サンプルはテキスト表示で作ってますが
フレームバッファに描画して計算でタイルを移動させるようなことをすれば
n * n パズルを動的に作ることも可能です。


Sbp (Sliding block puzzle) framework test


サンプル&フレームワーク一式
ttp://page.freett.com/ntr/frmwork/sbp.zip


ソース(これだけではビルドできません。)


main.c

/*---------------------------------------------------------------------------------
	
	Sbp (Sliding Block Puzzle) framework test
	
	version 0.02
	May 10, 2010
	
	By REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <stdio.h>
#include <time.h>
#include <nds.h>
#include "fwmy/Sbp.h"


#define SHUFFLE_NUM 100
#define PIECE_X 4
#define PIECE_Y 4


void drawPanel(Sbp sbp);


//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
	
	consoleDemoInit();
	printf("Sbp (Sliding Block Puzzle)\n framework test\n\nversion 0.02\nMay 10, 2010\n\nBy REGEKATSU");
	
	Sbp sbp = Sbp_CreatePanel(PIECE_X, PIECE_Y);
	
	Sbp_ShufflePiece(sbp, time(NULL), SHUFFLE_NUM);
	
	while(1){
		
		swiWaitForVBlank();
		scanKeys();
		
		drawPanel(sbp);
		
		if(keysDown() & KEY_LEFT){
			Sbp_MovePieceLeft(sbp);
			
		}else if(keysDown() & KEY_RIGHT){
			Sbp_MovePieceRight(sbp);
			
		}else if(keysDown() & KEY_UP){
			Sbp_MovePieceUp(sbp);
			
		}else if(keysDown() & KEY_DOWN){
			Sbp_MovePieceDown(sbp);
			
		}
		
		if(Sbp_IsCompletePanel(sbp)){
			drawPanel(sbp);
			printf("\x01b[17;0H...CLEAR!...");
			sbp = Sbp_DestroyPanel(sbp);
			return 0;
		}
		
	}
	
}

//---------------------------------------------------------------------------------
void drawPanel(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	int x, y;
	
	printf("\x01b[10;0H");
	
	for(y = 0;y < PIECE_Y;y++){
		for(x = 0;x < PIECE_X;x++){
			if(Sbp_GetPieceValue(sbp, x, y) == Sbp_GetPieceBlank(sbp)){
				printf("  ");
			}else{
				printf("%2X", Sbp_GetPieceValue(sbp, x, y));
			}
		}
		printf("\n");
	}
	
}

//---------------------------------------------------------------------------------


Sbp.h

/*---------------------------------------------------------------------------------
	
	Sbp (Sliding Block Puzzle) framework header
	
	version 0.02
	May 10, 2010
	
	By REGEKATSU
	
---------------------------------------------------------------------------------*/

#ifndef _SBP_H_
#define _SBP_H_


typedef struct _Sbp *Sbp;


#ifdef __cplusplus
extern "C" {
#endif


//ゲームパネルの生成・破棄
Sbp Sbp_CreatePanel(int piece_x, int piece_y);
Sbp Sbp_DestroyPanel(Sbp sbp);

//パネルが完成してるかの確認
bool Sbp_IsCompletePanel(Sbp sbp);

//パネル盤面にある現在のピース情報を返す
int Sbp_GetPieceValue(Sbp sbp, int piece_x, int piece_y);

//空ピースとして使用してるピース情報の取得・変更
int Sbp_GetPieceBlank(Sbp sbp);
void Sbp_SetPieceBlank(Sbp sbp, int piece_blank);

//パネル盤面にあるピースをシャッフルする
void Sbp_ShufflePiece(Sbp sbp, int seed, int shuffle_num);

//ピースを上下左右へ移動する
int Sbp_MovePieceLeft(Sbp sbp);
int Sbp_MovePieceRight(Sbp sbp);
int Sbp_MovePieceUp(Sbp sbp);
int Sbp_MovePieceDown(Sbp sbp);

//一番新しく移動(交換)のあったピース情報を返す
int Sbp_GetMovePieceA(Sbp sbp);
int Sbp_GetMovePieceB(Sbp sbp);


#ifdef __cplusplus
}
#endif

#endif	// _SBP_H_


Sbp.c

/*---------------------------------------------------------------------------------
	
	Sbp (Sliding Block Puzzle) framework routine
	
	version 0.02
	May 10, 2010
	
	By REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <stdlib.h>
#include <nds/ndstypes.h>
#include "../libmy/Random.h"
#include "Sbp.h"


typedef struct _Sbp{
	
	int *panel;
	
	int piece_x;
	int piece_y;
	int piece_max;
	int piece_blank;
	
	int piece_a;
	int piece_b;
	
	Random random;
	
}_Sbp;


void sbp_SwapPiece(int *a, int *b);


//---------------------------------------------------------------------------------
Sbp Sbp_CreatePanel(int piece_x, int piece_y) {
//---------------------------------------------------------------------------------
	
	Sbp sbp;
	
	sbp = (Sbp)malloc(sizeof(_Sbp));
	
	sbp->piece_x = (piece_x <= 0) ? 1 : piece_x;
	sbp->piece_y = (piece_x <= 0) ? 1 : piece_y;
	sbp->piece_max = sbp->piece_x * sbp->piece_y;
	sbp->piece_blank = sbp->piece_max - 1;
	
	sbp->panel = malloc(sizeof(int) * sbp->piece_max);
	
	sbp->random = Random_Create(GENERATOR_LCGS);
	
	int i;
	for(i = 0;i < sbp->piece_max;i++){
		sbp->panel[i] = i;
	}
	
	return sbp;
	
}

//---------------------------------------------------------------------------------
Sbp Sbp_DestroyPanel(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return NULL;
	
	sbp->random = Random_Destroy(sbp->random);
	free(sbp->panel);
	free(sbp);
	
	return NULL;
	
}

//---------------------------------------------------------------------------------
bool Sbp_IsCompletePanel(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return false;
	
	int i;
	for(i = 0;i < sbp->piece_max;i++){
		if(sbp->panel[i] != i) return false;
	}
	
	return true;
	
}

//---------------------------------------------------------------------------------
int Sbp_GetPieceValue(Sbp sbp, int piece_x, int piece_y) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	if( (piece_x < 0 || piece_x > sbp->piece_x) || (piece_y < 0 || piece_y > sbp->piece_y) ) return -1;
	
	return sbp->panel[ piece_x + (sbp->piece_x * piece_y) ];
	
}

//---------------------------------------------------------------------------------
int Sbp_GetPieceBlank(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	return sbp->piece_blank;
	
}

//---------------------------------------------------------------------------------
void Sbp_SetPieceBlank(Sbp sbp, int piece_blank) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return;
	
	if(piece_blank < 0 || piece_blank >= sbp->piece_max) return;
	
	sbp->piece_blank = piece_blank;
	
}

//---------------------------------------------------------------------------------
void Sbp_ShufflePiece(Sbp sbp, int seed, int shuffle_num) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return;
	
	int i, rnd;
	
	Random_SetSeed(sbp->random, seed);
	
	for(i = 0;i < shuffle_num;i++){
		
		rnd = Random_GetValue(sbp->random) % 4;
		
		switch(rnd){
			
		case 0:
			Sbp_MovePieceLeft(sbp);
			break;
			
		case 1:
			Sbp_MovePieceRight(sbp);
			break;
			
		case 2:
			Sbp_MovePieceUp(sbp);
			break;
			
		case 3:
			Sbp_MovePieceDown(sbp);
			break;
			
		}
		
	}
	
}

//---------------------------------------------------------------------------------
int Sbp_MovePieceLeft(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	int y;
	for(y = 0;y < sbp->piece_y;y++){
		if( sbp->panel[ sbp->piece_x * y + sbp->piece_x - 1 ] == sbp->piece_blank){
			return sbp->piece_a = sbp->piece_b = 0;
		}
	}
	
	int i;
	for(i = 0;i < sbp->piece_max;i++){
		if(sbp->panel[i] == sbp->piece_blank) break;
	}
	
	sbp->piece_a = i;
	sbp->piece_b = i + 1;
	sbp_SwapPiece(&sbp->panel[sbp->piece_a], &sbp->panel[sbp->piece_b]);
	return 1;
	
}

//---------------------------------------------------------------------------------
int Sbp_MovePieceRight(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	int y;
	for(y = 0;y < sbp->piece_y;y++){
		if( sbp->panel[ sbp->piece_x * y ] == sbp->piece_blank){
			return sbp->piece_a = sbp->piece_b = 0;
		}
	}
	
	int i;
	for(i = 0;i < sbp->piece_max;i++){
		if(sbp->panel[i] == sbp->piece_blank) break;
	}
	
	sbp->piece_a = i - 1;
	sbp->piece_b = i;
	sbp_SwapPiece(&sbp->panel[sbp->piece_a], &sbp->panel[sbp->piece_b]);
	return 1;
	
}

//---------------------------------------------------------------------------------
int Sbp_MovePieceUp(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	int x;
	for(x = 0;x < sbp->piece_x;x++){
		if( sbp->panel[ sbp->piece_x * (sbp->piece_y - 1) + x ] == sbp->piece_blank){
			return sbp->piece_a = sbp->piece_b = 0;
		}
	}
	
	int i;
	for(i = 0;i < sbp->piece_max;i++){
		if(sbp->panel[i] == sbp->piece_blank) break;
	}
	
	sbp->piece_a = i;
	sbp->piece_b = i + sbp->piece_x;
	sbp_SwapPiece(&sbp->panel[sbp->piece_a], &sbp->panel[sbp->piece_b]);
	return 1;
	
}

//---------------------------------------------------------------------------------
int Sbp_MovePieceDown(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	int x;
	for(x = 0;x < sbp->piece_x;x++){
		if( sbp->panel[x] == sbp->piece_blank){
			return sbp->piece_a = sbp->piece_b = 0;
		}
	}
	
	int i;
	for(i = 0;i < sbp->piece_max;i++){
		if(sbp->panel[i] == sbp->piece_blank) break;
	}
	
	sbp->piece_a = i - sbp->piece_x;
	sbp->piece_b = i;
	sbp_SwapPiece(&sbp->panel[sbp->piece_a], &sbp->panel[sbp->piece_b]);
	return 1;
	
}

//---------------------------------------------------------------------------------
int Sbp_GetMovePieceA(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	return sbp->piece_a;
	
}

//---------------------------------------------------------------------------------
int Sbp_GetMovePieceB(Sbp sbp) {
//---------------------------------------------------------------------------------
	
	if(sbp == NULL) return -1;
	
	return sbp->piece_b;
	
}

//---------------------------------------------------------------------------------
void sbp_SwapPiece(int *a, int *b) {
//---------------------------------------------------------------------------------
	
	int temp;
	
	temp = *a;
	*a = *b;
	*b = temp;
	
}

//---------------------------------------------------------------------------------