質問するログイン新規登録
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

意見交換

24回答

1227閲覧

C言語で将棋のゲームを作成

todasan

総合スコア94

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

1クリップ

投稿2025/09/26 05:01

0

1

以下のようなソースで、C言語から将棋のゲームを途中まで作成しています。
以下はvisualstdioで動作します。添付画像では9 9 3 9を入力して、先歩を
移動して後歩を取っています。プログラムの構造的には他にいいアイデアは、
ないでしょうか。C言語の勉強により、さくっと作りましたので、構造的に、
いいアイデアがあれば、お聞きしたいです。将棋の盤をもっと現実的にする
いい方法があれば、何かお聞きしてもよろしいですか。

#pragma once typedef struct koma_info { int tate; // 位置_縦 int yoko; // 位置_横 int sente; // 先手_後手 char koma[10]; // 駒の種類 } person; typedef struct koma_shurui { char koma[10]; // 駒の種類 } motikoma;

shougi_shisaku.cpp

// shougi_shisaku.cpp : このファイルには 'main' 関数が含まれています。プログラム実行の開始と終了がそこで行われます。 // #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <iostream> #include "shougi_shisaku.h" extern void explode(const char*, char*, int); // 項目を取り出す person data[81]; // 駒のデータの読み込み person dataretu[81]; // 駒のデータのコピー先 motikoma sente[20]; //先手の持ち駒 motikoma gote[20]; //先手の持ち駒 char kuuhaku[] = "  "; char tate_str[] = "一二三四五六七八九"; char koma_str_aite[10] = {}; int tate_mae = 0, yoko_mae = 0, tate_ato = 0, yoko_ato = 0, sente_cnt = 0,gote_cnt = 0 ; void banmen_hyouji() { int readtate, readyoko, coma_cnt = 0; char sub_str[4]; printf("将棋盤\n"); printf("|9    |8    |7    |6    |5    |4    |3    |2    |1     \n"); printf("--------------------------------------------------------------------------------------------\n"); for (readtate = 1; readtate < 10; readtate++) { for (readyoko = 9; readyoko > 0; readyoko--) { if (dataretu[coma_cnt].tate == readtate && dataretu[coma_cnt].yoko == readyoko && dataretu[coma_cnt].koma[0] != '\0') { // 駒の情報がある時 printf("|%s ", &dataretu[coma_cnt].koma[0]); coma_cnt++; } else { // 駒の情報がない時 printf("|%s ", kuuhaku); coma_cnt++; } if (readyoko == 1) { // 縦の駒番号を表示する。 // strから部分文字列を切り出す strncpy_s(sub_str, tate_str + (readtate - 1) * 2, 2); sub_str[3] = '\0'; // 切り出した部分の終端文字を追加 printf("|%s ", sub_str); } } printf("\n"); printf("--------------------------------------------------------------------------------------------\n"); } printf("|先手の持ち駒 %s\n", sente[sente_cnt - 1].koma); } void taikyoku_kaisi() { int koma_data,idoumotosenteno,idousakisenteno; char koma_str[10] = {}; size_t length = 0; printf("***先手の番です***\n"); printf("***どの地点を動かしますか***\n"); scanf_s("%d%d", &tate_mae,&yoko_mae); printf("***どこにを動かしますか***\n"); scanf_s("%d%d", &tate_ato, &yoko_ato); for (koma_data = 0; koma_data < 81; koma_data++){ if (dataretu[koma_data].tate == tate_mae && dataretu[koma_data].yoko == yoko_mae) { length = strlen(dataretu[koma_data].koma); idoumotosenteno = dataretu[koma_data].sente; } if (dataretu[koma_data].tate == tate_ato && dataretu[koma_data].yoko == yoko_ato){ length = strlen(dataretu[koma_data].koma); idousakisenteno = dataretu[koma_data].sente; printf("|%d \n", length); } } // 自分の駒があるので、移動できない。 if (length != 0 && idoumotosenteno == idousakisenteno) { goto skip; } // 移動する駒の文字列を保存する。 for (koma_data = 0; koma_data < 81; koma_data++){ if (dataretu[koma_data].tate == tate_mae && dataretu[koma_data].yoko == yoko_mae){ memcpy((void *)koma_str, &dataretu[koma_data].koma[0], 4); memset((void *)dataretu[koma_data].koma, '\0', 10); } } // 駒を移動先の文字列に格納する。 for (koma_data = 0; koma_data < 81; koma_data++){ if (dataretu[koma_data].tate == tate_ato && dataretu[koma_data].yoko == yoko_ato){ memcpy((void*)sente[sente_cnt].koma, (const void*)dataretu[koma_data].koma, 10); // printf("|koma_str_aite%s \n", koma_str_aite); sente_cnt = sente_cnt + 1; memcpy((void*)dataretu[koma_data].koma, (const void*)koma_str, 10); } } skip: return; } int main() { FILE* fp; char buf[512], * cp; int tatehoukou; printf("\n***将棋ゲーム***\n"); fopen_s(&fp,"shougi_banmen.csv", "r"); // 将棋のファイルを開く if (fp == NULL) goto END; // ファイルを開けない tatehoukou = 0; memset(&data[0], '\0', sizeof(data)); // データの全文字をNULLに memset(&sente[0], '\0', sizeof(sente)); // データの全文字をNULLに memset(&gote[0], '\0', sizeof(gote)); // データの全文字をNULLに while (1) { cp = fgets(buf, 256, fp); // 1レコードを読む if (cp == NULL) break; // EOF explode(",", buf, tatehoukou); // csvデータを1行ずつ、項目を取り出す tatehoukou = tatehoukou + 1; if (tatehoukou == 9) break; } fclose(fp); // 将棋のファイルを閉じる // memcpyを使ったコピー memcpy(&dataretu, &data, sizeof(person)*81); banmen_hyouji(); taikyoku_kaisi(); banmen_hyouji(); END:; }

