Xác định xem một số có phải là bội số của mười hay trong một tập hợp phạm vi cụ thể hay không


103

Tôi có một vài vòng lặp mà tôi cần trong chương trình của mình. Tôi có thể viết ra mã giả nhưng tôi không hoàn toàn chắc chắn về cách viết chúng một cách hợp lý.

Tôi cần -

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

Đây là trò chơi trên bàn cờ rắn và thang, nếu nó có ý nghĩa hơn đối với câu hỏi của tôi.

Tôi tưởng tượng câu lệnh if đầu tiên tôi sẽ cần sử dụng modulus, if (num == 100%10)có đúng không?

Cái thứ hai tôi không biết. Tôi có thể viết nó ra như thế if (num > 10 && num is < 21 || etc)nhưng phải có thứ gì đó thông minh hơn thế.


16
Nói chung, độ dài của mã tốt tỷ lệ với độ dài của tiếng Anh mô tả những gì nó làm. Vì vậy, khi "đặc điểm kỹ thuật" của bạn cho biết 11-20, 31-40, 51-60, 71-80, 91-100, bạn có thể mong đợi mã của mình cũng đề cập đến những con số đó. Nếu những con số đó đến từ một nơi nào đó hoặc được tạo ra bởi một số lý do, hãy xem liệu bạn có thể mã hóa lý do đó thay vì những con số hay không.
luqui

39
@ user3419168: Trình biên dịch không quan tâm đến việc mã của bạn có thể đọc được hay không; nó sẽ biên dịch nó trong một phần của giây. Nhưng đối với những người đọc mã của bạn, những lựa chọn bạn đưa ra có thể khiến nó được hiểu trong vài giây, vài phút, vài giờ hoặc không bao giờ. Điều này đặt ra một chi phí; mọi người được trả tiền để đọc và hiểu mã, vì vậy hãy làm cho chúng dễ dàng. Luôn viết mã sản xuất để tối đa hóa khả năng đọc và hãy nhớ rằng sự ngắn gọn không nhất thiết làm cho mã hoạt động tốt hơn.
Eric Lippert

2
@AmadeusDrZaius - Tôi RẤT RẤT RẤT RẤT RẤT đã làm điều tương tự, nhưng chỉ cho các phần quan trọng về hiệu suất. Vòng lặp chặt chẽ nhất được gọi là 100 triệu lần đủ điều kiện - câu lệnh if trong trò chơi rắn và thang thì không. Nơi bạn vẽ ranh giới giữa chúng là một lựa chọn cá nhân.
Floris

2
Tôi ghét phải nói điều đó, nhưng đã làm đủ công việc của công ty, với những người mới bắt đầu viết mã thực sự, tôi sẽ khuyên bạn nên ép buộc nó một cách thô bạo. Vì khi đó các chàng mới hiểu và không phạm. buồn nhưng có thật - trong một số trường hợp, nó thông minh đến mức ngu ngốc.
Richard Le Mesurier

22
Đây là một câu hỏi hay và tôi không muốn lấy đi bất cứ thứ gì trên tấm áp phích cả, nhưng điều này không xứng đáng với hơn 500 điểm. Đây là cách chúng tôi kết thúc với một số điều vô nghĩa mà chúng tôi làm với những người có hàng ngàn điểm dường như là chính quyền ở đây. (Vui lòng di chuyển nhận xét này nếu nó thuộc về nơi khác.)
GaTechThomas

Câu trả lời:


86

Đối với cách đầu tiên, để kiểm tra xem một số có phải là bội số hay không:

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

Đối với cái thứ hai:

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

Nhưng điều đó khá dày đặc và tốt hơn hết là bạn nên liệt kê các tùy chọn một cách rõ ràng.


Bây giờ bạn đã đưa ra ý tưởng tốt hơn về những gì bạn đang làm, tôi sẽ viết câu thứ hai là:

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

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

Đó là cùng một logic, nhưng bằng cách sử dụng hàm, chúng ta sẽ hiểu rõ hơn về ý nghĩa của nó.


79
if((num - 1) / 10) % 2 == 1 && num < 100)- Tôi sẽ khóc nếu tôi thấy điều đó.
Daniel Kamil Kozar

