[C++] 251 SDL : テトリスの最高スコアをxmlファイルに保存

[M1 Mac, Monterey 12.6.3, clang 13.0.0, SDL 2.26.2, ChatGPT Plus, NO IDE]

製作中のテトリスはアプリ起動中の最高スコアを表示していて、閉じるとデータは消えてしまいます。

そこでxmlファイルに最高スコアを保存し、起動の度にxmlファイルを読み込み、ゲームオーバー時に更新するようにしました。同時にバックアップファイルも作成しています。

xmlファイル作成・読込はJavaアプリで扱ったことはありますが、今回はChatGPTを使ってサクッと作りました。Homebrewでインストールしたpugixmlライブラリを使っています。

ある程度プログラミングが分かる方はChatGPT Plusを活用されることをお勧めします。学習・作業効率がこれまでと段違いです。

#include "pugixml.hpp"

extern string xmlFile;
extern string xmlFileBackup;

int readXML(){
	pugi::xml_document doc;

	cout << "readXML関数 xmlFile: " << xmlFile << endl;

    // XMLファイルを読み込む
    pugi::xml_parse_result result = doc.load_file(xmlFile.c_str());

    if (!result) {
        std::cerr << "XMLの読み込みに失敗しました。" << std::endl;
        return -1;
    }

    // ルートノードを取得する
    pugi::xml_node root = doc.child("properties");

    // HISCOREのエントリーを取得する
    pugi::xml_node hiscore_node = root.find_child_by_attribute("entry", "key", "HISCORE");

    // エントリーの値を取得する
    hiScore = hiscore_node.text().as_int();

    std::cout << "HISCOREの値は" << hiScore << "です。" << std::endl;

	return hiScore;
}

int writeXML(){
	pugi::xml_document doc;

	cout << "writeXML関数 xmlFile: " << xmlFile << endl;

    // XMLファイルを読み込む
    pugi::xml_parse_result result = doc.load_file(xmlFile.c_str());

    if (!result) {
        std::cerr << "XMLの読み込みに失敗しました。" << std::endl;
        return -1;
    }

    // ルートノードを取得する
    pugi::xml_node root = doc.child("properties");

    // HISCOREのエントリーを取得する
    pugi::xml_node hiscore_node = root.find_child_by_attribute("entry", "key", "HISCORE");

    // エントリーの値を書き換える
    hiscore_node.text().set(hiScore);

    // XMLファイルを上書きする
    doc.save_file(xmlFile.c_str());

    std::cout << "更新するHISCOREの値は" << hiScore << "です。" << std::endl;

	// ファイルを読み込む
    std::ifstream file(xmlFile);
    if (!file.good()) {
        std::cerr << "ファイルの読み込みに失敗しました。" << std::endl;
        return -1;
    }

    // バックアップファイルを作成する
    std::ofstream backup(xmlFileBackup);
    if (!backup.good()) {
        std::cerr << "バックアップファイルの作成に失敗しました。" << std::endl;
        return -1;
    }

    // バックアップファイルにデータを書き込む
    backup << file.rdbuf();

    // ファイルを閉じる
    file.close();
    backup.close();

    std::cout << "バックアップファイルを作成しました。" << std::endl;
}

[C++] 250 SDL : テトロミノが偏って生成しないようにする Tetris

[M1 Mac, Monterey 12.6.3, clang 13.0.0, SDL 2.26.2, ChatGPT Plus, NO IDE]

テトリスでテトロミノが偏って生成しないようにするため、ワールドルールに従って7種類あるテトロミノ番号を程よく生成する関数を作成しました。

for文の作成にはChatGPTにも手伝ってもらいました。

書いていて気がつきましたが、配列内要素が残り1つになったらその数を自動的に戻り値にすればいいですね。CPUへの負荷も減ります。改良版として追記しておきます。

vector<int> arr;
int GeneratorCount;