shougi_banmen.csv

後香,後桂,後銀,後金,後王,後金,後銀,後桂,後香, ,後飛,,,,,,後角,, 後歩,後歩,後歩,後歩,後歩,後歩,後歩,後歩,後歩, ,,,,,,,,, ,,,,,,,,, ,,,,,,,,, 先歩,先歩,先歩,先歩,先歩,先歩,先歩,先歩,先歩, ,先角,,,,,,先飛,, 先香,先桂,先銀,先金,先王,先金,先銀,先桂,先香,

explode.cpp

#include <stdio.h> #include <iostream> #include "shougi_shisaku.h" void explode(const char*, char*, int); // 項目を取り出す extern person data[81]; // 駒のデータの読み込み int koma_cnt = 0; void explode( /*----------------------------------*/ /* CSVデータから項目を取り出す */ /*----------------------------------*/ const char* kugiri, // 区切り文字 char* buf, // CSVの1レコード int tatehoukou) { char* cp0, * cp; int yokohoukou = 0, len; cp0 = buf; // CSVデータの先頭アドレス for (yokohoukou = 0; yokohoukou < 9; yokohoukou++) { if (*cp0 == 0x22) cp0++; // 最初の"(0x22)を除く cp = strstr(cp0, kugiri); // 区切り文字を検索 if (cp == NULL) break; // 区切り文字なし len = cp - cp0; // 項目の文字数 if (*(cp - 1) == 0x22) len--; // 最後の"(0x22)を除く if (len > 0) // 項目あり { memcpy(&data[koma_cnt].koma[0], cp0, len); // 項目の文字列をコピー data[koma_cnt].tate = tatehoukou + 1; data[koma_cnt].yoko = 9 - yokohoukou; if (strncmp(data[koma_cnt].koma, "先", 2) == 0){ data[koma_cnt].sente = 1; } else { data[koma_cnt].sente = 2; } koma_cnt = koma_cnt + 1; }else{ data[koma_cnt].tate = tatehoukou + 1; data[koma_cnt].yoko = 9 - yokohoukou; koma_cnt = koma_cnt + 1; } cp0 = cp + 1; // 次の文字のアドレス } }

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

