Menentukan apakah suatu bilangan adalah kelipatan sepuluh atau dalam satu set rentang tertentu

103

Saya memiliki beberapa loop yang saya perlukan dalam program saya. Saya dapat menulis kode pseudo tetapi saya tidak sepenuhnya yakin bagaimana menulisnya secara logis.

Saya butuh -

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

Ini untuk permainan papan ular tangga, jika pertanyaan saya lebih masuk akal.

Saya membayangkan yang pertama jika pernyataan saya harus menggunakan modulus, apakah if (num == 100%10)benar?

Yang kedua saya tidak tahu. Saya bisa menuliskannya seperti if (num > 10 && num is < 21 || etc)tetapi harus ada sesuatu yang lebih pintar dari itu.

pengguna3419168
sumber
16
Umumnya, panjang kode yang baik sebanding dengan panjang bahasa Inggris yang menjelaskan fungsinya. Jadi, jika "spesifikasi" Anda menyatakan 11-20, 31-40, 51-60, 71-80, 91-100, Anda dapat mengharapkan kode Anda menyebutkan angka-angka itu juga. Jika nomor-nomor itu berasal dari suatu tempat atau dibuat karena suatu alasan, lihat apakah Anda dapat membuat kode alasannya daripada nomornya.
luqui
39
@ user3419168: Kompilator tidak peduli seberapa terbaca kode Anda; itu akan menyusunnya dalam sepersekian detik. Tetapi bagi manusia yang membaca kode Anda, pilihan yang Anda buat dapat membuatnya dipahami dalam hitungan detik, menit, jam, atau tidak pernah. Ini membebankan biaya; orang dibayar untuk membaca dan memahami kode, jadi permudah mereka. Selalu tulis kode produksi untuk memaksimalkan keterbacaan, dan ingat bahwa kesimpulan tidak selalu membuat kode bekerja lebih baik.
Eric Lippert
2
@AmadeusDrZaius - Saya sangat jarang melakukan hal yang sama, tetapi hanya untuk bagian kinerja yang penting. Putaran paling ketat yang disebut 100 juta kali memenuhi syarat - pernyataan if dalam permainan ular tangga tidak memenuhi syarat. Di mana Anda menarik garis di antara mereka adalah pilihan pribadi.
Floris
2
Saya benci mengatakannya, tetapi setelah melakukan pekerjaan korporat yang cukup, dengan pemula menulis kode nyata, saya harus merekomendasikan pemaksaan kasar. Karena dengan begitu orang baru akan memahaminya dan tidak akan merusaknya. sedih tapi benar - dalam beberapa kasus adalah pintar untuk menjadi bodoh.
Richard Le Mesurier
22
Ini adalah pertanyaan yang layak, dan saya sama sekali tidak ingin menghilangkan apa pun dari poster, tetapi ini tidak pantas mendapatkan 500+ poin. Ini adalah bagaimana kami berakhir dengan beberapa omong kosong yang kami lakukan dengan orang-orang dengan ribuan poin yang tampak seperti otoritas di sini. (Jangan ragu untuk memindahkan komentar ini jika ada di tempat lain.)
GaTechThomas

Jawaban:

86

Untuk yang pertama, untuk memeriksa apakah suatu bilangan adalah kelipatan penggunaan:

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

Untuk yang kedua:

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

Tapi itu agak padat, dan Anda mungkin lebih baik hanya mencantumkan opsi secara eksplisit.


Sekarang setelah Anda memberikan gambaran yang lebih baik tentang apa yang Anda lakukan, saya akan menulis yang kedua sebagai:

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

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

Logikanya sama, tetapi dengan menggunakan fungsi tersebut kami mendapatkan ide yang lebih jelas tentang apa artinya.

Winston Ewert
sumber
79
if((num - 1) / 10) % 2 == 1 && num < 100)- Aku akan menangis jika melihatnya.
Daniel Kamil Kozar
32
@DanielKamilKozar, sebagaimana mestinya.
Winston Ewert
2
@ user3419168, dengan sendirinya itu membuat orang bertanya-tanya apa artinya itu. Tidak ada petunjuk tentang apa yang coba dilakukan di dunia ini. Itu sebabnya dalam edit saya menunjukkan versi yang membagi logika menjadi fungsi yang membuatnya lebih jelas apa yang sebenarnya dilakukan perhitungan.
Winston Ewert
3
Mungkin bijaksana juga untuk menegaskan num >= 11sebagai (1) bahwa batas bawah dilarang, dan (2) %pada bilangan negatif juga menghasilkan bilangan negatif. (Saya harus mengakui bahwa menggunakan di & 1sini "lebih aman" tetapi juga mengasumsikan pengetahuan tambahan.)
usr2564301
2
+1 untuk Edit, itu masuk ke mengapa daftar rentang dan menyajikannya dengan cara yang dapat dibaca. IMO, satu langkah maju adalah membungkus getRow(num) % 2 == 0fungsi juga untuk membuatnya jelas apa maksudnya. bool inEvenRow(int num){ return getRow(num) % 2 ==0;}
Tuan Mindor
40

