0

首謀者のゲームをシミュレートするプログラムを書いているのですが、推測したパターンとキーパターンを比較する方法に苦労しています。ゲームの条件が少し変更されます。

  • パターンは文字で構成されています。
  • 推測されたパターンの要素がキー パターンの要素と等しく、インデックスも等しい場合、b を出力します。
  • 推測されたパターンの要素がキー パターンの要素と等しいが、インデックスがそうでない場合、w を出力します。
  • 推測されたパターンの要素がキーパターンの要素と等しくない場合は、ドットを出力します。
  • 推測されたパターンに関するフィードバックでは、'b' が最初、'w' が 2 番目、'.' が最後です。

元のキーと推測パターンの一致コード

    for (i=0; i<patternlength; i++)
    {
        for (x=0; x<patternlength; x++)
        {
           if (guess[i]==key[x] && i==x)
                printf("b");
            if (guess[i]==key[x] && i!=x)
                printf("w");
            if (guess[i]!=key[x])
                printf(".");
        }   
    }

改訂されたコード

これは、 Jonathan Lefflerによって提供された回答の一部を使用しています。残念ながら、まだ正しく動作していません。手伝って頂けますか?

関数 length() とguessnum() は既に定義されています。

#include<stdio.h>
#include<string.h>
int length()
{
  int length;
  printf("Enter the pattern length: ");
  scanf("%d", &length);
  return length;
}
int guessnum()
{
  int guessnum;
  printf("Enter the number of guesses: ");
  scanf("%d", &guessnum);
  return guessnum;
}
int main(void)
{
  int patternlength = length();
  char key[patternlength+1];      
  char keyc[patternlength+1];    
  int numguess = guessnum();
  char guess[patternlength+1];    
  printf("Input the key pattern with no spaces: ");
  scanf("%s", key);
  int i,j,count = 1;
  int bcount = 0, wcount = 0;
  char guessc[patternlength+1];
  guessc[0] = '\0';            
  int ind;
  char output[patternlength];
  for (ind=0; ind<(patternlength+1); ind++)
    output[ind]='\0';
  char outputc[patternlength+1];
  char guessold[patternlength+1];
  for (ind=0; ind<(patternlength+1); ind++)
  guessold[ind]='\0';
  while (strcmp(key, guess) !=0 && count<=numguess)
    {
      if(count>1)
    strcpy(guessold, guess);
      strcpy(keyc, key);          
      printf("Input a guess pattern with no spaces: ");
      scanf("%s", guess);
      if (count>1)
    printf("%d: %s %s\n", count-1, output, guessold);
      strcpy(guessc, guess);
      wcount = 0;    
      bcount = 0;     
      printf("%d: ", count);
      for (i = 0; i < patternlength; i++)
    {
      if (keyc[i] == guessc[i])
        {
          putchar('b');
          keyc[i] = guessc[i] = '.';
          bcount++;
          for (ind=0; ind<patternlength; ind++)
        output[ind]='b';
        }
    }
      if (bcount != patternlength)
    {
      for (i = 0; i < patternlength; i++)
        {
          if (guessc[i] != '.')
        {

          for (j = 0; j < patternlength; j++)
            {

              if (guessc[i] == keyc[j])
            {
              wcount++;
              putchar('w');
              for (ind=0; ind<patternlength; ind++)
                if (output[ind]!='b')
                  output[ind]='w';

              keyc[j] = guessc[i] = '.';
              break;
            }
            }
        }
        }
      for (i = bcount  +  wcount; i < patternlength; i++)
        putchar('.');
      for (ind=bcount+wcount; ind<patternlength; ind++)
        output[ind]='.';
    }
      count++;
      printf(" %s\n", guess);
      strcpy(outputc, output);
    }
  if (strcmp(key, guess) != 0)
    {
      printf("You did not guess the pattern!\n");
    }
  else 
    {
      printf("You guessed the pattern!\n");
    }
  return 0;
}

上記のコードの出力:

Enter the pattern length: 3
Enter the number of guesses: 3
Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: acb
1: bww acb
Input a guess pattern with no spaces: abb
1: bbb acb
2: bb. abb
Input a guess pattern with no spaces: abc
2: bb. abb
3: bbb abc
You guessed the pattern!