回答24

#1

fana

総合スコア12298

投稿2025/09/26 08:41

編集2025/09/26 08:42

コードを念入りに見ているわけではありませんが,
盤の各マスに関して「何の駒があるのか(あるいは何もないのか)」という情報(すなわち駒の種類)をどう扱っているのかがイマイチわかりません.
ひょっとしたら「後銀」みたいな文字列が「ここに銀がある」という情報の実装手段になっているのでしょうか?
もしそうだとしたら,何か適当な数値(例えば enum だとか)を用いた方がいろいろと楽になりませんか?

あと,表示に関してはここではわりとどうでも良いかもしれませんが,「先」「後」という文字だと,駒が入り乱れてくると見にくそうかな,と思います.
(例えば「▲」「▽」とかの方がぱっと見で見分けが付くかな? みたいな)

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#2

Ham-tail

総合スコア19

投稿2025/09/26 09:21

編集2025/09/26 09:23

途中っぽいからあまり言うのもアレだがざっと見た感じ

  • 駒の定義(移動範囲等)が書いてない
  • 持ち駒が打てない
  • 勝利条件が書いてない
    などいろいろ必要

構造的なアドバイスが欲しいってことなんで

  1. 持ち駒の最大が20では足りなくなる
  2. 盤面を表すのに一次元配列を使ってるのが分かりにくいと思う。盤面と合わせて二次元にしよう
  3. 先手の持ち駒「後歩」は分かりずらすぎる
  4. 難しいと思うが出来ればマウスかキーボード(矢印)で選択したい

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#3

todasan

総合スコア94

投稿2025/09/26 09:25

fana さん
ご指摘ありがとうございます。「後銀」みたいな文字列がここにあるという実装で、9×9のマスを
全て見て、管理しています。enumをどのように用いるのですか。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#4

todasan

総合スコア94

投稿2025/09/26 09:30

Ham-tail さん
ご指摘ありがとうございます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#5

jimbe

総合スコア13427

投稿2025/09/26 09:45

編集2025/09/26 09:46

最初のご質問の時にコードをコピペして弄ろうとしたらcの環境が死んでいてjavaに移植(?)しつつ構造を見ていました。(前振りが長い)

1つ。なぜ構造体名が person 何でしょう。
1つ。person に縦横がありますが、必要でしょうか。
1つ。 explode 関数でダブルクオットを意識する処理をされていますが、必要でしょうか。
1つ。変数名とかローマ字はやはり変な感じです。横や縦はx,yで良いのではとか。
1つ。グローバルな変数は使わず、関数へのパラメータと返り値で上手くやり取りするようにしてみてください。例えば explode 関数内で data 配列に格納する処理を行うのは、適切とは言い難いです。

具体的なコードで示したい所ですが、動かせないのですみません。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#6

todasan

総合スコア94

投稿2025/09/26 10:01

jimbe さん
ご指摘ありがとうございます。
personは適当につけたので、気にしてはいません。
personの縦、横で、将棋の駒の位置の9×9を管理しています。
explode 関数のダブルクォットはcsvのデータが""で、囲まれた時の処理です。確かに
テキストで開くと""はないので、不用かもしれません。
explode 関数はcsvデータを1行ずつdataに格納していて、9×9の将棋データをdataで作成しています。

例えば explode 関数内で data 配列に格納する処理を行うのは、適切とは言い難いです。
csvファイルから1行ずつdataに格納していますが、何か適切な方法としては、日本語で簡単でいいので、
聞いてもよろしいですか。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#7

fana

総合スコア12298

投稿2025/09/26 10:03

編集2025/09/26 10:10

enumをどのように用いるのですか

別に enum じゃなくても何でも良いですが,
例えば 9x9 マスの盤面データを int Ban[9*9]; で保持するなら,各マスの情報を int なる数値で表すという話です.