if (num adalah kelipatan 10) {do this}

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

if (nomor dalam 11-20, 31-40, 51-60, 71-80, 91-100) {lakukan ini}

Triknya di sini adalah mencari semacam kesamaan di antara rentang tersebut. Tentu saja, Anda selalu dapat menggunakan metode "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
}

Tetapi Anda mungkin memperhatikan bahwa, jika Anda mengurangi 1dari num, Anda akan memiliki rentang:

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

Dengan kata lain, semua angka dua digit yang digit pertamanya ganjil. Selanjutnya, Anda perlu membuat rumus yang mengungkapkan hal ini. Anda bisa mendapatkan digit pertama dengan membaginya dengan 10, dan Anda dapat menguji ganjilnya dengan memeriksa sisa 1 ketika Anda membagi dengan 2. Menyatukan semuanya:

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

Mengingat trade-off antara kode yang lebih panjang tetapi dapat dipelihara dan kode "pintar" yang lebih pendek, saya akan memilih yang lebih panjang dan lebih jelas setiap saat. Paling tidak, jika Anda mencoba untuk menjadi pintar, harap sertakan komentar yang menjelaskan dengan tepat apa yang ingin Anda capai.

Ini membantu untuk mengasumsikan pengembang berikutnya untuk mengerjakan kode dipersenjatai dan tahu di mana Anda tinggal. :-)

Adam Liss
sumber
7
Saya masih menggunakan kode pintar, tetapi mengubahnya menjadi kode yang dapat dipelihara dengan mengekstrak fungsi. Ini akan sama terbaca jika bit terakhir itu mengatakan && isTensDigitOdd(num), mungkin dengan komentar sebelum definisi fungsi menjelaskan apa yang dilakukannya. Jika pola seperti itu ada, komentar yang menjelaskan alasan pola tersebut mencerahkan imo rawatan.
chris
3
Chris, itu adalah strategi yang bagus ketika "kecerdasan" memiliki keuntungan yang jelas: kode yang jauh lebih pendek (yang berarti lebih sedikit kemungkinan kesalahan ketik, terutama jika berubah), atau peningkatan efisiensi yang besar. Hampir selalu ada pertukaran antara singkatnya, kejelasan, dan efisiensi, dan menemukan kompromi yang baik adalah keterampilan yang bagus untuk dikembangkan. (Lihat stackoverflow.com/a/2151844/29157 untuk cekikan.)
Adam Liss
1
Ini adalah pendekatan yang jauh lebih baik. Jauh lebih mudah dipahami daripada 'kode pintar' dan perbedaan kinerja mungkin dapat diabaikan.
pengguna1477388
@AdamLiss, Ya, pendapat saya tidak terlalu berharga karena saya belum memiliki cukup pengalaman untuk melihat dampak dari keputusan ini. Saya yakin saya akan segera melakukannya, dan saya pasti akan mendapatkan opini kedua jika diperlukan.
chris
1
Jangan menjual diri Anda sendiri. Naluri Anda sangat peka, dan Anda tampak bersemangat untuk terus belajar. Setiap opini berharga jika ada alasan bagus di baliknya ... dan terkadang bahkan jika tidak ada. Saya berani bertaruh bahwa Anda akan pergi jauh.
Adam Liss
30

Jika Anda menggunakan GCC atau kompiler apa pun yang mendukung rentang kasus, Anda dapat melakukannya, tetapi kode Anda tidak akan portabel .

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;
}
Bryan Chen
sumber
1
Bisakah Anda memberi tahu saya mengapa kode ini tidak portabel?
M Sharath Hegde
8
@MSharathHegde karena memerlukan ekstensi GCC, yang bukan bagian dari standar dan beberapa kompiler tidak mendukungnya
Bryan Chen
5
Ini jawaban yang benar, karena langsung terlihat apa maksudnya. Semua jawaban 'pintar' dengan modulo adalah mimpi buruk pemeliharaan, bahkan dengan komentar.
smirkingman
@smirkingman Memang itulah yang saya katakan dalam komentar saya untuk pertanyaan utama. Hanya dibutuhkan beberapa pengalaman pembuat kode baru dalam pekerjaan perusahaan untuk menyadari bahwa cara yang jelas seringkali jauh lebih baik daripada cara ninja pintar.
Richard Le Mesurier
15