必要な出力:

    Enter the pattern length: 3
    Enter the number of guesses: 3
    Input the key pattern with no spaces: abc
    Input a guess pattern with no spaces: acb
    1: bww acb
    Input a guess pattern with no spaces: abb
    1: bww acb
    2: bb. abb
    Input a guess pattern with no spaces: abc
    1: bww acb
    2: bb. abb
    3: bbb abc
    You guessed the pattern!

推測のフィードバックを保存するもう1つの文字列を使用しようとしましたが、いくつかの推測がある場合、新しい推測が行われるたびに、何らかのループを使用して以前のすべての推測のフィードバックを出力する必要があると思います。しかし、ジョナサン・レフラーによって提案された構造でこのループをどのように書くべきかを理解するのは難しいです。

最後の修正をコードに追加したので、目的の出力にほぼ到達しました。ここで何ができるか考えている人はいますか?

4

2 に答える 2

2

構造体 (構造体に含まれる配列を簡単にコピーするため) があり、入力検証によって、キーと推測が同じ長さであり、キーと推測にアルファベット文字のみが含まれていることが保証されると仮定します。

typedef struct pattern
{
    char pattern[8];
} pattern;

size_t print_scoring(pattern key, pattern guess)
{
    size_t n = strlen(key.pattern);
    assert(n == strlen(guess.pattern));
    size_t bcount = 0;
    for (size_t i = 0; i < n; i++)
    {
        if (key.pattern[i] == guess.pattern[i])
        {
            putchar('b');
            key.pattern[i] = guess.pattern[i] = '.';
            bcount++;
        }
    }
    if (bcount != n)
    {
        size_t wcount = 0;
        for (size_t i = 0; i < n; i++)
        {
            if (guess.pattern[i] != '.')
            {
                for (size_t j = 0; j < n; j++)
                {
                    if (guess.pattern[i] == key.pattern[j])
                    {
                        wcount++;
                        putchar('w');
                        guess.pattern[i] = key.pattern[j] = '.';
                        break;
                    }
                }
            }
        }
        for (size_t i = bcount + wcount; i < n; i++)
            putchar('.');
    }
    return bcount;
}

この関数はキーとパターンのコピーで機能します (構造体はポインターではなく値で渡されます)。正しい位置にある正しい推測の数を返します。呼び出し元のコードがパターンの長さを知っていると想定しているため、呼び出し元のコードはパターンがいつ正しいかを知ることができます。推測文字とキー文字を「.」に置き換えることで「使用済み」としてマークします。これは、 のキーが正しく ではなく誤って とマークされるのを防ぐために重要"aba"です。これは、長さが 4 以上のキー/推測ではより重要になります。"aaa"bbwbb.

テストハーネス

#include <assert.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
    enum { NUM_KEYS = 3, NUM_GUESSES = 5 };
    pattern k[] = { { "abc" }, { "aba" }, { "aaa" } };
    pattern g[] = { { "aaa" }, { "aab" }, { "abc" }, { "cba" }, { "bab" } };
    for (int i = 0; i < NUM_KEYS; i++)
    {
        for (int j = 0; j < NUM_GUESSES; j++)
        {
            printf("Key: %s; Guess %s; Score: ", k[i].pattern, g[j].pattern);
            size_t n = print_scoring(k[i], g[j]);
            if (n == 3)
                printf(" -- Correct!");
            putchar('\n');
        }
    }
    return(0);
}

テスト出力

Key: abc; Guess aaa; Score: b..
Key: abc; Guess aab; Score: bw.
Key: abc; Guess abc; Score: bbb -- Correct!
Key: abc; Guess cba; Score: bww
Key: abc; Guess bab; Score: ww.
Key: aba; Guess aaa; Score: bb.
Key: aba; Guess aab; Score: bww
Key: aba; Guess abc; Score: bb.
Key: aba; Guess cba; Score: bb.
Key: aba; Guess bab; Score: ww.
Key: aaa; Guess aaa; Score: bbb -- Correct!
Key: aaa; Guess aab; Score: bb.
Key: aaa; Guess abc; Score: b..
Key: aaa; Guess cba; Score: b..
Key: aaa; Guess bab; Score: b..