どの値が何を示すのかは適当に(あなたにとって実装上便利な形に)決めればよいでしょう.
例えば,

  • 何も駒が無いマスは 0
  • 先手の歩がいるマスは 1
  • 先手の香がいるマスは 2
  • ...
  • 後手の歩がいるマスは 101
  • 後手の香がいるマスは 102
  • ...

とかした場合,値を見れば駒の種類のほかに,先手の駒なのか後手の駒なのかもわりと簡単に判別できそうですよね.
(ただの話としての例なので,これが良い定義方法だとは言いませんが)

※どうでもいいけど,駒の種類を表す定数を用意する場合,「歩」とか「銀」とかはなんと命名すればよいのだろう? "HU" とか "GIN" とかだとなんか見にくい気がするなぁ.

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#8

u2025

総合スコア103

投稿2025/09/26 10:51

編集2025/09/26 13:13

回答の意図あってるかわかりませんが、とりあえず9*9の盤面に王だけ配置して、王の選択と移動先を決めるというシンプルな操作のプログラムを作ってみたら王を好き勝手動かせるので楽しいのでは?と思いました。
そこからさらに壁の衝突判定とか、敵の駒を取得する判定とか作っていくみたいな。
そこまでやれば駒のバリエーションを増やすだけで作成できたりしないのかな?

あと、なんでこう思ったのか自分でも謎なのですが、
player1[9][9]とplayer2[9][9]みたいな配列にして、どっち陣営の駒がどこにあるのかを保持すれば、盤面で全部を表す必要がなくなってシンプルじゃないかな?と思った。配列のサイズがプレイヤーの倍されちゃうし、現実的にこの方法は必須ではないとは思うが。

また、入力に関して言えば、
どの駒を選択できるのか、
選択した駒がどこに移動できるのか、はあらかじめ計算できると思うので表示したほうが親切だろうと思った。

「位置データ」をデータとして持つのはいいけど、インデックスでアクセスしたいと思うのが普通だろうから、縦横をデータとして表すのは悪手ではないかと直感的には思った。
整理して考えてみると多分、持ち駒って概念があって、20コマをイテレートすれば全部の駒を表せられるから9*9を見るより早いみたいなことなのかもしれないが、そもそもとして「空のマス」を概念的には保持しない(※概念的に保持というのはデータとして保持せずとも表示上存在するという事実を認めないといけないという意味)と盤面を出しようがないから、効果が薄くて使いずらくなってる気がする。(ただ、表示ロジックを見る限りそういう目的で定義されて無さそうでもある)
ん?読み方間違えているのか?なに書いているかよくわからん。

実装があるのか分からないけど、拡張するときに面倒に感じるだろうから駒のいける位置は構造体を使うなら構造体で表現するのがベターな気がする。

例えば歩兵なら動ける方向は[x,y]であらわすとして行けるのが[[0,1]]とれる数が配列の数である1とかになるのかな。
手前からならy座標が+で奥からなら反転みたいなのもやらないとだけど。
王なら8個行けるから、
[
[0, 1], // 前
[1, 0], // 右(インデックス軸)
[-1, 0], // 左
[0, -1], // 後ろ
[1, 1], // 前+右
[-1, 1], // 前 + 左
[-1, -1], // 左 + 後ろ
[1, -1] // 右 + 後ろ
]
で配列の数の8も持っておく、みたいな。

やってないからできるかわからないですが。
C言語初心者なので間違ってたらすみません。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#9

u2025

総合スコア103

投稿2025/09/26 10:52

※どうでもいいけど,駒の種類を表す定数を用意する場合,「歩」とか「銀」とかはなんと命名すればよいのだろう? "HU" とか "GIN" とかだとなんか見にくい気がするなぁ

連番で良い気がしています。その定数って初期化ロジック以外で登場しないと思う。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#10

hiroki-o

総合スコア1642

投稿2025/09/26 14:47

