105

プログラムで必要なループがいくつかあります。疑似コードを書き出すことはできますが、それらを論理的に記述する方法が完全にはわかりません。

私は欲しい -

if (num is a multiple of 10) { do this }

if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }
else { do this } //this part is for 1-10, 21-30, 41-50, 61-70, 81-90

私の質問にこれ以上意味がある場合、これはヘビとはしごのボードゲーム用です。

モジュラスを使用する必要がある最初のifステートメントを想像します。if (num == 100%10)正しいでしょうか?

2つ目はよくわからない。のように書くこともできますがif (num > 10 && num is < 21 || etc.)、それよりもスマートなものが必要です。

4

13 に答える 13

88

最初のものについては、数値が使用の倍数であるかどうかを確認するには、次のようにします。

if (num % 10 == 0) // It's divisible by 10

2 つ目の場合:

if(((num - 1) / 10) % 2 == 1 && num <= 100)

しかし、それはかなり密集しているため、オプションを明示的にリストするだけの方がよい場合があります。


あなたが何をしているのかについてより良い考えを与えたので、私は2番目のものを次のように書きます:

   int getRow(int num) {
      return (num - 1) / 10;
   }

   if (getRow(num) % 2 == 0) {
   }

同じロジックですが、関数を使用することで、その意味がより明確になります。

于 2014-04-27T23:05:18.370 に答える
30

GCC または大文字と小文字の範囲をサポートするコンパイラを使用している場合は、これを行うことができますが、コードは移植できません

switch(num)
{
case 11 ... 20:
case 31 ... 40:
case 51 ... 60:
case 71 ... 80:
case 91 ... 100:
    // Do something
    break;
default:
    // Do something else
    break;
}
于 2014-04-27T23:16:06.937 に答える
5

最初のものは簡単です。モジュロ演算子を num 値に適用するだけです。

if ( ( num % 10 ) == 0)

C++ は 0 以外のすべての数値を true として評価しているため、次のように書くこともできます。

if ( ! ( num % 10 ) )  // Does not have a residue when divided by 10

2番目のものについては、これは理解しやすいと思います:

パターンは 20 ごとに繰り返されるため、モジュロ 20 を計算できます。20 で割り切れる要素を除いて、必要なすべての要素が一列に並んでいます。

それらも取得するには、num-1 またはより良い num+19 を使用して、負の数を処理しないようにします。

if ( ( ( num + 19 ) % 20 ) > 9 )

これは、パターンが永久に繰り返されることを前提としているため、111 ~ 120 の場合は再び適用されます。それ以外の場合は、数を 100 に制限する必要があります。

if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )
于 2014-04-28T00:33:28.477 に答える
5

コードにいくつかの適切なコメントがあれば、非常に簡潔に読みやすく記述できます。

// Check if it's a multiple of 10
if (num % 10 == 0) { ... }

// Check for whether tens digit is zero or even (1-10, 21-30, ...)
if ((num / 10) % 2 == 0) { ... }
else { ... }
于 2014-04-28T15:25:50.763 に答える
4

あなたは基本的に答えを自分で説明しましたが、念のためコードを示します。

if((x % 10) == 0) {
  // Do this
}
if((x > 10 && x < 21) || (x > 30 && x < 41) || (x > 50 && x < 61) || (x > 70 && x < 81) || (x > 90 && x < 101)) {
  // Do this
}
于 2014-04-27T23:03:49.907 に答える
3

あなたはこれを考えすぎているかもしれません。

if (x % 10)
{
   .. code for 1..9 ..
} else
{
   .. code for 0, 10, 20 etc.
}

最初の行がif (x % 10)機能するのは、(a) 10 の倍数の値は '0' として計算され、他の数値はその余りになるためです。(b) の 0 の値ifは と見なされfalse、その他の値はと見なされますtrue

編集:

20 代で前後に切り替えるには、同じトリックを使用します。今回、重要な番号は10次のとおりです。

if (((x-1)/10) & 1)
{
  .. code for 10, 30, ..
} else
{
   .. code for 20, 40, etc.
}

x/100 から 9 までの任意の数値を0、10 から 19 までなどを返します1。偶数または奇数をテストすると、偶数か奇数& 1かがわかります。範囲は実際には「11 ~ 20」であるため、テストする前に 1 を引きます。

于 2014-04-27T23:03:04.977 に答える
1

A plea for readability

While you already have some good answers, I would like to recommend a programming technique that will make your code more readable for some future reader - that can be you in six months, a colleague asked to perform a code review, your successor, ...

This is to wrap any "clever" statements into a function that shows exactly (with its name) what it is doing. While there is a miniscule impact on performance (from "function calling overhead") this is truly negligible in a game situation like this.