32
@DanielKamilKozar, như bạn nên làm.
Winston Ewert

2
@ user3419168, chỉ riêng bản thân nó đã khiến người ta phải tự hỏi nó có nghĩa là gì trên đời. Nó không đưa ra gợi ý về những gì trên thế giới mà nó đang cố gắng làm. Đó là lý do tại sao trong bản chỉnh sửa, tôi đã đưa ra một phiên bản chia logic thành một hàm giúp làm rõ hơn những gì các phép tính thực sự đang thực hiện.
Winston Ewert

3
Cũng có thể thận trọng khi khẳng định num >= 11như (1) rằng giới hạn dưới bị loại trừ, và (2) %trên một số âm cũng trả về một số âm. (Tôi phải thừa nhận việc sử dụng & 1ở đây là "an toàn hơn" nhưng cũng giả định kiến ​​thức bổ sung.)
usr2564301

2
+1 cho Chỉnh sửa, nó đi vào lý do của danh sách các phạm vi và trình bày nó theo cách dễ đọc. IMO, một bước nữa sẽ là bọc getRow(num) % 2 == 0một hàm trong một hàm để làm cho nó rõ ràng mục đích là gì. bool inEvenRow(int num){ return getRow(num) % 2 ==0;}
Mr.Mindor

40

if (num là bội số của 10) {do this}

if (num % 10 == 0) {
  // Do something
}

if (num nằm trong khoảng 11-20, 31-40, 51-60, 71-80, 91-100) {do this}

Bí quyết ở đây là tìm kiếm một số loại điểm chung giữa các phạm vi. Tất nhiên, bạn luôn có thể sử dụng phương pháp "brute force":

if ((num > 10 && num <= 20) ||
    (num > 30 && num <= 40) ||
    (num > 50 && num <= 60) ||
    (num > 70 && num <= 80) ||
    (num > 90 && num <= 100)) {
  // Do something
}

Nhưng bạn có thể nhận thấy rằng, nếu bạn trừ đi 1từ num, bạn sẽ có dãy:

10-19, 30-39, 50-59, 70-79, 90-99

Nói cách khác, tất cả các số có hai chữ số mà chữ số đầu tiên là số lẻ. Tiếp theo, bạn cần đưa ra một công thức thể hiện điều này. Bạn có thể lấy chữ số đầu tiên bằng cách chia cho 10 và bạn có thể kiểm tra xem nó có lẻ không bằng cách kiểm tra phần dư là 1 khi bạn chia cho 2. Cộng tất cả lại với nhau:

if ((num > 0) && (num <= 100) && (((num - 1) / 10) % 2 == 1)) {
  // Do something
}

Với sự cân bằng giữa mã dài hơn nhưng có thể bảo trì và mã ngắn hơn "thông minh", tôi sẽ chọn dài hơn và rõ ràng hơn mọi lúc. Ít nhất, nếu bạn cố gắng trở nên thông minh, vui lòng gửi kèm một nhận xét giải thích chính xác những gì bạn đang cố gắng hoàn thành.

Nó giúp giả sử nhà phát triển tiếp theo làm việc trên mã được trang bị và biết bạn sống ở đâu. :-)


7
Tôi vẫn muốn tìm mã thông minh, nhưng biến nó thành mã có thể bảo trì bằng cách trích xuất các hàm. Nó sẽ dễ đọc hơn nếu bit cuối cùng đó nói && isTensDigitOdd(num), có lẽ với một nhận xét trước định nghĩa hàm giải thích chức năng của nó. Nếu một mẫu như vậy tồn tại, một nhận xét giải thích lý do cho mẫu sẽ khai sáng cho imo khả năng bảo trì.
chris

3
Chris, đó là một chiến lược tuyệt vời khi "sự thông minh" có lợi thế rõ ràng: mã ngắn hơn nhiều (có nghĩa là ít khả năng mắc lỗi chính tả hơn, đặc biệt nếu nó thay đổi) hoặc cải thiện lớn về hiệu quả. Hầu như luôn có sự cân bằng giữa sự ngắn gọn, rõ ràng và hiệu quả, và tìm ra một sự thỏa hiệp tốt là một kỹ năng tuyệt vời để phát triển. (Xem stackoverflow.com/a/2151844/29157 cho một snicker.)
Adam Liss