編集2025/09/26 14:59
  • 結局、Visual Studioと「Visual Studio Code + GCC」のどちらで作ることにしたのでしょうか? それとも、両方でビルドできることを目指しているのでしょうか?
  • 文字コードは、Shift_JISとUTF-8のどちらで作ることにしたのでしょうか?
    (ソースファイル、CSVファイル、内部処理、出力)
  • 中身は完全にCなので、拡張子は*.cに変更、両方とも#include <iostream>は撤去、explode.c#include <string.h>を追加してください。
    (現状はC++コンパイラのC互換機能でビルドしている状態)
  • 1個だけ、C++の関数が使用されています。shougi_shisaku.cstrncpy_sで、CとC++では引数の数が異なります。以下のように修正してください。

strncpy_s(sub_str, sizeof(sub_str), tate_str + (readtate - 1) * 2, 2);

  • 次の行のsub_str[3] = '\0';は不要です。strncpy_sは自動的にNULL終端が付きます。しかも、2byteコピーしているのに、4byte目にNULL終端を入れても意味が無いです。
  • 上記以外で、文字列のコピーにstrcpyではなくmemcpyを使用する理由は?

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#11

todasan

総合スコア94

投稿2025/09/26 19:15

fana さん
ご指摘ありがとうございます。enumについては、途中まで作っているので、保留にします。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#12

todasan

総合スコア94

投稿2025/09/26 19:22

u2025 さん
ご指摘ありがとうございます。
移動範囲については、作ろうと考えていたため、
9x9は配列にしました。駒の種類の定数はどのように使うイメージですか。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#13

todasan

総合スコア94

投稿2025/09/26 19:28

編集2025/09/26 19:34

hiroki-o さん
ご指摘ありがとうございます。
visualstudioとgccで、現状、両方ある程度動きます。visualstudioはシフトジス、gccはutf-8で作ろうといます。memcpy、strcpyは勉強のため、適当に選択しました。gccの方の表示がおかしかったので、バグ探しをしていました。答えを見つけていただき、ありがとうございます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#14

thkana

総合スコア7769

投稿2025/09/27 01:03

personは適当につけたので、気にしてはいません。

気にしてください。不適切な変数名は思考の混乱を招き、バグの温床となるものと思ってください。
また、ソースコードは、何をしようとしたか、プログラマの思考を表すドキュメントである、という側面もあります。門外不出なら好きにしていいですけれど、他人にみせて相談するなら、それなりに体裁を整えてください。体裁を整えるだけでバグが見つかり解消することだってなくはないのです。

enum云々は、「enumにする」ことが本論ではなくて、シンボルにすることによって情報が圧縮できたり、汎用性を持たせられるから、と考えましょう。将棋の駒の種類はたかだか8+5種類しかないのに、駒の名前をそのまま記載したらその記録に数バイトが必要になります。まぁ、今どきのコンピュータであれば大した負担ではありませんが...しかし、情報を圧縮するということは「本質を取り出す」ということに繋がっています。今回すでにsjisとUTF8で文字コードが違って...という話が出てきています。さて、では棋譜をセーブ/ロードすることにして、今のように駒の名前をそのままデータとして書き出すとしたら...sjis版とUTF8版で同じ棋譜が違うデータで書き出されることになり、それがどちらなのか管理したり場合によっては変換しなきゃならなかったり、ということになります。それは、例えば「歩である」という本質だけが必要なところに"歩"の文字コードを影響させてしまったが故に発生する手間といっていいでしょう。ここを、抽象化して歩なら1、香車は2とかシンボル化しておけばそういう違いの影響を排除できます。文字コードなどの外部事情に影響されやすい画面表示処理やデータ入出力を処理本体とは分離する、というのはプログラミングにおけるテクニックのひとつです。また、そういう圧縮の過程で(例えば歩がと金に)'成る'関係を(例えばどこかのビットを立てるなど)駒の性質として持たせたりもできるかも知れません。どちらの持ち駒なのか、というのも本質と言うより性質ですよね。そういうのをどう手際よく扱うか、というのは腕の見せ所のひとつでしょう。