int TetroTypeGenerator()
{	
	int tetroType;

	if (GeneratorCount == 0){
		arr = {0, 1, 2, 3, 4, 5, 6};
	}

	while(1){
		tetroType = rand() % kNumTetrominoTypes;

		if (arr.size() == 0){
			arr = {0, 1, 2, 3, 4, 5, 6};
			cout << "テトロミノ配列が空になったのでリセットしました" << endl;
		}

		for (auto it = arr.begin(); it != arr.end(); ) {
			if (*it == tetroType) {
				it = arr.erase(it);

				cout << "tetroType: " << to_string(tetroType) << endl;

				GeneratorCount++;
				return tetroType;

			} else {
				it++;
			}
		}
	}
}
tetroType: 2
tetroType: 4
tetroType: 1
tetroType: 0
tetroType: 3
tetroType: 5
tetroType: 6
テトロミノ配列が空になったのでリセットしました
tetroType: 6
tetroType: 2
tetroType: 1
tetroType: 5
tetroType: 4
tetroType: 0
tetroType: 3
テトロミノ配列が空になったのでリセットしました
tetroType: 5
tetroType: 3
tetroType: 0

以下、改良版

vector<int> arr;
int GeneratorCount;

int TetroTypeGenerator()
{	
	int tetroType;

	if (GeneratorCount == 0){
		arr = {0, 1, 2, 3, 4, 5, 6};
	}

	while(1){
		tetroType = rand() % kNumTetrominoTypes;

		if (arr.size() == 0){
			arr = {0, 1, 2, 3, 4, 5, 6};
			cout << "テトロミノ配列が空になったのでリセットしました" << endl;
		} else if (arr.size() == 1){
			tetroType = arr.front();
			arr = {};

			cout << "tetroType残り1: " << to_string(tetroType) << endl;

			GeneratorCount++;
			return tetroType;
		}

		for (auto it = arr.begin(); it != arr.end(); ) {
			if (*it == tetroType) {
				it = arr.erase(it);

				cout << "tetroType: " << to_string(tetroType) << endl;

				GeneratorCount++;
				return tetroType;

			} else {
				it++;
			}
		}
	}
}
tetroType: 2
tetroType: 4
tetroType: 0
tetroType: 3
tetroType: 1
tetroType: 5
tetroType残り1: 6
テトロミノ配列が空になったのでリセットしました
tetroType: 3
tetroType: 1
tetroType: 2
tetroType: 0
tetroType: 6
tetroType: 5
tetroType残り1: 4
テトロミノ配列が空になったのでリセットしました
tetroType: 1
tetroType: 2
tetroType: 3

[C++] 249 FLTK : Fl_Menu_Itemの書式

[M1 Mac, Monterey 12.6.3, clang 13.0.0, FLTK 3.8.1, ChatGPT Plus, NO IDE]

SFTP通信アプリのメンテナンスです。即時ファイル移動ができないiCloudの代替ツールとして開発しています。PC間のファイル移動が瞬時にできます(Windows機とはSamba接続)。

アプリに新たなPCを登録する際、Fl_Menu_Itemの書き方を間違えたためにプルダウンメニュークリック時に落ちるようになってしまいました。以前からクセのある書式にトラブルの可能性を感じていたのでまとめておきます。

Fl_Menu_ItemオブジェクトはArrayを作成する際、最後にヌルポインタを入れることでArrayの終了が分かるようになっています。これにより要素数を扱わずに済みます。要素数を入れても問題はないですが、最後のヌルポインタもカウントした数値を使用します。

// 要素数を使わない場合
Fl_Menu_Item pc_type[] = {
        {"Mac mini Intel"},
        {"MacBook Air M1"},
        {"MacBook Intel"},
        {"Windows11PC"},
        {"Windows10PC"},
        {"LinuxPC"},
        {0}
};

// 要素数を使う場合
Fl_Menu_Item pc_type[7] = {
        {"Mac mini Intel"},
        {"MacBook Air M1"},
        {"MacBook Intel"},
        {"Windows11PC"},
        {"Windows10PC"},
        {"LinuxPC"},
        {0}
};

// 最後のヌルポインタは省略可能(見た目では数が合わない)
Fl_Menu_Item pc_type[7] = {
        {"Mac mini Intel"},
        {"MacBook Air M1"},
        {"MacBook Intel"},
        {"Windows11PC"},
        {"Windows10PC"},
        {"LinuxPC"}
};