質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.52%

  • C

    3664questions

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

はさみ将棋の囲み判定

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 218

zakio

score 2

 はさみ将棋をc言語で作っており、囲まれた時の判定をどのように判定したらいいのかわからずに困ってます。

はさみ将棋をc言語で作っており、挟まれた時の判定はできたのですが、囲まれた時の判定をどのように判定したらいいのかわからずに困ってます。
盤の配列は11x11で定義していますが、ゲームの盤自体はは9x9で考えていて、盤の一番上下左右の端は壁として設定しています。

 発生している問題・エラーメッセージ

囲まれた時の判定をどのように判定したらいいのかわからない。

 該当のソースコード

二次元配列を使って、盤を保存しています。
#define HORIZONTAL_LINE 11//横
#define VERTICAL_LINE 11//縦
#define EMPTY 0
#define FU 1
#define TO 2
#define KABE 3

//グローバル変数
int table[VERTICAL_LINE][HORIZONTAL_LINE];//[][]


    int counta, countb;

    //駒と碁盤の壁を定義
    for (counta = 0; counta < VERTICAL_LINE; counta++) {
        for (countb = 0; countb < HORIZONTAL_LINE; countb++) {
            table[counta][countb] = EMPTY;
        }
    }
    for (counta = 0; counta < VERTICAL_LINE; counta++) {
        for (countb = 0; countb < HORIZONTAL_LINE; countb++) {
            if (counta == 1) {
                table[counta][countb] = TO;
            }
            if (counta == VERTICAL_LINE - 2) {
                table[counta][countb] = FU;
            }
            if (counta == 0 || counta == VERTICAL_LINE - 1 || countb == 0 || countb == HORIZONTAL_LINE - 1) {
                table[counta][countb] = KABE;
            }
        }

 試したこと

移動した駒の左右上下を確認していく。
それぞれで壁の値が出るまで、相手の駒が連続で続いているかをチェックして、続いていたらその続いている駒の上下を確認していく?
自分でもよくわかりません。

 補足情報(FW/ツールのバージョンなど)

はさみ将棋のルール(公益社団法人 日本将棋連盟)
https://www.shogi.or.jp/knowledge/hasami_shogi/

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

2018/07/09 追記しました

追記ここから

is_siege関数が囲まれているかを判定する関数となっています。

#include <stdio.h>

#define HORIZONTAL_LINE 11 //横
#define VERTICAL_LINE 11   //縦
#define EMPTY 0
#define FU 1
#define TO 2
#define KABE 3


#define UE    0
#define SHITA    1
#define HIDARI    2
#define MIGI    3


//グローバル変数
int table[VERTICAL_LINE][HORIZONTAL_LINE] = {
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
{ 3, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3 },
{ 3, 0, 2, 0, 1, 2, 1, 0, 1, 2, 3 },
{ 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3 },
{ 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3 },
{ 3, 2, 1, 0, 0, 1, 1, 0, 0, 0, 3 },
{ 3, 1, 0, 0, 0, 2, 2, 1, 0, 0, 3 },
{ 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3 },
{ 3, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3 },
{ 3, 0, 1, 2, 1, 0, 1, 2, 2, 2, 3 },
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
};

struct stack {
    int koma;
    int x;
    int y;
};

#define STACK_SIZE    9
static struct stack s_stack[STACK_SIZE];
static int s_stack_top;


void init_stack(void) {
    s_stack_top = 0;
}

void push(int koma, int x, int y) {
    if (s_stack_top >= STACK_SIZE) {
        return;
    }
    s_stack[s_stack_top].koma = koma;
    s_stack[s_stack_top].x = x;
    s_stack[s_stack_top].y = y;
    s_stack_top++;
}

int pop(struct stack* s)
{
    if (s_stack_top < 1) {
        return 0;
    }

    s_stack_top--;
    s->koma = s_stack[s_stack_top].koma;
    s->x = s_stack[s_stack_top].x;
    s->y = s_stack[s_stack_top].y;
    return 1;
}



void disp_table(void)
{
    int i, j;
    putchar(' ');
    for (i = 0; i < HORIZONTAL_LINE; i++)
    {
        putchar(i + 0x30);
    }
    putchar('\n');
    for (j = 0; j < VERTICAL_LINE; j++)
    {
        putchar(j + 0x30);
        for (i = 0; i < HORIZONTAL_LINE; i++)
        {
            switch (table[j][i])
            {
            case KABE:
                putchar('*');
                break;
            case FU:
                putchar('F');
                break;
            case TO:
                putchar('T');
                break;
            default:
                putchar(' ');
                break;
            }
        }
        putchar('\n');
    }
}

// 駒のつながりが途切れた先にあるものを調べる
int koma_probe(int koma, int x, int y, int d)
{
    int placed;
    if (table[y][x] == EMPTY)
    {
        return EMPTY;
    }
    if (table[y][x] == KABE)
    {
        return KABE;
    }
    if (table[y][x] != koma)
    {
        return table[y][x];
    }

    placed = 0;
    switch (d)
    {
    case UE:
        placed = koma_probe(koma, x, y - 1, d);
        break;
    case SHITA:
        placed = koma_probe(koma, x, y + 1, d);
        break;
    case HIDARI:
        placed = koma_probe(koma, x - 1, y, d);
        break;
    case MIGI:
        placed = koma_probe(koma, x + 1, y, d);
        break;
    }
    return placed;
}


// komaをたどりながらEMPTYを探す
// EMPTYを検出した=囲まれてないので取れない
// 0 - EMPTYが無かった
// 1 - EMPTYを見つけた
int empty_probe(int ff_table[][HORIZONTAL_LINE], int koma, int x, int y) {
    if (ff_table[y][x] == koma) {
        push(koma, x, y);
        ff_table[y][x] = -1;    //検査済み

    }
    else if (ff_table[y][x] == EMPTY) {
        // EMPTYを見つけたので探査を打ち切る
        return 1;
    }
    else {
        // EMPTYではない何かがあったので探査を打ち切る
        return 0;
    }

    // 上下左右方向に探査を続ける
    if (empty_probe(ff_table, koma, x, y - 1)) {
        return 1;
    }
    else if (empty_probe(ff_table, koma, x, y + 1)) {
        return 1;
    }
    else if (empty_probe(ff_table, koma, x - 1, y)) {
        return 1;
    }
    else if (empty_probe(ff_table, koma, x + 1, y)) {
        return 1;
    }
    return 0;
}


// 囲まれているか調べる
int is_siege(int koma, int x, int y)
{
    int i, j;

    // 作業用にコピーする
    int ff_table[VERTICAL_LINE][HORIZONTAL_LINE];
    for (j = 0;j < VERTICAL_LINE;j++) {
        for (i = 0;i < HORIZONTAL_LINE;i++) {
            ff_table[j][i] = table[j][i];
        }
    }

    init_stack();
    return !empty_probe(ff_table, koma, x, y);
}


//x,yの位置にある駒が取れるか?
// 0 - とれない
// 1 - 取れる
int is_capture(int x, int y)
{
    int koma = table[y][x];
    int ue = koma_probe(koma, x, y - 1, UE);
    int shita = koma_probe(koma, x, y + 1, SHITA);
    int hidari = koma_probe(koma, x - 1, y, HIDARI);
    int migi = koma_probe(koma, x + 1, y, MIGI);

    int aite;
    if (koma == FU)
    {
        aite = TO;
    }
    else
    {
        aite = FU;
    }

    //上下左右方向にaiteで挟まれてたら取れる
    if (ue == aite && shita == aite)
    {
        return 1;
    }
    if (hidari == aite && migi == aite)
    {
        return 1;
    }

    // コマが囲まれてたら取れる
    if (is_siege(koma, x, y)) {
        return 1;
    }

    return 0;
}

void disp_result(int x, int y)
{
    int koma = table[y][x];
    char *name[2] = { "FU", "TO" };
    if (is_capture(x, y))
    {
        printf("%d,%dの%sは取れる\n", x, y, name[koma - 1]);
    }
    else
    {
        printf("%d,%dの%sは取れない\n", x, y, name[koma - 1]);
    }
}

int main(void)
{
    disp_table();
    disp_result(2, 2);
    disp_result(5, 2);
    disp_result(1, 5);
    disp_result(3, 9);
    disp_result(5, 6);
    disp_result(6, 6);
    disp_result(8, 9);
    disp_result(9, 1);
}

実行結果

 0123456789:
0***********
1* F     FT*
2* T FTF FT*
3* F       *
4*F        *
5*TF  FF   *
6*F   TTF  *
7*    F    *
8*  F    F *
9* FTF FTTT*
:***********
2,2のTOは取れる
5,2のTOは取れる
1,5のTOは取れる
3,9のTOは取れる
5,6のTOは取れる
6,6のTOは取れない
8,9のTOは取れない
9,1のTOは取れない

追記ここまで


is_capture関数で指定位置の駒を取れるか調べます。

#include <stdio.h>

#define HORIZONTAL_LINE 11 //横
#define VERTICAL_LINE 11   //縦
#define EMPTY 0
#define FU 1
#define TO 2
#define KABE 3

//グローバル変数
int table[VERTICAL_LINE][HORIZONTAL_LINE] = {
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
{ 3, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3 },
{ 3, 0, 2, 0, 1, 2, 1, 0, 1, 2, 3 },
{ 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3 },
{ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 },
{ 3, 0, 0, 0, 0, 1, 1, 0, 0, 0, 3 },
{ 3, 0, 0, 0, 0, 2, 2, 1, 0, 0, 3 },
{ 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3 },
{ 3, 1, 0, 0, 0, 0, 0, 1, 1, 1, 3 },
{ 3, 2, 1, 0, 0, 0, 0, 2, 2, 2, 3 },
{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
};

void disp_table(void)
{
    int i, j;
    putchar(' ');
    for (i = 0; i < HORIZONTAL_LINE; i++)
    {
        putchar(i + 0x30);
    }
    putchar('\n');
    for (j = 0; j < VERTICAL_LINE; j++)
    {
        putchar(j + 0x30);
        for (i = 0; i < HORIZONTAL_LINE; i++)
        {
            switch (table[j][i])
            {
            case KABE:
                putchar('*');
                break;
            case FU:
                putchar('F');
                break;
            case TO:
                putchar('T');
                break;
            default:
                putchar(' ');
                break;
            }
        }
        putchar('\n');
    }
}

// 駒のつながりが途切れた先にあるものを調べる
int probe(int koma, int x, int y, int d)
{
    int placed;
    if (table[y][x] == EMPTY)
    {
        return EMPTY;
    }
    if (table[y][x] == KABE)
    {
        return KABE;
    }
    if (table[y][x] != koma)
    {
        return table[y][x];
    }

    placed = 0;
    switch (d)
    {
    case 0:
        placed = probe(koma, x, y - 1, d);
        break;
    case 1:
        placed = probe(koma, x, y + 1, d);
        break;
    case 2:
        placed = probe(koma, x - 1, y, d);
        break;
    case 3:
        placed = probe(koma, x + 1, y, d);
        break;
    }
    return placed;
}

//x,yの位置にある駒が取れるか?
// 0 - とれない
// 1 - 取れる
int is_capture(int x, int y)
{
    int koma = table[y][x];
    int ue = probe(koma, x, y - 1, 0);
    int shita = probe(koma, x, y + 1, 1);
    int hidari = probe(koma, x - 1, y, 2);
    int migi = probe(koma, x + 1, y, 3);

    int aite;
    if (koma == FU)
    {
        aite = TO;
    }
    else
    {
        aite = FU;
    }

    if (ue == aite && shita == aite)
    {
        return 1;
    }
    if (ue == aite && shita == KABE)
    {
        if (hidari != EMPTY && migi != EMPTY)
        {
            return 1;
        }
    }
    if (ue == KABE && shita == aite)
    {
        if (hidari != EMPTY && migi != EMPTY)
        {
            return 1;
        }
    }

    if (hidari == aite && migi == aite)
    {
        return 1;
    }
    if (hidari == aite && migi == KABE)
    {
        if (ue != EMPTY && shita != EMPTY)
        {
            return 1;
        }
    }
    if (hidari == KABE && migi == aite)
    {
        if (ue != EMPTY && shita != EMPTY)
        {
            return 1;
        }
    }

    return 0;
}

void disp_result(int x, int y)
{
    int koma = table[y][x];
    char *name[2] = { "FU", "TO" };
    if (is_capture(x, y))
    {
        printf("%d,%dの%sは取れる\n", x, y, name[koma - 1]);
    }
    else
    {
        printf("%d,%dの%sは取れない\n", x, y, name[koma - 1]);
    }
}

int main(void)
{

    disp_table();
    disp_result(2, 2);
    disp_result(5, 2);
    disp_result(1, 9);
    disp_result(5, 6);
    disp_result(6, 6);
    disp_result(9, 9);
    disp_result(9, 1);
}

実行結果

./a.out
 0123456789:
0***********
1* F     FT*
2* T FTF FT*
3* F       *
4*         *
5*    FF   *
6*    TTF  *
7*    F    *
8*F     FFF*
9*TF    TTT*
:***********
2,2のTOは取れる
5,2のTOは取れる
1,9のTOは取れる
5,6のTOは取れる
6,6のTOは取れない
9,9のTOは取れない
9,1のTOは取れない

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/08 14:37 編集

    回答ありがとうございます。tatamyiwathyさんの回答で考えさせていただいたのですが、この判定方法だとはさみ判定しかうまくできませんでした。囲み判定を対象の駒の上と下。そして左右の連続する駒の端しか確認しておらず。
    例えば、下のような場合も取れると判定してしまいます。(とは完全に囲まれてはいない)
    0123456789:
    0***********
    1* *
    2* *
    3* *
    4* *
    5* *
    6* *
    7* *
    8* F *
    9* FTTTTT*
    :.***********
    6,9のTOは取れる

    ↑の状況

       歩
    歩ととトとと壁
    壁壁壁壁壁壁壁

    トについてチェック


    私のルール説明不足だったのですが、囲む場合は相手の駒を完全に囲み連続している相手の駒がすべて移動できない状態でないと、相手の駒を取れません。私の説明では、少しわかりにくいので、質問文の補足情報にはさみ将棋のルールが説明されているサイトのリンクを張っておきましたので参考にしてください。

    もし、よろしければ、これらを考慮して教えていただければ、ありがたいです。

    キャンセル

  • 2018/07/09 17:13

    横から失礼します。
    はさみ将棋は、基本的にははさめば駒を取れますが、壁に接している場合は動きを封じないと取れないというルールなのですよね。
    なら、判定する駒が壁に接しているかどうかで分岐させて、壁に接していなければtatamyiwathyさんの判定を使い、壁に接していたら、動けるかどうかで判定すれば良いのではないでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3664questions

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