Bir istikameti 8 yöne sınıflandırırken if / else if zincirinden nasıl kaçınılır?


111

Takip koduna sahibim:

if (this->_car.getAbsoluteAngle() <= 30 || this->_car.getAbsoluteAngle() >= 330)
  this->_car.edir = Car::EDirection::RIGHT;
else if (this->_car.getAbsoluteAngle() > 30 && this->_car.getAbsoluteAngle() <= 60)
  this->_car.edir = Car::EDirection::UP_RIGHT;
else if (this->_car.getAbsoluteAngle() > 60 && this->_car.getAbsoluteAngle() <= 120)
  this->_car.edir = Car::EDirection::UP;
else if (this->_car.getAbsoluteAngle() > 120 && this->_car.getAbsoluteAngle() <= 150)
  this->_car.edir = Car::EDirection::UP_LEFT;
else if (this->_car.getAbsoluteAngle() > 150 && this->_car.getAbsoluteAngle() <= 210)
  this->_car.edir = Car::EDirection::LEFT;
else if (this->_car.getAbsoluteAngle() > 210 && this->_car.getAbsoluteAngle() <= 240)
  this->_car.edir = Car::EDirection::DOWN_LEFT;
else if (this->_car.getAbsoluteAngle() > 240 && this->_car.getAbsoluteAngle() <= 300)
  this->_car.edir = Car::EDirection::DOWN;
else if (this->_car.getAbsoluteAngle() > 300 && this->_car.getAbsoluteAngle() <= 330)
  this->_car.edir = Car::EDirection::DOWN_RIGHT;

ifZincirinden kaçınmak istiyorum ; gerçekten çirkin. Bunu yazmanın başka, muhtemelen daha temiz bir yolu var mı?


77
@Oraekiathis->_car.getAbsoluteAngle() Tüm çağlayandan önce bir kez geçerseniz çok daha az çirkin, daha az yazmak ve okumak daha iyi görünür .
πάντα ῥεῖ

26
this( this->) İle ilgili tüm bu açık başvurular gerekli değildir ve okunabilirlik için gerçekten iyi bir şey yapmaz ..
Jesper Juhl

2
Anahtar olarak @Neil Pair, değer olarak numaralandırma, özel arama lambda.
πάντα ῥεῖ

56
Kod, tüm bu >testler olmadan çok daha az çirkin olurdu ; bunlara gerek yoktur, çünkü her biri önceki ifaçıklamada (ters yönde) zaten test edilmiştir .
Pete Becker

10
@PeteBecker Bu, böyle kodlarla ilgili evcil hayvanımdan biri. Çok fazla programcı anlamıyor else if.
Barmar

Yanıtlar:


176
#include <iostream>

enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT };

Direction GetDirectionForAngle(int angle)
{
    const Direction slices[] = { RIGHT, UP_RIGHT, UP, UP, UP_LEFT, LEFT, LEFT, DOWN_LEFT, DOWN, DOWN, DOWN_RIGHT, RIGHT };
    return slices[(((angle % 360) + 360) % 360) / 30];
}

int main()
{
    // This is just a test case that covers all the possible directions
    for (int i = 15; i < 360; i += 30)
        std::cout << GetDirectionForAngle(i) << ' ';

    return 0;
}

Ben böyle yapardım. (Önceki yorumuma göre).


92
Kelimenin tam anlamıyla Konami Kodunu orada enum yerine bir saniyeliğine gördüğümü düşündüm.
Zano

21
@CodesInChaos: C99 ve C ++, C # ile aynı gereksinime sahiptir: eğer q = a/bve r = a%bsonra q * b + reşit olmalıdır a. Bu nedenle, bir kalanın negatif olması C99'da yasaldır. BorgLeader, ile sorunu çözebilirsiniz (((angle % 360) + 360) % 360) / 30.
Eric Lippert

7
@ericlippert, siz ve hesaplamalı matematik bilginiz etkilemeye devam edin.
gregsdennis

33
Bu çok zekice, ama tamamen okunamaz ve daha fazla sürdürülemez, bu yüzden orijinalin "çirkinliğine" algılanan iyi bir çözüm olduğuna katılmıyorum. Burada kişisel bir zevk unsuru var sanırım, ancak x4u ve motoDrizzt'in temizlenmiş dallanma versiyonlarını büyük ölçüde tercih edilir buluyorum.
IMSoP

4
@cyanbeam temelde for döngüsü sadece bir "demo", GetDirectionForAngleif / else
kademesinin