あなたがプログラムを作っているのはなんのためでしょう?「動くプログラムができればよい」のか、それともプログラミングの勉強の一環であるのか...勉強の一環であるなら、面倒くさがって適切な方向に舵を切るのを遠慮すべきではないと思いますけれど。(いやまぁ、走るだけ走って、あとから振り返ってみるというのもありですけれど)

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#15

hiroki-o

総合スコア1642

投稿2025/09/27 01:32

#13
Visual Studioは、設定でUTF-8に対応した開発が可能です。
それでも、Visual StudioのCコンパイラとGCCの違いを探りたいなら、並行して開発するのは自由ですが。
私なら、どちらかに1本化します。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#16

jimbe

総合スコア13427

投稿2025/09/27 04:26

編集2025/09/27 04:45

#6

person に関しましては#14 thkana さんの最初の一言と同じ意見です。

explode 関数に関してですが、 c の古い関数で strtok というのがあります。
珍しく状態を持つ関数で使い方が若干難しく、英文を英単語に分ける用途向きですが "分割" という点で csv のような文字列行の解析にも使われることがありました。
詳細はここで説明するよりドキュメントやサンプル等を検索・御覧頂くのが良いでしょう。
で、その strtok は残念ながら『デリミタが並ぶ場合は1つのデリミタとして扱う』という仕様の為、件の csv には使えません。ですがそのインターフェース(「関数を呼ぶ度に次の文字列が取り出される」)は使えます。
以下は strtok 的な explode 関数を実験した例です。(ファイル読み込みの代わりに配列を使っています。)

c

1#include <stdio.h> 2#include <string.h> 3 4static char* exploding_addr = NULL; 5static const char DELIMITER = ','; 6 7char *explode(char *line) { 8 if(line != NULL) { 9 exploding_addr = line; 10 } else if(exploding_addr == NULL) { 11 return NULL; 12 } 13 14 char *start = exploding_addr; 15 for( ; ; ++exploding_addr) { 16 if(*exploding_addr == '\0') { 17 exploding_addr = NULL; 18 break; 19 } 20 if(*exploding_addr == DELIMITER) { 21 *exploding_addr++ = '\0'; 22 break; 23 } 24 } 25 return start; 26} 27 28int main(void){ 29 const char *csv[] = { 30 "後香,後桂,後銀,後金,後王,後金,後銀,後桂,後香", 31 ",後飛,,,,,,後角,", 32 "後歩,後歩,後歩,後歩,後歩,後歩,後歩,後歩,後歩", 33 ",,,,,,,,", 34 NULL //EOD 35 }; 36 37 int no=0; 38 char line[256]; 39 40 for(int i=0; csv[i]!=NULL; ++i) { 41 strcpy(line, csv[i]); 42 for(char *token=explode(line); token!=NULL; token=explode(NULL)) { 43 printf("%d: '%s'\n", no, token); 44 //data[no].tate = no / 9; 45 //data[no].yoko = 9 - (no % 9); 46 //strcpy(data[no].koma, token); 47 ++no; 48 } 49 } 50}
0: '後香' 1: '後桂' 2: '後銀' 3: '後金' 4: '後王' 5: '後金' 6: '後銀' 7: '後桂' 8: '後香' 9: '' 10: '後飛' 11: '' 12: '' 13: '' 14: '' 15: '' 16: '後角' 17: '' 18: '後歩' 19: '後歩' 20: '後歩' 21: '後歩' 22: '後歩' 23: '後歩' 24: '後歩' 25: '後歩' 26: '後歩' 27: '' 28: '' 29: '' 30: '' 31: '' 32: '' 33: '' 34: '' 35: ''

41 行目で行を取り出し、 explode 関数が NULL を返すまで取り出しては表示をしています。
カウントしている no 変数がインデックスとして利用できるので、44~46行目のコメントのように data 構造体配列に各種データを設定できます。

strtok の「状態を static 変数に持つ」というやり方はあまり好まれない(というか嫌われる?)場合もありますが、それなら何か構造体を作ってそこで管理する等の修正も出来ます。
まぁ、おそらくゲームの最初の初期化位にしか使わない部分でしょうから、ゲーム本体に比べれば何でもいい部分かもしれませんが。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#17