1
Đây là một cách tiếp cận tốt hơn nhiều. Vì vậy, dễ hiểu hơn nhiều so với 'mã thông minh' và sự khác biệt về hiệu suất có lẽ là không đáng kể.
user1477388

@AdamLiss, Vâng, ý kiến ​​của tôi không có giá trị vì tôi chưa có đủ kinh nghiệm để thấy hậu quả của những quyết định này. Tôi chắc chắn rằng tôi sẽ sớm có đủ và tôi chắc chắn sẽ có ý kiến ​​thứ hai nếu cần.
chris

1
Đừng bán khống bản thân. Bản năng của bạn rất nhạy cảm và bạn có vẻ mong muốn tiếp tục học hỏi. Mọi ý kiến ​​đều có giá trị nếu có lý do chính đáng đằng sau nó ... và đôi khi ngay cả khi không có. Tôi dám cá rằng bạn sẽ đi xa.
Adam Liss,

30

Nếu bạn đang sử dụng GCC hoặc bất kỳ trình biên dịch nào hỗ trợ phạm vi trường hợp, bạn có thể làm điều này, nhưng mã của bạn sẽ không di động được .

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;
}

1
Bạn có thể vui lòng cho tôi biết tại sao mã này không phải là xách tay?
M Sharath Hegde

8
@MSharathHegde bởi vì nó đòi hỏi phải mở rộng GCC, mà không phải là một phần của tiêu chuẩn và một số trình biên dịch sẽ không hỗ trợ nó
Bryan Chen

5
Đây là câu trả lời đúng, bởi vì nó ngay lập tức rõ ràng mục đích là gì. Tất cả những câu trả lời 'thông minh' đó với modulo là một cơn ác mộng bảo trì, ngay cả với các bình luận.
smirkingman

@smirkingman Thật vậy, đó là những gì tôi đã nói trong nhận xét của mình cho câu hỏi chính. Chỉ cần một số kinh nghiệm của các lập trình viên mới trong công việc của công ty để nhận ra rằng cách rõ ràng thường tốt hơn cách thông minh của ninja.
Richard Le Mesurier

15

Điều này dành cho khách truy cập trong tương lai nhiều hơn là người mới bắt đầu. Đối với một giải pháp giống thuật toán tổng quát hơn, bạn có thể lấy danh sách các giá trị bắt đầu và kết thúc và kiểm tra xem giá trị được truyền có nằm trong một trong số chúng hay không:

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;
    });
}

Để đơn giản, tôi đã sử dụng lambda đa hình (C ++ 14) thay vì một pairđối số rõ ràng . Điều này có lẽ cũng nên tuân theo việc sử dụng <==phù hợp với các thuật toán tiêu chuẩn, nhưng nó hoạt động như vậy miễn là Elemđã <=xác định cho nó. Dù sao, nó có thể được sử dụng như thế này:

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);

Có một ví dụ trực tiếp ở đây .


Giải pháp gọn gàng. Tôi có thể đã sử dụng một mảng duy nhất, vì bạn có thể định dạng nó với 2 số trên mỗi dòng để đại diện cho các cặp.
Kevin Lam

@ HunterGuy2, Điểm rất hay. Tôi thực sự sẽ thay đổi nó để hoạt động trên các cặp vì tôi chỉ nghĩ về trình vòng lặp zip vì một số lý do.
chris

Cách tiếp cận stl thực sự tốt đẹp! Yêu nó!
higuaro

5

Điều đầu tiên là dễ dàng. Bạn chỉ cần áp dụng toán tử modulo cho giá trị num của mình:

if ( ( num % 10 ) == 0)

Vì C ++ đang đánh giá mọi số không phải là 0 là đúng, bạn cũng có thể viết:

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

Đối với điều thứ hai, tôi nghĩ điều này dễ hiểu hơn:

Mẫu lặp lại sau mỗi 20, vì vậy bạn có thể tính toán modulo 20. Tất cả các phần tử bạn muốn sẽ nằm trong một hàng ngoại trừ những phần tử có giá trị chia hết cho 20.