71

map::lower_boundHer açının üst sınırını bir haritada kullanabilir ve saklayabilirsiniz.

Aşağıdaki çalışma örneği:

#include <cassert>
#include <map>

enum Direction
{
    RIGHT,
    UP_RIGHT,
    UP,
    UP_LEFT,
    LEFT,
    DOWN_LEFT,
    DOWN,
    DOWN_RIGHT
};

using AngleDirMap = std::map<int, Direction>;

AngleDirMap map = {
    { 30, RIGHT },
    { 60, UP_RIGHT },
    { 120, UP },
    { 150, UP_LEFT },
    { 210, LEFT },
    { 240, DOWN_LEFT },
    { 300, DOWN },
    { 330, DOWN_RIGHT },
    { 360, RIGHT }
};

Direction direction(int angle)
{
    assert(angle >= 0 && angle <= 360);

    auto it = map.lower_bound(angle);
    return it->second;
}

int main()
{
    Direction d;

    d = direction(45);
    assert(d == UP_RIGHT);

    d = direction(30);
    assert(d == RIGHT);

    d = direction(360);
    assert(d == RIGHT);

    return 0;
}

Bölme gerekmez. İyi!
O. Jones

17
@ O. Jones: Derleme zamanı sabiti ile bölme oldukça ucuz, sadece çarpma ve biraz kayma. table[angle%360/30]Cevaplardan biriyle giderdim çünkü ucuz ve dalsız. Uzak bir ağaç arama döngü daha ucuz, kaynağına benzer asm bu derlerken eğer. ( std::unordered_mapgenellikle bir karma tablodur, ancak std::maptipik olarak kırmızı-siyah bir ikili ağaçtır. Kabul edilen yanıt angle%360 / 30, açılar için mükemmel bir karma işlevi olarak etkili bir şekilde kullanır (bir çift girişi kopyaladıktan sonra ve Bijay'ın cevabı, bir ofset ile bunu bile önler)).
Peter Cordes

2
lower_boundSıralanmış bir dizi kullanabilirsiniz . Bu, a'dan çok daha verimli olacaktır map.
wilx

@PeterCordes harita aramasının yazılması ve bakımı kolaydır. Aralıklar değişirse, karma kodu güncellemek hatalara neden olabilir ve aralıklar tek tip değilse, basitçe parçalanabilir. Bu kod, performans açısından kritik olmadığı sürece, rahatsız etmem.
OhJeez

@OhJeez: Zaten tek tip değiller, bu da birden çok grupta aynı değere sahip olarak ele alınır. Daha fazla kova elde etmek için daha küçük bir bölen kullanın, bu çok küçük bir bölen kullanmak ve çok fazla kova olması anlamına gelmedikçe. Ayrıca, performans önemli değilse, eğer bir if / else zinciri de, this->_car.getAbsoluteAngle()bir tmp var ile çarpanlarına atılarak ve OP'nin her bir cümlesinden fazlalık karşılaştırmayı kaldırarak basitleştirilirse kötü değildir if()(zaten eşleşmiş olan bir şeyi kontrol etmek önceki if ()). Veya @ wilx'in sıralı dizi önerisini kullanın.
Peter Cordes

58

Her öğesi 30 derecelik bir blokla ilişkilendirilmiş bir dizi oluşturun:

Car::EDirection dirlist[] = { 
    Car::EDirection::RIGHT, 
    Car::EDirection::UP_RIGHT, 
    Car::EDirection::UP, 
    Car::EDirection::UP, 
    Car::EDirection::UP_LEFT, 
    Car::EDirection::LEFT, 
    Car::EDirection::LEFT, 
    Car::EDirection::DOWN_LEFT,
    Car::EDirection::DOWN, 
    Car::EDirection::DOWN, 
    Car::EDirection::DOWN_RIGHT, 
    Car::EDirection::RIGHT
};

Ardından diziyi / 30 açısıyla indeksleyebilirsiniz:

this->_car.edir = dirlist[(this->_car.getAbsoluteAngle() % 360) / 30];

Karşılaştırma veya dallanma gerekmez.

Ancak sonuç orijinalden biraz farklıdır. Sınırlardaki değerler, yani 30, 60, 120 vb. Bir sonraki kategoriye yerleştirilir. Örneğin, orijinal kodda için geçerli değerler UP_RIGHT31 ila 60'tır. Yukarıdaki kod, 30 ila 59'u atar UP_RIGHT.

Açıdan 1 çıkararak bunu aşabiliriz:

this->_car.edir = dirlist[((this->_car.getAbsoluteAngle() - 1) % 360) / 30];

Bu şimdi bize RIGHT30, UP_RIGHT60, vb. Verir .

0 durumunda ifade olur (-1 % 360) / 30. Bu geçerli çünkü -1 % 360 == -1ve -1 / 30 == 0dolayısıyla hala 0 indeksi elde ediyoruz.

Bölüm 5.6 C ++ standart onaylar bu davranışı:

4 İkili /operatör bölümü verir ve ikili %operatör, birinci ifadenin ikinciye bölünmesinden kalanı verir. İkinci işlenen /veya %sıfır ise, davranış tanımsızdır. İntegral işlenenler için /operatör, herhangi bir kesirli kısım atılmış olarak cebirsel bölümü verir. bölüm a/bsonuç türünde gösterilebilirse (a/b)*b + a%b, eşittir a.

DÜZENLE:

Bunun gibi bir yapının okunabilirliği ve sürdürülebilirliği ile ilgili birçok soru ortaya atıldı. MotoDrizzt tarafından verilen cevap, daha sürdürülebilir ve pek de "çirkin" olmayan orijinal yapıyı basitleştirmenin güzel bir örneğidir.

Cevabını genişleterek, işte üçlü operatörün kullanıldığı başka bir örnek. Orijinal gönderideki her durum aynı değişkene atandığından, bu operatörün kullanılması okunabilirliği daha da artırmaya yardımcı olabilir.

int angle = ((this->_car.getAbsoluteAngle() % 360) + 360) % 360;

this->_car.edir = (angle <= 30)  ?  Car::EDirection::RIGHT :
                  (angle <= 60)  ?  Car::EDirection::UP_RIGHT :
                  (angle <= 120) ?  Car::EDirection::UP :
                  (angle <= 150) ?  Car::EDirection::UP_LEFT :
                  (angle <= 210) ?  Car::EDirection::LEFT : 
                  (angle <= 240) ?  Car::EDirection::DOWN_LEFT :
                  (angle <= 300) ?  Car::EDirection::DOWN:  
                  (angle <= 330) ?  Car::EDirection::DOWN_RIGHT :
                                    Car::EDirection::RIGHT;

49

Bu kod çirkin değil, basit, pratik, okunaklı ve anlaşılması kolay. Kendi yönteminde izole edilecek, bu nedenle günlük hayatta kimse onunla uğraşmak zorunda kalmayacak. Ve birisinin bunu kontrol etmesi gerektiğinde -belki de başka bir yerde bir sorun için uygulamanızda hata ayıkladığı için- o kadar kolay ki, kodu ve ne yaptığını anlaması iki saniye sürecektir.

Böyle bir hata ayıklama yapıyor olsaydım, işlevinizin ne yaptığını anlamaya çalışmak için beş dakika harcamak zorunda kalmazdım. Bu bağlamda, diğer tüm işlevler, hata ayıklama sırasında insanların derinlemesine analiz etmek ve test etmek zorunda kalacağı karmaşık bir karmaşa içinde basit, unutup hatasız bir rutini değiştirdiklerinden tamamen başarısız olurlar. Bir proje yöneticisi olarak, geliştiricinin basit bir görevi üstlenmesi beni çok üzüyor ve bunu basit, zararsız bir şekilde uygulamak yerine, onu aşırı karmaşık bir şekilde uygulamak için zaman harcıyor. Sadece onu düşünerek boşa harcadığınızı bir düşünün, sonra SO'ya gelip sormak ve bunların hepsi sadece bir şeyin bakımını ve okunabilirliğini kötüleştirmek uğruna.

Bununla birlikte, kodunuzda onu daha az okunabilir kılan yaygın bir hata vardır ve oldukça kolay bir şekilde yapabileceğiniz birkaç iyileştirme vardır:

int angle = this->_car.getAbsoluteAngle();

if (angle <= 30 || angle >= 330)
  return Car::EDirection::RIGHT;
else if (angle <= 60)
  return Car::EDirection::UP_RIGHT;
else if (angle <= 120)
  return Car::EDirection::UP;
else if (angle <= 150)
  return Car::EDirection::UP_LEFT;
else if (angle <= 210)
  return Car::EDirection::LEFT;
else if (angle <= 240)
  return Car::EDirection::DOWN_LEFT;
else if (angle <= 300)
  return Car::EDirection::DOWN;
else if (angle <= 330)
  return Car::EDirection::DOWN_RIGHT;

Bunu bir yönteme koyun, döndürülen değeri nesneye atayın, yöntemi daraltın ve sonsuza kadar unutun.

Not: 330 eşiğinin üzerinde başka bir hata var, ancak nasıl tedavi etmek istediğinizi bilmiyorum, bu yüzden hiç düzeltmedim.


Daha sonra güncelleme

Yoruma göre, eğer varsa, diğerlerinden bile kurtulabilirsiniz:

int angle = this->_car.getAbsoluteAngle();

if (angle <= 30 || angle >= 330)
  return Car::EDirection::RIGHT;

if (angle <= 60)
  return Car::EDirection::UP_RIGHT;

if (angle <= 120)
  return Car::EDirection::UP;

if (angle <= 150)
  return Car::EDirection::UP_LEFT;

if (angle <= 210)
  return Car::EDirection::LEFT;

if (angle <= 240)
  return Car::EDirection::DOWN_LEFT;

if (angle <= 300)
  return Car::EDirection::DOWN;

if (angle <= 330)
  return Car::EDirection::DOWN_RIGHT;

Bunu yapmadım çünkü belirli bir noktanın sadece kendi tercihlerime ait olduğunu hissediyorum ve cevabımın kapsamı, "kodun çirkinliği" hakkındaki endişenize farklı bir bakış açısı kazandırmaktı (ve öyle). Her neyse, dediğim gibi, birisi yorumlarda buna işaret etti ve bunu göstermenin mantıklı olduğunu düşünüyorum.


1
Bunun neyi başarması gerekiyordu?
Soyutlama her şeydir.

8
Bu yolu gitmek isterseniz, en azından gereksiz kurtulmak gerektiğini else if, ifyeterlidir.
04'te

10
@ Ðаn hakkında tamamen katılmıyorum else if. Bir kod bloğuna bakmayı ve bunun bir grup ilgisiz ifadeden ziyade bir karar ağacı olduğunu görmeyi faydalı buluyorum. Evet, elseya breakda a'dan sonra derleyici için gerekli değil return, ancak koda göz atan insan için kullanışlıdır.
IMSoP

@ Ðаn Orada fazladan yuvalanmanın gerekli olacağı bir dil görmedim. Ya ayrı bir elseif/ elsifanahtar kelime var ya da teknik olarak ifburada olduğu gibi başlayan tek ifadeli bir blok kullanıyorsunuz . Ne düşündüğünüzü ve düşündüğümün kısa bir
örneği

7
@ Ðаn Evet, bunun korkunç olacağını kabul ediyorum. Ama bunu elseyapman değil, else iffarklı bir ifade olarak kabul etmeyen zayıf bir stil rehberi . Her zaman parantez kullanırdım, ancak özümde gösterdiğim gibi asla böyle bir kod yazmam.
IMSoP

39

Sözde kodda:

angle = (angle + 30) %360; // Offset by 30. 

Demek ki var 0-60, 60-90, 90-150, ... kategoriler olarak. 90 derecelik her bir kadranda bir kısım 60, bir kısım 30'dur. Yani şimdi:

i = angle / 90; // Figure out the quadrant. Could be 0, 1, 2, 3 

j = (angle - 90 * i) >= 60? 1: 0; // In the quardrant is it perfect (eg: RIGHT) or imperfect (eg: UP_RIGHT)?

index = i * 2 + j;

Dizini, numaralandırmaları uygun sırada içeren bir dizide kullanın.


7
Bu iyi, muhtemelen buradaki en iyi cevap. Muhtemelen soru soran kişi daha sonra numaralandırmayı kullandığına bakarsa, daha sonra tekrar sayıya dönüştürüldüğü bir vakası olduğunu görecektir! Numaralamayı tamamen ortadan kaldırmak ve sadece bir yön tamsayısına bağlı kalmak muhtemelen kodundaki diğer yerler için mantıklıdır ve bu yanıt sizi doğrudan oraya götürür.
Bill K

18
switch (this->_car.getAbsoluteAngle() / 30) // integer division
{
    case 0:
    case 11: this->_car.edir = Car::EDirection::RIGHT; break;
    case 1: this->_car.edir = Car::EDirection::UP_RIGHT; break;
    ...
    case 10: this->_car.edir = Car::EDirection::DOWN_RIGHT; break;
}

açı = this -> _ car.getAbsoluteAngle (); sektör = (açı% 360) / 30; Sonuç 12 sektördür. Sonra diziye indeksleyin veya yukarıdaki gibi switch / case kullanın - hangi derleyici yine de atlama tablosuna dönüşür.
ChuckCottrill

1
If / else zincirlerinden gerçekten daha iyi geçiş yapmayın.
Bill K

5
@BillK: Derleyici onu sizin için bir tablo aramasına dönüştürürse olabilir. Bu, bir if / else zincirinden daha olasıdır. Ancak kolay olduğundan ve mimariye özgü herhangi bir numara gerektirmediğinden, tablo aramasını kaynak kodda yazmak muhtemelen en iyisidir.
Peter Cordes

Genel olarak performans bir sorun olmamalı - okunabilirlik ve sürdürülebilirliktir - her anahtar ve if / else zinciri genellikle yeni bir öğe eklediğinizde birden çok yerde güncellenmesi gereken bir grup dağınık kopyalama ve yapıştırma kodu anlamına gelir. Her ikisinden de kaçınmak ve tabloları, hesaplamaları göndermeyi denemek veya sadece bir dosyadan veri yüklemek ve mümkünse veri olarak değerlendirmek en iyisidir.
Bill K

Derleyici PeterCordes, anahtar için olduğu gibi LUT için de aynı kodu üretecektir. @BillK, anahtarı bir 0..12 -> Car :: EDirection işlevine çıkartabilirsiniz, bu da LUT
Caleth

16

ifBiraz özel bir durum olan ilk durumunuzu göz ardı ederek , geri kalanların hepsi aynı düzeni izler: bir min, maks ve yön; sözde kodu:

if (angle > min && angle <= max)
  _car.edir = direction;

Bu gerçek C ++ 'ı yapmak şöyle görünebilir:

enum class EDirection {  NONE,
   RIGHT, UP_RIGHT, UP, UP_LEFT, LEFT, DOWN_LEFT, DOWN, DOWN_RIGHT };

struct AngleRange
{
    int min, max;
    EDirection direction;
};

Şimdi, bir grup ifs yazmak yerine , çeşitli olasılıklarınızın üzerinde bir döngü yapın:

EDirection direction_from_angle(int angle, const std::vector<AngleRange>& angleRanges)
{
    for (auto&& angleRange : angleRanges)
    {
        if ((angle > angleRange.min) && (angle <= angleRange.max))
            return angleRange.direction;
    }

    return EDirection::NONE;
}

( throwZiyade bir istisna ing returning NONEbaşka bir seçenektir).

Daha sonra ararsınız:

_car.edir = direction_from_angle(_car.getAbsoluteAngle(), {
    {30, 60, EDirection::UP_RIGHT},
    {60, 120, EDirection::UP},
    // ... etc.
});

Bu teknik, veriye dayalı programlama olarak bilinir . Bir grup ifs'den kurtulmanın yanı sıra , diğer kodu yeniden çalıştırmadan kolayca daha fazla yön eklemenize (örneğin, NNW) veya sayıyı (sol, sağ, yukarı, aşağı) azaltmanıza olanak tanır.


(İlk özel durumunuzu ele almak "okuyucu için bir egzersiz" olarak bırakılmıştır. :-))


1
Teknik olarak, tüm açı aralıklarının eşleştiği göz önüne alındığında minimum değeri ortadan kaldırabilirsiniz, bu da . if(angle <= angleRange.max)Gibi C ++ 11 özelliklerini kullanmak için durumu + 1'e düşürür enum class.
Pharap

12

Bir arama tablosuna dayalı olarak önerilen varyantlar angle / 30muhtemelen tercih edilebilir olsa da, burada, karşılaştırmaların sayısını en aza indirmek için sabit kodlu ikili arama kullanan bir alternatif vardır.

static Car::EDirection directionFromAngle( int angle )
{
    if( angle <= 210 )
    {
        if( angle > 120 )
            return angle > 150 ? Car::EDirection::LEFT
                               : Car::EDirection::UP_LEFT;
        if( angle > 30 )
            return angle > 60 ? Car::EDirection::UP
                              : Car::EDirection::UP_RIGHT;
    }
    else // > 210
    {
        if( angle <= 300 )
            return angle > 240 ? Car::EDirection::DOWN
                               : Car::EDirection::DOWN_LEFT;
        if( angle <= 330 )
            return Car::EDirection::DOWN_RIGHT;
    }
    return Car::EDirection::RIGHT; // <= 30 || > 330
}

2

Yinelemeden gerçekten kaçınmak istiyorsanız, bunu matematiksel bir formül olarak ifade edebilirsiniz.

Her şeyden önce, @ Geek's Enum kullandığımızı varsayalım.

Enum EDirection { RIGHT =0, UP_RIGHT, UP, UP_LEFT, LEFT, DOWN_LEFT,DOWN, DOWN_RIGHT}

Şimdi tamsayı matematiğini kullanarak enumu hesaplayabiliriz (dizilere ihtiyaç duymadan).

EDirection angle2dir(int angle) {
    int d = ( ((angle%360)+360)%360-1)/30;
    d-=d/3; //some directions cover a 60 degree arc
    d%=8;
    //printf ("assert(angle2dir(%3d)==%-10s);\n",angle,dir2str[d]);
    return (EDirection) d;
}

@MotoDrizzt'in belirttiği gibi, kısa kod mutlaka okunabilir kod değildir. Bunu matematik olarak ifade etmenin, bazı yönlerin daha geniş bir yayı kapladığını açıkça ortaya koymasının küçük bir avantajı var. Bu yöne gitmek istiyorsanız, kodu anlamanıza yardımcı olacak bazı iddialar ekleyebilirsiniz.

assert(angle2dir(  0)==RIGHT     ); assert(angle2dir( 30)==RIGHT     );
assert(angle2dir( 31)==UP_RIGHT  ); assert(angle2dir( 60)==UP_RIGHT  );
assert(angle2dir( 61)==UP        ); assert(angle2dir(120)==UP        );
assert(angle2dir(121)==UP_LEFT   ); assert(angle2dir(150)==UP_LEFT   );
assert(angle2dir(151)==LEFT      ); assert(angle2dir(210)==LEFT      );
assert(angle2dir(211)==DOWN_LEFT ); assert(angle2dir(240)==DOWN_LEFT );
assert(angle2dir(241)==DOWN      ); assert(angle2dir(300)==DOWN      );
assert(angle2dir(301)==DOWN_RIGHT); assert(angle2dir(330)==DOWN_RIGHT);
assert(angle2dir(331)==RIGHT     ); assert(angle2dir(360)==RIGHT     );

Yinelemeyi eklediniz, ancak iddialarda çoğaltma o kadar da kötü değil. Tutarsız bir iddianız varsa, yakında öğreneceksiniz. Onaylar, dağıttığınız yürütülebilir dosyayı şişirmemek için yayın sürümünden derlenebilir. Yine de, bu yaklaşım muhtemelen kodu daha az çirkin hale getirmek yerine optimize etmek istiyorsanız en uygunudur.


1

Partiye geç kaldım ama düzgün bir şeyler yapmak için enum bayrakları ve menzil kontrolleri kullanabiliriz.

enum EDirection {
    RIGHT =  0x01,
    LEFT  =  0x02,
    UP    =  0x04,
    DOWN  =  0x08,
    DOWN_RIGHT = DOWN | RIGHT,
    DOWN_LEFT = DOWN | LEFT,
    UP_RIGHT = UP | RIGHT,
    UP_LEFT = UP | LEFT,

    // just so we be clear, these won't have much use though
    IMPOSSIBLE_H = RIGHT | LEFT, 
    IMPOSSIBLE_V = UP | DOWN
};

açının mutlak olduğu varsayılarak kontrol (sözde kod) (0 ile 360 ​​arasında):

int up    = (angle >   30 && angle <  150) * EDirection.UP;
int down  = (angle >  210 && angle <  330) * EDirection.DOWN;
int right = (angle <=  60 || angle >= 330) * EDirection.Right;
int left  = (angle >= 120 && angle <= 240) * EDirection.LEFT;

EDirection direction = (Direction)(up | down | right | left);

switch(direction){
    case RIGHT:
         // do right
         break;
    case UP_RIGHT:
         // be honest
         break;
    case UP:
         // whats up
         break;
    case UP_LEFT:
         // do you even left
         break;
    case LEFT:
         // 5 done 3 to go
         break;
    case DOWN_LEFT:
         // your're driving me to a corner here
         break;
    case DOWN:
         // :(
         break;
    case DOWN_RIGHT:
         // completion
         break;

    // hey, we mustn't let these slide
    case IMPOSSIBLE_H:
    case IMPOSSIBLE_V:
        // treat your impossible case here!
        break;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.