コメントから

コードが機能しないのはなぜですか? よろしければご覧いただけますか?問題は、推測パターンを入力した後、次のステップに進むことができないことです。私のコードにいくつかの間違いが見られないかもしれません。

即時応答:

私の回答の重要なポイントの 1 つは、入力されたデータのコピーに対して比較コードが機能しているということです。これは破壊的な比較アルゴリズムであり、データにドットを書き込みます。私のコードをあなたのプログラムにマージしようとしても、この回答の重要な部分であるデータの個別のコピーで動作する個別の機能が保持されませんでした。構造体を使用すると、データのコピーを簡単に渡すことができます (C が配列を自動的にコピーするのは 1 回だけです)。比較コードは、インラインではなく、独自の関数内にある必要がありますmain()

ただし、指定されたコードを機能させることはできます。いくつかの転記エラー (以下で BUG とマークされています) と、その他の問題 (以下で特定) がいくつかありました。

問題の改訂コードの作業バージョン

これは、重要な変更の注釈が付けられたプログラムの作業バージョンです。重要ではない変更には、演算子の前後のスペースと 4 つのスペースのインデント レベルの使用が含まれます。

#include <string.h>
#include <stdio.h>

static int length(void) { return 3; }    // Dummy function
static int guessnum(void) { return 5; }  // Dummy function

int main(void)
{
    int patternlength = length();
    char key[patternlength+1];      // Buffer overflow
    char keyc[patternlength+1];     // Copy of key
    int numguess = guessnum();
    char guess[patternlength+1];    // Buffer overflow
    printf("Input the key pattern with no spaces: ");
    scanf("%s", key);
    int i,j,count = 1;
    int bcount = 0, wcount = 0;
    char guessc[patternlength+1];   // Buffer overflow
    guessc[0] = '\0';               // Initialize!
    while (strcmp(key, guess) != 0 && count <= numguess)
    {
        strcpy(keyc, key);          // Copy key too
        printf("Input a guess pattern with no spaces: ");
        scanf("%s", guess);
        strcpy(guessc, guess);

        wcount = 0;     // Reinitialize
        bcount = 0;     // Reinitialize
        printf("%d: ", count);
        for (i = 0; i < patternlength; i++)
        {
            if (keyc[i] == guessc[i])
            {
                putchar('b');
                keyc[i] = guessc[i] = '.';
                bcount++;
            }
        }
        if (bcount != patternlength)    // Extraneous semi-colon excised! ;
        {
            for (i = 0; i < patternlength; i++)
            {
                if (guessc[i] != '.')
                {
                    //for (j = 0; i < patternlength; j++) BUG
                    for (j = 0; j < patternlength; j++)
                    {
                        //if (guessc[i] == keyc[i]) BUG
                        if (guessc[i] == keyc[j])
                        {
                            wcount++;
                            putchar('w');
                            //guessc[i] = keyc[i];  BUG
                            keyc[j] = guessc[i] = '.';
                            break;
                        }
                    }
                }
            }
            for (i = bcount  +  wcount; i < patternlength; i++)
                putchar('.');
        }
        count++;
        printf(" %s\n", guess);
    }
    if (strcmp(key, guess) != 0)
    {
        printf("You did not guess the pattern!\n");
    }
    else 
    {
        printf("You guessed the pattern!\n");
    }
    return 0;
}

コンパイラは、迷子のセミコロンについて教えてくれました:

ss2.c: In function ‘main’:
ss2.c:36:37: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]

コンパイラがそれについて教えてくれなかった場合は、十分な警告を使用していません (または、より優れたコンパイラが必要です)。私は日常的に使用します:

gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition ss2.c -o ss2

作業コードは、気まぐれでそれを渡します。

サンプル出力

Input the key pattern with no spaces: abc
Input a guess pattern with no spaces: aaa
1: b.. aaa
Input a guess pattern with no spaces: bbb
2: b.. bbb
Input a guess pattern with no spaces: ccc
3: b.. ccc
Input a guess pattern with no spaces: cab
4: www cab
Input a guess pattern with no spaces: abc
5: bbb abc
You guessed the pattern!