Để có được những số đó, chỉ cần sử dụng num-1 hoặc num + 19 để tránh giao dịch với các số âm.

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

Điều này giả sử mô hình lặp lại mãi mãi, vì vậy đối với 111-120, nó sẽ áp dụng lại, v.v. Nếu không, bạn cần giới hạn số lượng ở 100:

if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )

5

Với một vài nhận xét tốt trong mã, nó có thể được viết khá ngắn gọn và dễ đọc.

// 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 { ... }

2
Nhận xét đầu tiên là không cần thiết. Bất kỳ lập trình viên nào có một chút kinh nghiệm sẽ biết rằng num % 10 == 0điều đó giống như numbội số của 10.
Justin

7
có nhưng người mới bắt đầu cũng đọc trang web này. Tôi thường sẽ không sử dụng nhận xét đó trong mã của riêng mình nhưng nó làm cho câu trả lời rõ ràng hơn cho những người mới bắt đầu, những người sẽ được hưởng lợi từ câu hỏi dành cho người mới bắt đầu này.
La-comadreja

2
Xin đừng bao giờ làm điều này. Nó thực sự làm giảm khả năng đọc, bằng cách làm chậm người đọc và buộc họ phải đọc mọi thứ hai lần. Bất kỳ lập trình viên nào không hiểu điều đó cũng if (num % 10 == 0)có nghĩa là // Check if it's a multiple of 10không nên duy trì mã của bạn . Đây là một mẫu chống nổi tiếng.
Dawood ibn Kareem

1
@DavidWallace xem nhận xét ở trên. Chúng tôi không thể đảm bảo rằng độc giả của bài đăng này sẽ biết kiểu chống đối này.
La-comadreja

1
Không, ý tôi là bình luận từng dòng để nói nó làm gì là phản khuôn mẫu. Ý tôi không phải là sử dụng %là chống lại khuôn mẫu; rõ ràng là nó không phải. Thực sự, giả sử rằng nhiều người đọc bài đăng này là người mới bắt đầu, việc dạy họ phong cách viết bình luận này sẽ đóng góp tiêu cực vào sự phát triển của họ với tư cách là lập trình viên.
Dawood ibn Kareem

4

Về cơ bản, bạn đã tự giải thích câu trả lời, nhưng đây là mã đề phòng.

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
}

2
Sửa lại x < 41 x > 50và đặt dấu ngoặc đơn.
101010

1
@ 40two, Về mặt kỹ thuật, operator&&có mức độ ưu tiên cao hơn operator||, vì vậy nó ổn, nhưng tôi khá chắc chắn rằng GCC vẫn cảnh báo về điều đó.
chris

18
Cân nhắc đại diện cho sự bất bình đẳng 10 < x < 21như 10 < x && x < 21hơn x > 10 && x < 21. Sẽ dễ dàng hơn để đọc bất đẳng thức khi nó có cùng thứ tự như khi bạn viết nó bằng toán học.
Eric Lippert

5
Mã này khá khó đọc và nói rất ít về logic thực tế. Tôi không thích câu trả lời này.
Dariusz

3
Tôi không đồng ý điều này vì bạn đã trả lời chính xác những gì OP đã làm.
Bruno Ferreira

3

Bạn có thể đang suy nghĩ quá mức về điều này.

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

Dòng đầu tiên if (x % 10)hoạt động vì (a) một giá trị là bội số của 10 được tính là '0', các số khác dẫn đến phần còn lại của chúng, (b) giá trị 0 trong an ifđược coi là falsegiá trị bất kỳ khác true.

Biên tập:

Để chuyển đổi qua lại ở tuổi đôi mươi, hãy sử dụng thủ thuật tương tự. Lần này, số quan trọng là 10:

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

x/10trả về bất kỳ số nào từ 0 đến 9 0, 10 đến 19 1, v.v. Thử nghiệm trên chẵn hay lẻ - the & 1- cho bạn biết nó chẵn hay lẻ. Vì phạm vi của bạn thực sự là "11 đến 20", hãy trừ đi 1 trước khi thử nghiệm.


1

Lời cầu xin cho sự dễ đọc