Ini untuk pengunjung masa depan lebih dari pemula. Untuk solusi yang lebih umum dan mirip algoritme, Anda dapat mengambil daftar nilai awal dan akhir dan memeriksa apakah nilai yang diteruskan ada di dalam salah satunya:

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

Untuk kesederhanaan, saya menggunakan lambda polimorfik (C ++ 14) alih-alih pairargumen eksplisit . Ini mungkin juga harus tetap menggunakan <dan ==konsisten dengan algoritme standar, tetapi berfungsi seperti ini selama Elemtelah <=ditentukan untuk itu. Bagaimanapun, itu bisa digunakan seperti ini:

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

Ada contoh nyata di sini .

chris
sumber
Solusi yang rapi. Saya mungkin akan menggunakan satu array, karena Anda dapat memformatnya dengan 2 angka per baris untuk mewakili pasangan.
Kevin Lam
@ HunterGuy2, Poin yang sangat bagus. Saya sebenarnya akan mengubahnya untuk beroperasi berpasangan karena saya hanya memikirkan iterator zip untuk beberapa alasan.
chris
Pendekatan stl yang sangat bagus! Suka!
higuaro
5

Yang pertama mudah. Anda hanya perlu menerapkan operator modulo ke nilai num Anda:

if ( ( num % 10 ) == 0)

Karena C ++ mengevaluasi setiap angka yang bukan 0 sebagai benar, Anda juga bisa menulis:

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

Untuk yang kedua, saya pikir ini lebih bersih untuk dipahami:

Pola ini berulang setiap 20, sehingga Anda dapat menghitung modulo 20. Semua elemen yang Anda inginkan akan berada dalam satu baris kecuali elemen yang dapat dibagi 20.

Untuk mendapatkannya juga, gunakan saja num-1 atau lebih baik num + 19 untuk menghindari berurusan dengan bilangan negatif.

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

Ini mengasumsikan pola berulang selamanya, jadi untuk 111-120 itu akan berlaku lagi, dan seterusnya. Jika tidak, Anda perlu membatasi jumlahnya menjadi 100:

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

Dengan beberapa komentar bagus dalam kode, itu bisa ditulis dengan cukup ringkas dan mudah dibaca.

// 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 { ... }
La-comadreja
sumber
2
Komentar pertama tidak dibutuhkan. Setiap programmer dengan sedikit pengalaman akan tahu bahwa itu num % 10 == 0adalah hal yang sama numdengan kelipatan 10.
Justin
7
ya tapi pemula membaca situs ini juga. Saya biasanya tidak menggunakan komentar itu dalam kode saya sendiri tetapi itu membuat jawaban lebih jelas bagi para pemula yang akan mendapat manfaat dari pertanyaan pemula ini.
La-comadreja
2
Tolong jangan pernah melakukan ini. Ini sebenarnya mengurangi keterbacaan, dengan memperlambat pembaca dan memaksa mereka membaca semuanya dua kali. Setiap programmer yang tidak mengerti itu if (num % 10 == 0)berarti sama dengan // Check if it's a multiple of 10tidak boleh memelihara kode Anda . Ini adalah anti-pola yang terkenal.
Dawood ibn Kareem
1
@DavidWow lihat komentar di atas. Kami tidak dapat menjamin bahwa pembaca posting ini akan mengetahui anti-pola ini.
La-comadreja
1
Tidak, maksud saya mengomentari setiap baris untuk mengatakan apa yang dilakukannya adalah anti-pola. Saya tidak bermaksud bahwa menggunakan %adalah anti-pola; jelas tidak. Sungguh, dengan asumsi bahwa banyak pembaca posting ini adalah pemula, mengajari mereka gaya menulis komentar ini memberikan kontribusi negatif bagi perkembangan mereka sebagai programmer.
Dawood ibn Kareem
4