Along the way you can sanitize your inputs - for example, test for "illegal" values. Thus you might end up with code like this - see how much more readable it is? The "helper functions" can be hidden away somewhere (the don't need to be in the main module: it is clear from their name what they do):

#include <stdio.h>

enum {NO, YES, WINNER};
enum {OUT_OF_RANGE=-1, ODD, EVEN};

int notInRange(int square) {
  return(square < 1 || square > 100)?YES:NO;
}

int isEndOfRow(int square) {
  if (notInRange(square)) return OUT_OF_RANGE;
  if (square == 100) return WINNER; // I am making this up...
  return (square % 10 == 0)? YES:NO;
}

int rowType(unsigned int square) {
  // return 1 if square is in odd row (going to the right)
  // and 0 if square is in even row (going to the left)
  if (notInRange(square)) return OUT_OF_RANGE; // trap this error
  int rowNum = (square - 1) / 10;
  return (rowNum % 2 == 0) ? ODD:EVEN; // return 0 (ODD) for 1-10, 21-30 etc.
                                       // and 1 (EVEN) for 11-20, 31-40, ...
}

int main(void) {
  int a = 12;
  int rt;
  rt = rowType(a); // this replaces your obscure if statement

  // and here is how you handle the possible return values:
  switch(rt) {
  case ODD:
    printf("It is an odd row\n");
    break;
  case EVEN:
    printf("It is an even row\n");
    break;
  case OUT_OF_RANGE:
    printf("It is out of range\n");
    break;
  default:
    printf("Unexpected return value from rowType!\n");
  }

  if(isEndOfRow(10)==YES) printf("10 is at the end of a row\n");
  if(isEndOfRow(100)==WINNER) printf("We have a winner!\n");
}
于 2014-04-29T22:32:26.773 に答える
0

他の人が指摘しているように、条件をより簡潔にしても、コンパイルや実行が高速化されるわけではなく、必ずしも読みやすさにも役立つわけではありません。

後で 6 x 6 ボードで幼児用バージョンのゲームが必要な場合や、40 x 50 ボードで上級バージョン (一晩中プレイできる) が必要な場合に備えて、プログラムをより柔軟にするのに役立ちます。 .

したがって、次のようにコーディングします。

// What is the size of the game board?
#define ROWS            10
#define COLUMNS         10

// The numbers of the squares go from 1 (bottom-left) to (ROWS * COLUMNS)
// (top-left if ROWS is even, or top-right if ROWS is odd)
#define firstSquare     1
#define lastSquare      (ROWS * COLUMNS)
// We haven't started until we roll the die and move onto the first square,
// so there is an imaginary 'square zero'
#define notStarted(num) (num == 0)
// and we only win when we land exactly on the last square
#define finished(num)   (num == lastSquare)
#define overShot(num)   (num > lastSquare)

// We will number our rows from 1 to ROWS, and our columns from 1 to COLUMNS
// (apologies to C fanatics who believe the world should be zero-based, which would
//  have simplified these expressions)
#define getRow(num)   (((num - 1) / COLUMNS) + 1)
#define getCol(num)   (((num - 1) % COLUMNS) + 1)

// What direction are we moving in?
// On rows 1, 3, 5, etc. we go from left to right
#define isLeftToRightRow(num)    ((getRow(num) % 2) == 1)
// On rows 2, 4, 6, etc. we go from right to left
#define isRightToLeftRow(num)    ((getRow(num) % 2) == 0)

// Are we on the last square in the row?
#define isLastInRow(num)    (getCol(num) == COLUMNS)

// And finally we can get onto the code

if (notStarted(mySquare))
{
  // Some code for when we haven't got our piece on the board yet
}
else
{
  if (isLastInRow(mySquare))
  {
    // Some code for when we're on the last square in a row
  }


  if (isRightToLeftRow(mySquare))
  {
    // Some code for when we're travelling from right to left
  }
  else
  {
    // Some code for when we're travelling from left to right
  }
}

はい、冗長ですが、ゲーム ボードで何が起こっているかを正確に明確にします。

このゲームを携帯電話やタブレットで表示するように開発する場合、定数の代わりに ROWS 変数と COLUMNS 変数を作成して、(ゲームの開始時に) 画面のサイズと向きに合わせて動的に設定できるようにします。

また、ゲームの途中でいつでも画面の向きを変更できるようにします。必要なのは、ROWS と COLUMNS の値を切り替えるだけで、他のすべて (各プレイヤーがオンになっている現在の平方数と、すべてのヘビとはしごの開始/終了マス) は変更されません。次に、ボードをうまく描画し、アニメーションのコードを記述する必要があります(それがあなたのifステートメントの目的だったと思います)...

于 2014-04-30T01:39:35.380 に答える
0

この質問には非常に多くの答えがあることは知っていますが、とにかくここに私のものを投げます...

Steve McConnell のCode Complete、第 2 版からの引用: "階段状のアクセス テーブル:

さらに別の種類のテーブル アクセスは、階段方式です。このアクセス方法は、インデックス構造ほど直接的ではありませんが、データ スペースを無駄にしません。図 18-5 に示されている階段構造の一般的な考え方は、テーブル内のエントリが個別のデータ ポイントではなく、データの範囲に対して有効であるということです。

ここに画像の説明を入力してください

図 18-5 階段アプローチでは、「階段」に到達するレベルを決定することによって、各エントリを分類します。ヒットした「ステップ」によって、そのカテゴリが決まります。

たとえば、評価プログラムを作成している場合、「B」のエントリ範囲は 75% から 90% になる可能性があります。いつかプログラムしなければならない可能性のある学年は次のとおりです。

ここに画像の説明を入力してください

階段法を使用するには、各範囲の上限をテーブルに入れ、各範囲の上限に対してスコアをチェックするループを記述します。スコアが最初に範囲の上限を超えるポイントを見つけると、グレードが何であるかがわかります。階段状の手法では、範囲のエンドポイントを適切に処理するように注意する必要があります。この例に基づいて学生のグループに成績を割り当てる Visual Basic のコードを次に示します。

ここに画像の説明を入力してください

これは単純な例ですが、簡単に一般化して、複数の学生、複数の採点方式 (たとえば、異なる課題の異なるポイント レベルに対する異なる成績)、および採点方式の変更を処理できます。」

Code Complete、第 2 版、426 ~ 428 ページ (第 18 章)。

于 2014-04-30T17:27:26.570 に答える