最終的なデバッグを含んだコード

これは主に、何が問題なのかを確認するために使用した印刷のレベルを示すためのものです. 診断出力に使用すると、出力ラインが構築されたときにstderr、診断がバッファリングに干渉しませんでした。stdoutまた、デバッグ コードにインデントを使用しないことで、デバッグ コードを簡単に取り除くことができました。

#include <string.h>
#include <stdio.h>

static int length(void) { return 3; }
static int guessnum(void) { return 5; }

int main(void)
{
    int patternlength = length();
    char key[patternlength+1];      // Buffer overflow
    char keyc[patternlength+1];     // Copy of key
    int numguess = guessnum();
    char guess[patternlength+1];    // Buffer overflow
    printf("Input the key pattern with no spaces: ");
    scanf("%s", key);
    int i,j,count = 1;
    int bcount = 0, wcount = 0;
    char guessc[patternlength+1];   // Buffer overflow
    guessc[0] = '\0';               // Initialize!
    while (strcmp(key, guess) != 0 && count <= numguess)
    {
        strcpy(keyc, key);          // Copy key too
        printf("Input a guess pattern with no spaces: ");
        scanf("%s", guess);
        strcpy(guessc, guess);

fprintf(stderr, "B1: (%s) vs (%s)\n", key, guess);
fprintf(stderr, "B2: (%s) vs (%s)\n", keyc, guessc);
        wcount = 0;     // Reinitialize
        bcount = 0;     // Reinitialize
        printf("%d: ", count);
        for (i = 0; i < patternlength; i++)
        {
fprintf(stderr, "L1a: %d\n", i);
            if (keyc[i] == guessc[i])
            {
fprintf(stderr, "L1b: B (%c = %c)\n", keyc[i], guessc[i]);
                putchar('b');
                keyc[i] = guessc[i] = '.';
                bcount++;
            }
        }
fprintf(stderr, "M1: (%s) vs (%s)\n", keyc, guessc);
        if (bcount != patternlength)    // Extraneous semi-colon excised! ;
        {
fprintf(stderr, "L2a: b = %d (%s) vs (%s)\n", bcount, keyc, guessc);
            for (i = 0; i < patternlength; i++)
            {
fprintf(stderr, "L2b: %d (%c)\n", i, guessc[i]);
                if (guessc[i] != '.')
                {
fprintf(stderr, "L2c: %d (%c)\n", i, guessc[i]);
                    //for (j = 0; i < patternlength; j++) BUG
                    for (j = 0; j < patternlength; j++)
                    {
fprintf(stderr, "L2d: %d (%c) vs %d (%c)\n", i, guessc[i], j, keyc[j]);
                        //if (guessc[i] == keyc[i]) BUG
                        if (guessc[i] == keyc[j])
                        {
fprintf(stderr, "L2e: W %d (%c) vs %d (%c)\n", i, guessc[i], j, keyc[j]);
                            wcount++;
                            putchar('w');
                            keyc[j] = guessc[i] = '.';
                            //guessc[i] = keyc[i];  BUG
                            break;
                        }
                    }
                }
            }
fprintf(stderr, "L3a: %d + %d vs %d\n", bcount, wcount, patternlength);
            for (i = bcount  +  wcount; i < patternlength; i++)
fprintf(stderr, "L3b: D %d\n", i),
                putchar('.');
        }
        count++;
        printf(" %s\n", guess);
    }
    if (strcmp(key, guess) != 0)
    {
        printf("You did not guess the pattern!\n");
    }
    else 
    {
        printf("You guessed the pattern!\n");
    }
    return 0;
}

fprintf()最後の関数呼び出しの後のコンマ演算子のトリックに注意してください。

以前の推測とマークの記録を保持する

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void err_exit(const char *msg, ...);
static void prompt_str(const char *prompt, int bufsiz, char *buffer);
static int  prompt_int(const char *prompt);