Trong khi bạn đã có một số câu trả lời tốt, tôi muốn giới thiệu một kỹ thuật lập trình giúp mã của bạn dễ đọc hơn đối với một số người đọc trong tương lai - đó có thể là bạn trong sáu tháng, một đồng nghiệp được yêu cầu thực hiện đánh giá mã, người kế nhiệm của bạn, .. .

Đây là gói bất kỳ câu lệnh "thông minh" nào vào một hàm hiển thị chính xác (với tên của nó) những gì nó đang làm. Mặc dù có một tác động nhỏ đến hiệu suất (từ "chức năng gọi chi phí"), điều này thực sự không đáng kể trong tình huống trò chơi như thế này.

Trong quá trình này, bạn có thể khử trùng đầu vào của mình - ví dụ: kiểm tra các giá trị "bất hợp pháp". Vì vậy, bạn có thể kết thúc với mã như thế này - hãy xem nó dễ đọc hơn bao nhiêu? "Các chức năng trợ giúp" có thể bị ẩn đi đâu đó (không cần thiết phải có trong mô-đun chính: nó rõ ràng từ tên của họ những gì họ làm):

#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");
}

3
Nó không phải là cố gắng đẩy nó quá xa với YESNO?
rmobis,

@Raphael_ - cũng có thể là: Tôi chỉ hiển thị một "ví dụ". Nhiều người sử dụng true / false, hiển nhiên. Nhưng tôi không bao giờ có thể nhớ (vì ngôn ngữ khác nhau sử dụng quy ước khác nhau): là là TRUE, Truehoặc true? Và những gì, nếu có, các tệp tiêu đề tôi sẽ cần bao gồm trong C thông thường? Vì vậy, tôi tự lăn. Wonder nếu đó là những gì có một downvote ...
Floris

1

Đối với cái đầu tiên:

if (x % 10 == 0)

sẽ áp dụng cho:

10, 20, 30, .. 100 .. 1000 ...

Đối với cái thứ hai:

if (((x-1) / 10) % 2 == 1)

sẽ áp dụng cho:

11-20, 31-40, 51-60, ..

Về cơ bản, trước tiên chúng tôi làm x-1để có được:

10-19, 30-39, 50-59, ..

Sau đó, chúng tôi chia chúng 10cho:

1, 3, 5, ..

Vì vậy, chúng tôi kiểm tra xem kết quả này có phải là kỳ lạ hay không.


1

Bạn có thể thử những cách sau:

        // 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
        }

Trong câu hỏi OP, kiểm tra bội số của 10 không liên quan đến kiểm tra phạm vi và trong phạm vi kiểm tra 20 cần phải nằm trên cùng phạm vi 11, với mã của bạn ((20/10)% 2) -> ( 2% 2) -> 0
Serpiton

0

Tôi biết rằng câu hỏi này có rất nhiều câu trả lời, nhưng dù sao thì tôi cũng sẽ ném vào đây ...

Lấy từ Mã Hoàn thành của Steve McConnell , Ấn bản thứ 2: "Bảng Truy cập Bậc thang:

Tuy nhiên, một kiểu tiếp cận bảng khác là phương pháp bậc thang. Phương thức truy cập này không trực tiếp như cấu trúc chỉ mục, nhưng nó không lãng phí nhiều không gian dữ liệu. Ý tưởng chung của cấu trúc bậc thang, được minh họa trong Hình 18-5, là các mục nhập trong bảng có giá trị cho các dải dữ liệu hơn là cho các điểm dữ liệu riêng biệt.

Nhập mô tả hình ảnh tại đây

Hình 18-5 Cách tiếp cận bậc cầu thang phân loại từng lối vào bằng cách xác định mức độ mà nó chạm vào “cầu thang”. "Bước" mà nó truy cập xác định danh mục của nó.

Ví dụ: nếu bạn đang viết một chương trình chấm điểm, phạm vi mục nhập “B” có thể từ 75 phần trăm đến 90 phần trăm. Dưới đây là một loạt các điểm bạn có thể phải lập trình vào một ngày nào đó:

Nhập mô tả hình ảnh tại đây

