プログラムで必要なループがいくつかあります。擬似コードを書き出すことはできますが、論理的にどのように書くかは完全にはわかりません。
私は欲しい -
_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)
は正しいでしょうか?
二つ目は私にはわからない。 if (num > 10 && num is < 21 || etc)
のように記述できますが、それよりももっとスマートなものが必要です。
最初の例では、数値が使用の倍数であるかどうかを確認します。
if (num % 10 == 0) // its divisible by 10
2番目の場合:
if(((num - 1) / 10) % 2 == 1 && num <= 100)
しかし、それはかなり高密度です。オプションを明示的にリストするだけの方が良いかもしれません。
int getRow(int num) {
return (num - 1) / 10;
}
if (getRow(num) % 2 == 0) {
}
同じロジックですが、関数を使用することで、その意味がより明確になります。
if(numは10の倍数){これを行う}
if (num % 10 == 0) {
// Do something
}
if(numは11-20、31-40、51-60、71-80、91-100の範囲内){これを行う}
ここでのコツは、範囲間のある種の共通性を探すことです。もちろん、常に「ブルートフォース」方式を使用できます:
if ((num > 10 && num <= 20) ||
(num > 30 && num <= 40) ||
(num > 50 && num <= 60) ||
(num > 70 && num <= 80) ||
(num > 90 && num <= 100)) {
// Do something
}
しかし、あなたは、num
から1
を引くと、範囲があることに気付くかもしれません:
10-19, 30-39, 50-59, 70-79, 90-99
つまり、最初の桁が奇数であるすべての2桁の数字。次に、これを表現する式を考え出す必要があります。 10で除算することで最初の桁を取得でき、2で除算するときに1の剰余をチェックすることで奇数であることをテストできます。すべてをまとめると:
if ((num > 0) && (num <= 100) && (((num - 1) / 10) % 2 == 1)) {
// Do something
}
長いが保守可能なコードと短い「賢い」コードの間のトレードオフを考えると、私は毎回より長く明確に選ぶでしょう。少なくとも、賢くしようとするなら、あなたが達成しようとしていることを正確に説明するコメントを含めてください。
コードで作業する次の開発者が武装しており、どこに住んでいるかを知っていると想定すると役立ちます。 :-)
GCCまたは Case Ranges をサポートするコンパイラを使用している場合、これを行うことができますが、コードはポータブルではありません
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;
}
これは初心者よりも将来の訪問者向けです。より一般的なアルゴリズムのような解決策として、開始値と終了値のリストを取得し、渡された値がそれらのいずれかに含まれているかどうかを確認できます。
template<typename It, typename Elem>
bool in_any_interval(It first, It last, const Elem &val) {
return std::any_of(first, last, [&val](const auto &p) {
return p.first <= val && val <= p.second;
});
}
簡単にするために、明示的なpair
引数の代わりにポリモーフィックラムダ(C++ 14)を使用しました。これはおそらく<
および==
は標準アルゴリズムと一貫性がありますが、Elem
が<=
に定義されています。とにかく、次のように使用できます。
std::pair<int, int> intervals[]{
{11, 20}, {31, 40}, {51, 60}, {71, 80}, {91, 100}
};
const int num = 15;
std::cout << in_any_interval(std::begin(intervals), std::end(intervals), num);
実例があります here 。
コードにいくつかの良いコメントがあれば、非常に簡潔かつ読みやすく書けます。
// 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 { ... }
最初の方法は簡単です。モジュロ演算子をnum値に適用するだけです。
if ( ( num % 10 ) == 0)
SInce c ++は0以外のすべての数値をtrueとして評価していますが、次のように書くこともできます。
if ( ! ( num % 10 ) ) //does not have a residue when devided by 10
2番目の場合、これは理解しやすいと思います。
パターンは20ごとに繰り返されるため、20を法として計算できます。20で割り切れる要素を除き、必要なすべての要素が1行になります。
これらも取得するには、負の数を処理しないように、num-1以上のnum + 19を使用します。
if ( ( ( num + 19 ) % 20 ) > 9 )
これは、パターンが永久に繰り返されることを前提としているため、111-120の場合は再び適用されます。それ以外の場合は、数値を100に制限する必要があります。
if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )
基本的には自分で答えを説明しましたが、念のためコードを示します。
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
}
あなたはこれを考え過ぎているかもしれません。
_if (x % 10)
{
.. code for 1..9 ..
} else
{
.. code for 0, 10, 20 etc.
}
_
最初の行if (x % 10)
は、(a)10の倍数である値が「0」として計算され、他の数値は残りのままになるため、(b)if
の値0 false
と見なされ、他の値はtrue
です。
編集:
20代で前後に切り替えるには、同じトリックを使用します。今回は、ピボット番号は_10
_です。
_if (((x-1)/10) & 1)
{
.. code for 10, 30, ..
} else
{
.. code for 20, 40, etc.
}
_
_x/10
_は、0から9までの任意の数を_0
_として、10から19までを_1
_などとして返します。偶数または奇数(_& 1
_)でテストすると、偶数か奇数かがわかります。実際の範囲は「11〜20」なので、テストする前に1を引きます。
最初の場合:
if (x % 10 == 0)
適用対象:
10, 20, 30, .. 100 .. 1000 ...
2番目の場合:
if (((x-1) / 10) % 2 == 1)
に適用されます:
11-20, 31-40, 51-60, ..
基本的に、最初にx-1
を実行して以下を取得します。
10-19, 30-39, 50-59, ..
次に、それらを10
で除算して取得します。
1, 3, 5, ..
したがって、この結果が奇数であるかどうかを確認します。
読みやすさを求める
すでにいくつかの良い答えがありますが、将来の読者がコードを読みやすくするプログラミング手法をお勧めします。6か月以内に、同僚がコードレビューの実行を依頼し、後継者になります。 。
これは、「巧妙な」ステートメントを、その名前で正確に実行していることを示す関数にラップすることです。パフォーマンスへの影響はごくわずかですが(「関数呼び出しのオーバーヘッド」から)、これはこのようなゲーム状況では本当に無視できます。
途中で入力をサニタイズできます-たとえば、「不正な」値をテストします。したがって、あなたはこのようなコードで終わるかもしれません-それがどれほど読みやすいか見てください? 「ヘルパー関数」はどこかに隠しておくことができます(メインモジュールにある必要はありません。名前から明らかなことです)。
#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");
}
以下を試すことができます:
// multiple of 10
if ((num % 10) == 0)
{
// Do something
}
else if (((num / 10) % 2) != 0)
{
//11-20, 31-40, 51-60, 71-80, 91-100
}
else
{
//other case
}
他の人が指摘しているように、条件をより簡潔にすることはコンパイルや実行の速度を上げることにはならず、読みやすさにも必ずしも役立ちません。
後で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
ステートメントの目的だったと思います)...
この質問にはたくさんの答えがあることはわかっていますが、とにかくここに投げます... Steve McConnellのCode Complete 2nd Editionから抜粋:「階段アクセステーブル:
さらに別の種類のテーブルアクセスは、階段状の方法です。このアクセス方法は、インデックス構造ほど直接的ではありませんが、データ領域を無駄にしません。図18-5に示されている階段構造の一般的な考え方は、テーブル内のエントリが個別のデータポイントではなくデータの範囲に対して有効であることです。
図18-5階段状アプローチは、「階段」に到達するレベルを決定することにより、各エントリを分類します。ヒットする「ステップ」がそのカテゴリを決定します。
たとえば、採点プログラムを作成している場合、「B」の入力範囲は75パーセントから90パーセントです。いつかプログラムしなければならないグレードの範囲は次のとおりです。
階段状の方法を使用するには、各範囲の上端をテーブルに入れてから、ループを記述して、各範囲の上端に対してスコアをチェックします。スコアが最初に範囲の上限を超えるポイントを見つけると、成績がわかります。階段状の手法では、範囲のエンドポイントを適切に処理するように注意する必要があります。この例に基づいて生徒のグループに評点を割り当てるVisual Basicのコードは次のとおりです。
これは簡単な例ですが、簡単に一般化して、複数の学生、複数の採点スキーム(たとえば、異なる割り当ての異なるポイントレベルの異なるグレード)、および採点スキームの変更を処理できます。
Code Complete 2nd Edition pages 426-428(Chapter 18)。これがお役に立てば幸いです。c++でコードを変換しなかったのでごめんなさい。しかし、あなたはその古い中国のsaying言を知っています。 :)