int main(void)
{
    int  patternlength = prompt_int("Length of key");
    int  numguess = prompt_int("Number of guesses");
    char key[patternlength+1];
    char guesses[numguess][patternlength+1];
    char marks[numguess][patternlength+1];
    int  count = 0;

    prompt_str("Input the key pattern with no spaces", patternlength, key);

    while (count < numguess)
    {
        char guess[patternlength+1];
        char keyc[patternlength+1];
        char mark[patternlength+1];
        char *marker = mark;
        int wcount = 0;
        int bcount = 0;

        strcpy(keyc, key);
        prompt_str("Input a guess pattern with no spaces", patternlength, guess);
        strcpy(guesses[count], guess);

        for (int i = 0; i < patternlength; i++)
        {
            if (keyc[i] == guess[i])
            {
                *marker++ = 'b';
                keyc[i] = guess[i] = '.';
                bcount++;
            }
        }
        if (bcount == patternlength)
            break;
        for (int i = 0; i < patternlength; i++)
        {
            if (guess[i] == '.')
                continue;
            for (int j = 0; j < patternlength; j++)
            {
                if (guess[i] == keyc[j])
                {
                    wcount++;
                    *marker++ = 'w';
                    keyc[j] = guess[i] = '.';
                    break;
                }
            }
        }
        for (int i = bcount  +  wcount; i < patternlength; i++)
            *marker++ = '.';
        *marker = '\0';
        strcpy(marks[count], mark);
        count++;
        for (int i = 0; i < count; i++)
            printf("Guess: %d [%s] marks [%s]\n", i, guesses[i], marks[i]);
    }
    if (count >= numguess)
        printf("You did not guess the pattern (which was [%s])!\n", key);
    else 
        printf("You guessed the pattern!\n");
    return 0;
}

static void prompt_str(const char *prompt, int bufsiz, char *buffer)
{
    char fmt[8];
    int  c;

    sprintf(fmt, "%%%ds", bufsiz);
    printf("%s: ", prompt);
    if (scanf(fmt, buffer) != 1)
        err_exit("Unexpected input failure\n");
    while ((c = getchar()) != EOF && c != '\n')
        ;
}

static int prompt_int(const char *prompt)
{
    int number;
    printf("%s: ", prompt);
    if (scanf("%d", &number) != 1)
        err_exit("Unexpected input failure\n");
    if (number <= 0 || number > 9)
        err_exit("Number should be in the range 1..9 (not %d)\n", number);
    return(number);
}

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}

prompt_int()関数を導入prompt_str()し、データを取得します。このprompt_str()関数は、オーバーフローに対して適度に回復力があります。エラー報告機能があります。ダミー関数が置き換えられます。出力例を次に示します。ここから先はあなた次第!

Length of key: 4
Number of guesses: 8
Input the key pattern with no spaces: abcd
Input a guess pattern with no spaces: aaaa
Guess: 0 [aaaa] marks [b...]
Input a guess pattern with no spaces: dcba
Guess: 0 [aaaa] marks [b...]
Guess: 1 [dcba] marks [wwww]
Input a guess pattern with no spaces: cdba
Guess: 0 [aaaa] marks [b...]
Guess: 1 [dcba] marks [wwww]
Guess: 2 [cdba] marks [wwww]
Input a guess pattern with no spaces: abcd
You guessed the pattern!
于 2012-11-03T07:12:01.050 に答える
1

keyあなたは基本的に のすべての要素を のすべての要素と一致させていますがguess、これはあなたが望むものではありません。

guess3つのケースを繰り返して区別する必要があります

  1. 正しく推測された要素
  2. 要素が正しく推測されていませんが、キーに存在します
  3. 要素が正しく推測されず、キーに存在しません

    int i,k;
    bool found;
    
    for (i=0; i<patternlength; i++)
    {
        if (key[i] == guess[i])
        {
            printf("b");
        }
        else
        {
            found = false;
            for (k=0; k<patternlength && !found; k++)
            {
                if (key[k] == guess[i])
                {
                    found = true;
                    printf("w");
                }
            }
            if (!found)
            {
                printf(".");
            }
        }
    }
    

内部ループでは、 を持つ要素を見つけると停止することに注意してください&& !found。そうしないと、あなたと同様の問題に陥ります( にwある私の推測に一致するすべての要素が出力されますkey

于 2012-11-03T05:42:33.180 に答える