u2025

総合スコア103

投稿2025/09/27 08:42

u2025 さん
ご指摘ありがとうございます。
移動範囲については、作ろうと考えていたため、
9x9は配列にしました。駒の種類の定数はどのように使うイメージですか。

自分はそもそも、UI的に「選択できるコマをすべて表示する」、「選択したコマがどこに行けるのかを表示する」
は必要な要件だと思っているから、選択されたコマがどこなら移動できるのかを予め計算して、次の入力がそのマスかを判定できる機構が必要だと思ってる。
飛車と角だけ本家のルールでも行けるマスが特殊だから考えないと行けないけど。

で、本質的な話としてこの将棋プログラムはあなたが個人的に勉強の為にやっていると思ったんでもっとミクロな部分から作って広げているべきでは?というのが主張。

逆に勉強ではなく将棋プログラムを作り上げるのが目的ならば、そういうソースはネットにあるだろうからリーディングして盗んだ方が懸命。

大体の場合、プログラムって完成品を使うからプログラマーは完成品ありきで作ってると思い込んで設計からすべきだと思っているのであれば間違いだと私は思っていて、一つ一つ順を追って書いて理解していってると思ってる。たまに、特定の処理をスキップしてトラブルシューティングできるのはセオリーが頭の中に入っているから。
だから、質問時にソースコードを載せれば並レベルのプログラマなら読解できるはずというのは間違いだと思っている。

もちろん、設計が楽しいとか、最初にしておかないと後で破綻するという意見は飲めるけど、特に拡張性とか関係なく将棋プログラムを作るだけなら通らないと思う。
作ってからリファクタリングできる、というレベルをまずは目指すのがベストじゃないかなと思う。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#18

jimbe

総合スコア13427

投稿2025/09/27 16:25

ふと、画面関係なら curses(ncurses) はどうかと思いましたが、c の勉強としては行き過ぎでしょうね、
そもそも visualstudio で動くのかも知りませんし。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#19

todasan

総合スコア94

投稿2025/09/29 00:48

ご指摘ありがとうございます。C言語はある程度経験がありますが、苦手意識があるので、勉強のために、
体裁は気にせずコードをたくさん書くために、将棋のゲームにしました。
cursesについてですが、visualstudiocodeとgccでも作っているので、少し使ってみたくなりました。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#20

fana

総合スコア12298

投稿2025/09/29 01:53

構造

について言うなら,入出力している部分と,それ以外の部分とを明確に分離するといいんじゃないかな.
後で UI を変更とかしやすいように.

(他の方からも「UI」と言われているけど)最初のうちはまだコンソールで動作確認していられるだろうけど,すぐにそれがきつくなる題材であろうと思う.

あと,最初はもうちょっと 規模が小さいやつ(例えば「どうぶつ将棋」みたいな)とか,ルールが複雑でないやつ(オセロみたいな) を題材としてもいいんじゃないかな? という気もする.

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#21

cametan

総合スコア212

投稿2025/10/01 17:44

こういうのって、人に訊くより、他人が書いたソースコード読んで勉強した方がエエんだよな。
例えば、GNU Shogiと言うフリーソフトウェアがある。

GNU Shogi

これはC言語で書かれていて、「どういう風に書かれてるのか」と言うのをソースコードを見て学んだ方が早いと思うんだよな。
あるいは、「俺ならこうする」って批判的に読んでも良いだろうし。

ちなみに、これもcursesが使われてる模様。
ただ、恐らくWindowsではcursesは使えない。curses側の問題ではなく、WindowsのDOS窓あるいはPowerShellは正確に言うとUNIX系OSで言うターミナルエミュレータじゃないから、だ。
もうちょっと付け足すと、Linuxなんかの端末(ターミナル)はホントにハードウェア(端末の実機)エミュレータを意図してる。一方、WindowsのDOS窓は単に古典的なDOSを入力するためのツールであって、別に往年のDOSパソコンのエミュレータじゃない(だからDOS時代のグラフィカルなゲーム、例えばDOS用Sim CityなんかをDOS窓では遊べない)。
UNIXで言う端末とWindowsのDOS窓は似て非なるモノで、目的が違うんだ。
従って、目的が違うブツで、同じライブラリは使えないだろう。