Anda pada dasarnya menjelaskan jawabannya sendiri, tetapi inilah kodenya untuk berjaga-jaga.

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
}
Henry Harris
sumber
2
Perbaiki x < 41 x > 50dan beri tanda kurung.
101010
1
@ 40two, Secara teknis, operator&&memiliki prioritas lebih tinggi daripada operator||, jadi tidak apa-apa, tapi saya cukup yakin GCC tetap memperingatkannya.
chris
18
Pertimbangkan untuk merepresentasikan ketidaksetaraan 10 < x < 21sebagai 10 < x && x < 21gantinya x > 10 && x < 21. Lebih mudah membaca pertidaksamaan jika urutannya sama seperti saat Anda menulisnya secara matematis.
Eric Lippert
5
Kode ini cukup tidak terbaca dan tidak banyak bicara tentang logika sebenarnya. Saya tidak suka jawaban ini.
Dariusz
3
Saya downvoting ini karena Anda menjawab persis apa yang dilakukan OP.
Bruno Ferreira
3

Anda mungkin terlalu memikirkan ini.

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

Baris pertama if (x % 10)berfungsi karena (a) nilai yang merupakan kelipatan 10 dihitung sebagai '0', angka lain menghasilkan sisa, (b) nilai 0 dalam an ifdianggap false, nilai lainnya dianggap true.

Edit:

Untuk beralih bolak-balik di usia dua puluhan, gunakan trik yang sama. Kali ini, angka pentingnya adalah 10:

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

x/10mengembalikan angka apa pun dari 0 hingga 9 sebagai 0, 10 hingga 19 sebagai 1dan seterusnya. Pengujian genap atau ganjil - itu & 1- memberi tahu Anda apakah genap atau ganjil. Karena rentang Anda sebenarnya adalah "11 sampai 20", kurangi 1 sebelum pengujian.

usr2564301
sumber
1

Permohonan agar mudah dibaca

Meskipun Anda sudah memiliki beberapa jawaban yang bagus, saya ingin merekomendasikan teknik pemrograman yang akan membuat kode Anda lebih mudah dibaca untuk beberapa pembaca yang akan datang - yaitu Anda dalam enam bulan, seorang kolega meminta untuk melakukan tinjauan kode, penerus Anda, .. .

Ini untuk membungkus setiap pernyataan "pintar" ke dalam fungsi yang menunjukkan dengan tepat (dengan namanya) apa yang dilakukannya. Meskipun ada dampak kecil pada kinerja (dari "fungsi pemanggilan overhead") ini benar-benar dapat diabaikan dalam situasi permainan seperti ini.

Sepanjang jalan Anda dapat membersihkan masukan Anda - misalnya, menguji nilai "ilegal". Jadi, Anda mungkin akan mendapatkan kode seperti ini - lihat seberapa jauh lebih mudah dibaca? "Fungsi pembantu" dapat disembunyikan di suatu tempat (tidak perlu berada di modul utama: jelas dari namanya apa fungsinya):

#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");
}
Floris
sumber
3
Bukankah itu mencoba untuk mendorongnya terlalu jauh dengan YESdan NO?
rmobis
@Raphael_ - mungkin saja: Saya hanya menunjukkan "misalnya". Banyak orang menggunakan benar / salah, jelas. Tapi aku tidak pernah ingat (karena bahasa yang berbeda menggunakan konvensi yang berbeda): adalah adalah TRUE, True, atau true? Dan apa, jika ada, file header yang perlu saya sertakan dalam C biasa? Jadi saya menggulung sendiri. Bertanya-tanya apakah itu yang mendapat suara negatif ...
Floris
1

Untuk yang pertama:

if (x % 10 == 0)

akan berlaku untuk:

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

Untuk yang kedua:

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

akan melamar:

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

Kami pada dasarnya pertama kali melakukan x-1untuk mendapatkan:

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

Kemudian kami membaginya dengan 10untuk mendapatkan:

1, 3, 5, ..

Jadi kami memeriksa apakah hasil ini ganjil.

Khaled.K
sumber
1

Anda dapat mencoba yang berikut ini:

        // 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
        }
ShalakaV
sumber
Dalam pertanyaan OP pemeriksaan kelipatan 10 tidak terkait dengan pemeriksaan kisaran, dan dalam pemeriksaan kisaran 20 harus berada pada kisaran yang sama dari 11, dengan kode Anda ((20/10)% 2) -> ( 2% 2) -> 0
Serpiton
0

Saya tahu bahwa pertanyaan ini memiliki begitu banyak jawaban, tetapi saya akan tetap melemparkan pertanyaan saya ke sini ...

Diambil dari Steve McConnell's Code Complete , Edisi ke-2: "Tabel Akses Tangga-Tangga:

Jenis akses meja lainnya adalah metode anak tangga. Metode akses ini tidak langsung seperti struktur indeks, tetapi tidak membuang banyak ruang data. Ide umum dari struktur anak tangga, yang diilustrasikan pada Gambar 18-5, adalah bahwa entri dalam tabel valid untuk rentang data daripada untuk titik data yang berbeda.

Masukkan deskripsi gambar di sini

Gambar 18-5 Pendekatan anak tangga mengkategorikan setiap entri dengan menentukan tingkat di mana ia mencapai "tangga". "Langkah" yang dipukul menentukan kategorinya.

Misalnya, jika Anda menulis program penilaian, kisaran entri "B" mungkin dari 75 persen hingga 90 persen. Berikut kisaran nilai yang mungkin harus Anda program suatu hari nanti:

Masukkan deskripsi gambar di sini

Untuk menggunakan metode anak tangga, Anda meletakkan ujung atas setiap rentang ke dalam tabel dan kemudian menulis putaran untuk memeriksa skor terhadap ujung atas setiap rentang. Saat Anda menemukan titik di mana skor pertama kali melebihi puncak rentang, Anda tahu berapa nilainya. Dengan teknik anak tangga, Anda harus berhati-hati untuk menangani titik akhir rentang dengan benar. Berikut kode dalam Visual Basic yang memberikan nilai kepada sekelompok siswa berdasarkan contoh ini:

Masukkan deskripsi gambar di sini

Meskipun ini adalah contoh sederhana, Anda dapat dengan mudah menggeneralisasikannya untuk menangani beberapa siswa, beberapa skema penilaian (misalnya, nilai yang berbeda untuk level poin yang berbeda pada tugas yang berbeda), dan perubahan dalam skema penilaian. "

Kode Lengkap , Edisi ke-2, halaman 426 - 428 (Bab 18).

lauCosma
sumber
Menurut Anda mengapa ini adalah pertanyaan yang salah? Hanya karena saya tidak memberikan contoh tentang kasus OP tidak berarti saya menjawab pertanyaan yang salah ...
lauCosma
0

Seperti yang ditunjukkan orang lain, membuat ketentuan lebih ringkas tidak akan mempercepat kompilasi atau eksekusi, dan juga tidak membantu keterbacaan.

Ini dapat membantu membuat program Anda lebih fleksibel, jika nanti Anda memutuskan bahwa Anda menginginkan versi balita dari permainan pada papan 6 x 6, atau versi lanjutan (yang dapat Anda mainkan sepanjang malam) pada papan 40 x 50 .

Jadi saya akan mengkodekannya sebagai berikut:

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

Ya, ini bertele-tele, tetapi menjelaskan dengan tepat apa yang terjadi di papan permainan.

Jika saya mengembangkan game ini untuk ditampilkan di ponsel atau tablet, saya akan membuat variabel BARIS dan KOLOM sebagai ganti konstanta, sehingga dapat disetel secara dinamis (di awal game) agar sesuai dengan ukuran dan orientasi layar.

Saya juga akan mengizinkan orientasi layar diubah kapan saja, di tengah permainan - yang perlu Anda lakukan hanyalah mengganti nilai ROWS dan COLUMNS, sambil meninggalkan yang lainnya (nomor kuadrat saat ini yang digunakan setiap pemain, dan kotak awal / akhir semua ular dan tangga) tidak berubah. Maka Anda 'hanya' harus menggambar papan dengan baik, dan menulis kode untuk animasi Anda (saya berasumsi bahwa itu adalah tujuan ifpernyataan Anda ) ...

Laurence Renshaw
sumber
Saya juga memilih jawaban Floris - gaya berbeda untuk mencapai hasil yang serupa, yang tidak saya lihat sebelum saya menulis jawaban saya
Laurence Renshaw
2
Anda harus menggunakan fungsi inline daripada#define
Bryan Chen
Ini adalah praktik yang baik ketika Anda menggunakan #defineinstruksi mirip fungsi , untuk meletakkan tanda kurung di sekitar argumen, di mana mereka muncul dalam perluasan. Jadi, alih-alih #define finished(num) (num == lastSquare)Anda harus menulis #define finished(num) ((num) == lastSquare). Alasannya adalah jika Anda menggunakan instruksi seperti itu dengan ekspresi yang mengandung operator dengan prioritas yang cukup rendah, Anda tidak akan mendapatkan jawaban yang Anda harapkan. Dalam kasus ini, jika Anda tidak menggunakan tanda kurung tambahan, lalu finished(a & b)meluas ke (a & b == lastSquare)yang hampir pasti bukan yang Anda inginkan.
Dawood ibn Kareem