Để sử dụng phương pháp bậc thang, bạn đặt đầu trên của mỗi phạm vi vào một bảng và sau đó viết một vòng lặp để kiểm tra điểm so với đầu trên của mỗi phạm vi. Khi bạn tìm thấy điểm mà điểm đầu tiên vượt quá đỉnh của một phạm vi, bạn sẽ biết điểm đó là bao nhiêu. Với kỹ thuật bậc thang, bạn phải cẩn thận để xử lý các điểm cuối của dãy đúng cách. Đây là mã trong Visual Basic chỉ định điểm cho một nhóm sinh viên dựa trên ví dụ này:

Nhập mô tả hình ảnh tại đây

Mặc dù đây là một ví dụ đơn giản, bạn có thể dễ dàng tổng quát hóa nó để xử lý nhiều học sinh, nhiều sơ đồ chấm điểm (ví dụ: các điểm khác nhau cho các mức điểm khác nhau trên các bài tập khác nhau) và các thay đổi trong sơ đồ chấm điểm. "

Code Complete , Tái bản lần 2, trang 426 - 428 (Chương 18).


tại sao bạn nghĩ rằng đây là câu hỏi sai? chỉ vì tôi không cung cấp ví dụ về trường hợp OP không có nghĩa là tôi đã trả lời sai câu hỏi ...
lauCosma

0

Như những người khác đã chỉ ra, việc làm cho các điều kiện ngắn gọn hơn sẽ không làm tăng tốc độ biên dịch hoặc thực thi và nó cũng không nhất thiết giúp ích cho việc dễ đọc.

Nó có thể giúp làm cho chương trình của bạn linh hoạt hơn, trong trường hợp sau này bạn quyết định rằng bạn muốn phiên bản trò chơi dành cho trẻ mới biết đi trên bảng 6 x 6 hoặc phiên bản nâng cao (bạn có thể chơi suốt đêm) trên bảng 40 x 50 .

Vì vậy, tôi sẽ viết mã nó như sau:

// 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
  }
}

Vâng, nó dài dòng, nhưng nó làm cho nó rõ ràng chính xác những gì đang xảy ra trên bảng trò chơi.

Nếu tôi đang phát triển trò chơi này để hiển thị trên điện thoại hoặc máy tính bảng, tôi sẽ tạo các biến ROWS và COLUMNS thay vì các hằng số để chúng có thể được đặt động (khi bắt đầu trò chơi) để phù hợp với kích thước và hướng màn hình.

Tôi cũng sẽ cho phép thay đổi hướng màn hình bất kỳ lúc nào, giữa trận đấu - tất cả những gì bạn cần làm là chuyển đổi các giá trị của ROWS và COLUMNS, trong khi để lại mọi thứ khác (số bình phương hiện tại mà mỗi người chơi đang sử dụng và hình vuông bắt đầu / kết thúc của tất cả các con rắn và thang) không thay đổi. Sau đó, bạn 'chỉ' phải vẽ bảng thật đẹp và viết mã cho các hoạt ảnh của bạn (tôi cho rằng đó là mục đích của các ifcâu lệnh của bạn ) ...


Tôi cũng đã bỏ phiếu cao cho câu trả lời của Floris - một phong cách khác để đạt được kết quả tương tự, mà tôi chưa thấy trước khi viết câu trả lời của mình
Laurence Renshaw

2
bạn nên sử dụng hàm nội tuyến thay vì#define
Bryan Chen

Thực hành tốt khi bạn sử dụng các #definehướng dẫn giống như hàm , để đặt dấu ngoặc đơn xung quanh các đối số, nơi chúng xuất hiện trong phần mở rộng. Vì vậy, thay vì #define finished(num) (num == lastSquare)bạn nên viết #define finished(num) ((num) == lastSquare). Lý do là nếu bạn sử dụng một lệnh như vậy với biểu thức chứa toán tử có độ ưu tiên đủ thấp, bạn sẽ không nhận được câu trả lời như mong đợi. Trong trường hợp này, nếu bạn không sử dụng dấu ngoặc đơn, thì việc finished(a & b)mở rộng vào (a & b == lastSquare)đó gần như chắc chắn không phải là điều bạn muốn.
Dawood ibn Kareem
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.