恐らくだけど、Windowsだとmingw-w64なんかのGCCを使ってWindows環境でダイレクトにプログラミングするより、Cygwin+MSYS2にするか(確か、MSYS2がLinux的な端末エミュレータを含んでたんじゃなかろうか、うろ覚えだけど)、あるいはWSLを使った方がいいんじゃないか。WSLにLinuxな端末エミュレータが含まれてるかどうかは知らないけど。
いずれにせよ、CLIでcursesを使ったプログラムを書きたい、って場合は、UNIX/Linux系環境を導入しないと上手く行かないんじゃないかな、とは思う。

XShogi

注: 上の写真はLinuxのXShogiのモノ。
ただし、これは「GUIフロントエンド」と呼ばれるブツで、本体はやっぱGNU Shogi。
つまり、CLIアプリであるGNU Shogiと情報をやり取りしてGUIアプリとして表示している。
なお、現代の感覚だと、どう見てもショボいが(笑)、GNU Shogi自体が1990年代のソフトウェアで、この頃のLinuxでは低レベルのX Window Systemを使って直接GUIをやってたんで、こういう情けないブツになってる(笑)。
なお、現代のLinuxでは色々とガワ(レイヤー)を上に重ねていってるんで、GUIアプリ/フロントエンドの見た目はもっと良くなっている。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#22

melian

総合スコア21502

投稿2025/10/01 18:32

#21

GNU Shogi には Windows 向けの移植版が存在します。ですが、15年前のものなので現行の Windows11 などでビルドできるのかどうかは不明です。

GNU Shogi Windows port

I updated the WinBoard version of GNU Shogi, to become a true Windows port, which is no longer dependent on the Cygwin DLLs. The price is that the stand-alone modes are totally broken, so this version is only suitable for playing under WinBoard.

説明文にある通り、WinBoard for Shogi の利用が前提となっています。

#19

コンソールの制御・表示に関しては、ANSIエスケープシーケンスへの対応が2015年11月リリースの更新プログラム(Windows10 Threshold 2)で行われた模様です。

 Console Virtual Terminal Sequences - Windows Console | Microsoft Learn

同ページにコード例が記載されています。

 Samples

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#23

cametan

総合スコア212

投稿2025/10/01 19:49

#22

GNU Shogi には Windows 向けの移植版が存在します。ですが、15年前のものなので現行の Windows11 などでビルドできるのかどうかは不明です。

公式では何も書いてなかったと思うんだけど、野良ビルド版なのかな。
うん、いずれにせよ、Windowsで動かせる(かどうかは確定してないけど)なら、余計ソースコード見て勉強した方が良さそうだね。
手元で「動いて」、「どうなってんだろ?」って見ていった方が早いだろうし。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#24

todasan

総合スコア94

投稿2025/10/02 02:12

Windowsだとmingw-w64なんかのGCCで、cursesは動く事は確認できました。
GNU Shogiは知っていますが、すごい高度な設計で、まだ解読はしていませんが、
何かすごい人が作っているので、C言語の勉強の一環としては、
まだいいかと思いました。うさぴょんのページはありますが、あちらもまだ理解していません。
題材として、機能が足せる分、一定の規模がありいいと思いました。
実際、将棋も勉強して対局しているので、将棋は6級程度ですが、将棋の強さにも
少しはつながると思いました。他にC言語の勉強の一環として、いい題材があればいいですが。
データベースは仕事でpostgresqlを使った事がありますが、C言語でそのようなものが
使えたらいいと思います。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

この意見交換はまだ受付中です。

会員登録して回答してみよう

アカウントをお持ちの方は

関連した質問