8 দিকের শিরোনামকে শ্রেণিবদ্ধকরণ করার সময় যদি চেইন থেকে থাকে তবে কীভাবে এড়ানো যায়?


111

আমার কাছে নিম্নলিখিত কোড রয়েছে:

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;

আমি ifএস চেইন এড়াতে চাই ; এটা সত্যিই কুরুচিপূর্ণ। এটির লেখার উপায় কি অন্য কোনও, সম্ভবত পরিষ্কার?


77
@ ওরেইকিয়া this->_car.getAbsoluteAngle()পুরো ক্যাসকেডের আগে একবার যদি ফ্যাক্ট করে তবে এটি দেখতে অনেক কম কুরুচিপূর্ণ , টাইপ করা কম এবং পড়ার চেয়ে আরও ভাল লাগবে ।
13

26
this( this->) এর সুস্পষ্ট dereferences বোঝার দরকার নেই এবং পাঠযোগ্যতার জন্য সত্যই কিছু করতে পারে না ..
জেস্পার জুহল

2
@ নীল জুটি কী হিসাবে, মান হিসাবে এনাম, কাস্টম লুকিং ল্যাম্বদা।
18

56
এই সমস্ত >পরীক্ষা ছাড়াই কোডটি অনেক কম কুশল হবে ; তাদের প্রয়োজন নেই, যেহেতু পূর্ববর্তী ifবিবৃতিতে তাদের প্রত্যেকে ইতিমধ্যে পরীক্ষা করা হয়েছে (বিপরীত দিকে) ।
পিট বেকার

10
@ পেটবেকার এটি কোড সম্পর্কে আমার পোষা প্রাণীর মধ্যে অন্যতম e অনেক বেশি প্রোগ্রামার বুঝতে পারে না else if
বার্মার

উত্তর:


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

এইভাবে আমি এটি করব। (আমার আগের মতামত অনুসারে)


92
আমি আক্ষরিকভাবে ভেবেছিলাম আমি কোনামি কোডটি দ্বিতীয় এনামের জায়গায় এনামের জায়গায় দেখেছি।
জ্যানো 21

21
@ কোডসইনচওস: সি 99 এবং সি ++ এর সি সি এর সমান প্রয়োজনীয়তা রয়েছে: যে যদি q = a/bএবং r = a%bতারপরে q * b + rঅবশ্যই সমান হয় a। সুতরাং এটি বাকী negativeণাত্মক হওয়ার জন্য C99 এ বৈধ। BorgLeader, আপনি সমস্যার সমাধান করতে পারেন (((angle % 360) + 360) % 360) / 30
এরিক লিপার্ট

7
@ এরিক্লিপার্ট, আপনি এবং আপনার গণনার গণিতের জ্ঞান ইমপ্রেস করে চলেছেন।
গ্রেগসডেনিস

33
এটি অত্যন্ত চতুর, তবে এটি সম্পূর্ণ অপঠনযোগ্য, এবং রক্ষণাবেক্ষণের আর সম্ভাবনা নেই, তাই আমি অসম্মতি প্রকাশ করি যে এটি মূলটির অনুভূত "কদর্যতা" এর একটি ভাল সমাধান। এখানে ব্যক্তিগত স্বাদের একটি উপাদান রয়েছে, আমি অনুমান করি, তবে আমি এক্স 4 ইউ এবং মোটোড্রিজ্টের দ্বারা পরিষ্কার করা শাখা প্রশাখাগুলিকে আরও ভাল find
আইএমএসওপি

4
@ স্যানবিয়াম মূলত লুপটি কেবল একটি "ডেমো", GetDirectionForAngleআমি যদি / অন্য ক্যাসকেডের প্রতিস্থাপন হিসাবে প্রস্তাব করছি তবে তারা উভয়ই (1) ...
বোরগ্লেডার

71

আপনি map::lower_boundএকটি মানচিত্রে প্রতিটি কোণের উপরের-সীমানা ব্যবহার এবং সঞ্চয় করতে পারেন ।

নীচে কাজের উদাহরণ:

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

কোন বিভাগ প্রয়োজন। ভাল!
ও জোনস

17
@ ও.জোনস: একটি সংকলন-ধ্রুবক দ্বারা বিভাগ মোটামুটি সস্তা, কেবল একটি গুণ এবং কিছু শিফট। আমি একটি table[angle%360/30]উত্তর নিয়ে যাব কারণ এটি সস্তা এবং শাখাবিহীন। গাছের অনুসন্ধানের লুপের তুলনায় অনেক কম সস্তা, যদি এটি উত্সের মতো অনুরূপভাবে সংশ্লেষ করে। ( std::unordered_mapসাধারণত একটি হ্যাশ টেবিল হয় তবে std::mapএটি সাধারণত একটি লাল-কালো বাইনারি গাছ থাকে accepted গ্রহণযোগ্য উত্তর কার্যকরভাবে angle%360 / 30কোণগুলির জন্য একটি সঠিক হ্যাশ ফাংশন হিসাবে ব্যবহার করে (কয়েকটি দম্পতির প্রবেশের প্রতিলিপি দেওয়ার পরে, এবং বিজয়ের উত্তর এমনকি অফসেট সহ এড়ানো যায়))।
পিটার

2
আপনি lower_boundবাছাই করা অ্যারে ব্যবহার করতে পারেন । এটি একটি এর চেয়ে অনেক বেশি দক্ষ হবে map
উইলেক্স

@ পিটারকর্ডস মানচিত্রের লুক্কুট লেখা সহজ এবং বজায় রাখা সহজ। যদি রেঞ্জগুলি পরিবর্তন হয়, হ্যাশিং কোড আপডেট করার ফলে বাগগুলি প্রবর্তিত হতে পারে এবং যদি রেঞ্জগুলি অ-ইউনিফর্ম হয়ে যায়, তবে এটি সহজেই পৃথক হয়ে যেতে পারে। যদি না কোডটি পারফরম্যান্সের সমালোচনা না করে, আমি বিরক্ত করব না।
ওহজিৎ

@ ওহজিঃ তারা ইতিমধ্যে অ-ইউনিফর্ম, যা একাধিক বালতিতে একই মান রেখে পরিচালিত হয়। আরও বালতি পেতে কেবলমাত্র একটি ছোট বিভাজক ব্যবহার করুন, যদি না এর অর্থ খুব ছোট ডিভাইডার ব্যবহার করে এবং অনেকগুলি বালতি না থাকে। এছাড়াও, যদি পারফরম্যান্সে কোনও গুরুত্ব আসে না, তবে একটি / অন্য শৃঙ্খলাও খারাপ না হয়, যদি this->_car.getAbsoluteAngle()একটি টেম্প্প ভার দিয়ে ফ্যাক্টর করে সরল করে দেওয়া হয় এবং ওপি'র প্রতিটি if()ধারা থেকে অপ্রয়োজনীয় তুলনা অপসারণ করা (এমন কিছু যা ইতিমধ্যে মিলেছে তা পরীক্ষা করা) পূর্ববর্তী যদি ())। অথবা @ উইলক্সের সাজানো-অ্যারের পরামর্শ ব্যবহার করুন।
পিটার কর্ডস

58

একটি অ্যারে তৈরি করুন, যার প্রতিটি উপাদান 30 ডিগ্রি ব্লকের সাথে সম্পর্কিত:

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

তারপরে আপনি কোণ / 30 দ্বারা অ্যারেটিকে সূচক করতে পারেন:

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

কোনও তুলনা বা শাখা প্রশাখার প্রয়োজন নেই।

ফলাফল তবে আসল থেকে কিছুটা দূরে। সীমান্তের মানগুলি, অর্থাৎ 30, 60, 120 ইত্যাদি পরবর্তী বিভাগে রাখা হয়েছে। উদাহরণস্বরূপ, মূল কোডটিতে বৈধ মানগুলি UP_RIGHT31 থেকে 60 হয় The উপরের কোডটি 30 থেকে 59 এ নির্ধারিত হয়UP_RIGHT

আমরা কোণ থেকে 1 টি বিয়োগ করে এটি প্রায় পেতে পারি:

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

এটি এখন আমাদের RIGHT30 এর জন্য দেয় ,UP_RIGHT 60 এর

0 এর ক্ষেত্রে ভাবটি হয়ে যায় (-1 % 360) / 30। এটি বৈধ কারণ -1 % 360 == -1এবং-1 / 30 == 0 তাই আমরা এখনও 0 এর সূচক পাই।

সি ++ স্ট্যান্ডার্ডের 5.6 ধারাটি এই আচরণের সত্যতা নিশ্চিত করে:

4 বাইনারি /অপারেটরটি ভাগফলটি দেয় এবং বাইনারি %অপারেটর দ্বিতীয় দ্বারা প্রথম প্রকাশের বিভাগ থেকে বাকী অংশটি দেয়। যদি দ্বিতীয় অপারেন্ড /বা %শূন্য হয় তবে আচরণটি সংজ্ঞায়িত হয়। ইন্টিগ্রাল অপারেন্ডগুলির জন্য /অপারেটর বাতিল হওয়া কোনও ভগ্নাংশের সাথে বীজগণিতের ভাগফল উপস্থাপন করে। a/bফলাফলের ধরণের ক্ষেত্রে ভাগফল যদি উপস্থাপনযোগ্য হয় তবে (a/b)*b + a%bএটি সমান a

সম্পাদনা করুন:

এই জাতীয় নির্মাণের পাঠযোগ্যতা এবং রক্ষণাবেক্ষণ সম্পর্কে অনেক প্রশ্ন উত্থাপিত হয়েছিল। মোটোড্রিজ্টের দেওয়া উত্তরটি মূল কন্সট্রাক্টকে সহজতর করার একটি ভাল উদাহরণ যা আরও রক্ষণাবেক্ষণযোগ্য এবং এটি "কুরুচিপূর্ণ" নয়।

তার উত্তরের প্রসারিত করে, এখানে টার্নারি অপারেটরটি ব্যবহারের আরও একটি উদাহরণ। যেহেতু মূল পোস্টের প্রতিটি কেস একই ভেরিয়েবলের জন্য বরাদ্দ করা হচ্ছে, এই অপারেটরটি ব্যবহার করা আরও পঠনযোগ্যতা বাড়াতে সহায়তা করতে পারে।

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

এই কোডটি কুৎসিত নয়, এটি সহজ, ব্যবহারিক, পাঠযোগ্য এবং সহজে বোঝা যায়। এটি নিজস্ব পদ্ধতিতে বিচ্ছিন্ন হবে, তাই দৈনন্দিন জীবনে কাউকেই এটি মোকাবেলা করতে হবে না। এবং কেবলমাত্র যদি কেউ এটি পরীক্ষা করে দেখতে পারে - কারণ তিনি অন্য কোথাও কোনও সমস্যার জন্য আপনার অ্যাপ্লিকেশনটি ডিবাগ করছেন - এটি এত সহজ যে কোড এবং এটি কী করে তা বুঝতে দ্বিতীয় সেকেন্ড সময় লাগবে।

যদি আমি এই ধরনের একটি ডিবাগ করছিলাম তবে আমি আপনার ক্রিয়াকলাপটি কী তা বোঝার চেষ্টা করার জন্য পাঁচ মিনিট ব্যয় না করে খুশি হব। এই ক্ষেত্রে, অন্যান্য সমস্ত ফাংশন সম্পূর্ণরূপে ব্যর্থ হয়, যেহেতু তারা একটি সাধারণ, ভুলে যাওয়া সম্পর্কে পরিবর্তন করে, বাগ ফ্রি রুটিন একটি জটিল জগতে যে ডিবাগিংয়ের সময় লোকেরা গভীরভাবে বিশ্লেষণ ও পরীক্ষা করতে বাধ্য হবে। প্রজেক্ট ম্যানেজার হিসাবে আমি একজন বিকাশকারী একটি সাধারণ কাজ গ্রহণের দ্বারা দৃ strongly়ভাবে বিচলিত হয়ে পড়েছিলাম এবং এটিকে একটি সহজ, ক্ষতিহীন উপায়ে রূপায়ণ করার পরিবর্তে এটিকে অতিরিক্ত জটিল উপায়ে কার্যকর করার জন্য সময় নষ্ট করে যাচ্ছি। আপনি যতক্ষণ ভাবছেন এর জন্য সমস্ত সময় নষ্ট করেছেন, তারপরে এসও জিজ্ঞাসা করুন, এবং কেবলমাত্র জিনিসটির রক্ষণাবেক্ষণ এবং পাঠযোগ্যতার অবনতির জন্য।

এটি বলেছিল, আপনার কোডে একটি সাধারণ ভুল রয়েছে যা এটিকে খুব কম পাঠযোগ্য করে তোলে এবং বেশ কয়েকটি উন্নতি আপনি খুব সহজেই করতে পারেন:

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;

এটিকে একটি পদ্ধতিতে রাখুন, অবজেক্টটির কাছে প্রত্যাবর্তিত মান নির্ধারণ করুন, পদ্ধতিটি ধসে পড়ুন এবং বাকী চিরকালের জন্য এটি ভুলে যান।

পিএস 330 থ্রেশহোল্ডের উপরে আরও একটি ত্রুটি রয়েছে, তবে আপনি কীভাবে এটি চিকিত্সা করতে চান তা আমি জানি না, তাই আমি একেবারেই ঠিক করে নি।


পরে আপডেট

মতামত অনুসারে আপনি অন্য কিছু থেকে মুক্তি পেতে পারেন তবে:

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;

আমি এটি করিনি 'কারণ আমি অনুভব করি যে একটি নির্দিষ্ট পয়েন্টটি এটি কেবল নিজের পছন্দসই বিষয় হয়ে দাঁড়ায়, এবং আমার উত্তরের পরিধি ছিল (এবং এটি) "কোডের কদর্যতা" সম্পর্কে আপনার উদ্বেগকে আলাদা দৃষ্টিভঙ্গি দেওয়া। যাইহোক, আমি যেমন বলেছিলাম, কেউ মন্তব্যগুলিতে এটি নির্দেশ করেছে এবং আমি মনে করি এটি এটি দেখানো বোধগম্য।


1
কী করার দরকার ছিল?
বিমূর্ততা সবকিছু।

8
যদি এই রুট যেতে চান, আপনার অন্ততপক্ষে অপ্রয়োজনীয় পরিত্রাণ পাওয়া উচিত else if, ifযথেষ্ট।
Ðаn

10
@ Ðаn সম্পর্কে আমি সম্পূর্ণ একমত নই else if। আমি কোনও কোড ব্লকে এক নজরে নজর রাখতে সক্ষম হয়েছি এবং এটি দেখতে পাচ্ছি যে এটি কোনও সিদ্ধান্ত সম্পর্কিত গাছ নয়, বরং একদল সম্পর্কিত সম্পর্কযুক্ত বক্তব্য। হ্যাঁ, elseবা ক এর পরে সংকলকটির জন্যbreak প্রয়োজনীয় নয় তবে কোডটিতে ঝলকানো মানুষের জন্য এগুলি দরকারী। return
আইএমএসওপি

@ .N আমি এমন কোনও ভাষা কখনও দেখিনি যেখানে সেখানে বাড়তি কোনও বাসা বাঁধার প্রয়োজন হবে। হয় আলাদা elseif/ elsifকীওয়ার্ড রয়েছে বা আপনি এখানে প্রযুক্তিগতভাবে একটি বিবৃতি ব্লক ব্যবহার করছেন যা শুরু হতে চলেছে if, ঠিক এখানেই। আপনি কী ভাবছেন এবং আমি কী ভাবছি তার দ্রুত উদাহরণ: gist.github.com/IMSoP/90bc1e9e2c56d8314413d7347e76532a
আইএমএসওপি

7
@ Yesn হ্যাঁ, আমি সম্মত হই যে এটি ভয়াবহ হবে। তবে এটি elseআপনাকে তৈরি করা নয় , এটি একটি দরিদ্র শৈলী গাইড যা else ifস্বতন্ত্র বক্তব্য হিসাবে স্বীকৃতি দেয় না । আমি সবসময় ধনুর্বন্ধনী ব্যবহার করতাম, তবে আমি কখনই এর মতো কোড লিখব না, যেমনটি আমি আমার সারাংশ দেখিয়েছি।
আইএমএসওপি

39

সিউডোকোডে:

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

সুতরাং, আমরা আছে 0-60, 60-90, 90-150, ... আরও হিসাবে। 90 ডিগ্রি সহ প্রতিটি কোয়াড্রেন্টে একটি অংশে 60, একটি অংশে 30 থাকে So সুতরাং, এখন:

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;

উপযুক্ত ক্রমে এনামগুলি সমেত একটি অ্যারেতে সূচকটি ব্যবহার করুন।


7
এটি ভাল, সম্ভবত এখানে সেরা উত্তর। সম্ভাবনাগুলি হ'ল যদি আসল প্রশ্নকর্তা এনামের ব্যবহারের দিকে নজর রাখেন পরে তিনি দেখতে পাবেন যে তার একটি মামলা রয়েছে যেখানে এটি কেবল একটি সংখ্যায় রূপান্তরিত হচ্ছে! এনামটিকে সম্পূর্ণরূপে নির্মূল করা এবং কেবল কোনও দিকনির্দেশক পূর্ণসংখ্যার সাথে আঁকানো সম্ভবত তার কোডের অন্যান্য জায়গাগুলির সাথে বোধ করা যায় এবং এই উত্তরটি আপনাকে সরাসরি সেখানে পেয়ে যায়।
বিল কে

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

কোণ = এটি -> _ car.getAbsolveAngle (); সেক্টর = (কোণ% 360) / 30; ফলাফল 12 সেক্টর। তারপরে অ্যারেতে সূচক করুন, বা উপরের মত স্যুইচ / কেস ব্যবহার করুন - যা সংকলক যাইহোক জাম্প টেবিলে রূপান্তরিত করে।
চককট্রিল 21

1
/ অন্য চেইনগুলির চেয়ে সত্যই ভাল নয়।
বিল কে

5
@ বিলক: এটি হতে পারে, যদি সংকলক এটি আপনার জন্য সারণী অনুসন্ধানে রূপান্তরিত করে। এটি যদি একটি আইএফ / অন্য শৃঙ্খলার চেয়ে বেশি থাকে। তবে এটি যেহেতু সহজ এবং কোনও আর্কিটেকচার-নির্দিষ্ট কৌশলগুলির প্রয়োজন নেই, সোর্স কোডে টেবিল-অনুসন্ধানটি লেখার পক্ষে এটি সর্বোত্তম।
পিটার কর্ডস

সাধারণত পারফরম্যান্স উদ্বেগের বিষয় হওয়া উচিত নয় - এটি পড়ার যোগ্যতা এবং রক্ষণাবেক্ষণযোগ্যতা - প্রতিটি স্যুইচ & যদি / অন্য শৃঙ্খলে সাধারণত একগুচ্ছ নোংরা অনুলিপি এবং পেস্ট কোড থাকে যা আপনি যখনই কোনও নতুন আইটেম যুক্ত করেন তখন একাধিক জায়গায় আপডেট করতে হবে। উভয় এড়াতে সেরা সারণি, গণনা বা কোনও ফাইল থেকে ডেটা লোড করার চেষ্টা করুন এবং যদি পারেন তবে এটি ডেটা হিসাবে বিবেচনা করুন।
বিল কে

পিটারকর্ডস সংকলকটি সম্ভবত LUT এর জন্য স্যুইচ হিসাবে অভিন্ন কোড তৈরি করবে। @ বিলক আপনি একটি 0..12 -> গাড়ী :: EDirection ফাংশনে স্যুইচটি এক্সট্র্যাক্ট করতে পারবেন, যার একটি
LUT- এর

16

আপনার প্রথমটিকে অগ্রাহ্য করা ifযা কিছুটা বিশেষ ক্ষেত্রে, বাকিরা সবাই একই প্যাটার্নটি অনুসরণ করে: একটি মিনিট, সর্বোচ্চ এবং দিকনির্দেশ; সুডোকোড:

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

এই আসল সি ++ তৈরি করা হতে পারে:

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

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

এখন একগুচ্ছ রচনা লেখার পরিবর্তে ifআপনার বিভিন্ন সম্ভাবনার উপর চাপ দিন:

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

( throwইনগিংয়ের চেয়ে একটি ব্যতিক্রম returnআইএনNONE অন্য বিকল্প)।

যার পরে আপনি কল করবেন:

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

এই কৌশলটি ডেটা-চালিত প্রোগ্রামিং হিসাবে পরিচিত । একগুচ্ছ থেকে মুক্তি পাওয়ার পাশাপাশি ifএটি আপনাকে আরও কোডগুলি সহজেই যুক্ত করতে (যেমন, এনএনডাব্লু) ব্যবহার করতে বা অন্য কোডটি পুনরায় কাজ না করে সংখ্যা (বাম, ডান, উপরে, নীচে) কমিয়ে আনার অনুমতি দেয়।


(আপনার প্রথম বিশেষ কেস পরিচালনা করা "পাঠকের জন্য অনুশীলন" হিসাবে বাকি রয়েছে) :-))


1
প্রযুক্তিগতভাবে আপনি সর্বনিম্ন কমাতে পারেন যে সমস্ত কোণ ব্যাপ্তি মিলে যায়, যা if(angle <= angleRange.max)সি ++ 11 এর মতো বৈশিষ্ট্যগুলি ব্যবহারের জন্য শর্তটিকে কিন্তু +1 এ হ্রাস করবে enum class
ফারাপ

12

যদিও দেখার জন্য টেবিলের উপর ভিত্তি করে প্রস্তাবিত রূপগুলি angle / 30সম্ভবত পছন্দনীয়, এখানে একটি বিকল্প যা তুলনামূলক সংখ্যাকে হ্রাস করতে একটি হার্ড কোডিং বাইনারি অনুসন্ধান ব্যবহার করে।

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

আপনি যদি সত্যই সদৃশ এড়াতে চান তবে আপনি এটি গাণিতিক সূত্র হিসাবে প্রকাশ করতে পারেন।

সবার আগে, ধরে নিই যে আমরা @ গিক্সের এনাম ব্যবহার করছি

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

এখন আমরা পূর্ণসংখ্যার গণিত (অ্যারেগুলির প্রয়োজন ছাড়াই) ব্যবহার করে এনামটি গণনা করতে পারি।

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

@ মোটোড্রিজেট যেমন উল্লেখ করেছেন, সংক্ষিপ্ত কোডটি প্রয়োজনীয়ভাবে পঠনযোগ্য কোড নয়। এতে অল্প সুবিধা রয়েছে যে এটি গণিত হিসাবে প্রকাশ করা এটিকে সুস্পষ্ট করে তোলে যে কিছু দিক একটি বৃহত্তর চাপকে coverেকে দেয়। আপনি যদি এই দিকে যেতে চান তবে কোড বুঝতে সাহায্যের জন্য আপনি কিছু যুক্তি যুক্ত করতে পারেন।

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

আপনি অনুলিপি যুক্ত করেছেন এমন দৃser় সংযোজন করার পরে, তবে দাবীগুলিতে সদৃশটি তেমন খারাপ নয়। যদি আপনার কোনও অসঙ্গতিপূর্ণ দৃsert়তা থাকে তবে আপনি খুব শীঘ্রই খুঁজে পাবেন। আপনার বিতরণকৃত এক্সিকিউটেবলকে ফুলিয়ে না দেওয়ার জন্য জোরগুলি প্রকাশের সংস্করণ থেকে বের করে সংকলন করা যেতে পারে। তবুও, আপনি যদি কোডটি কম কুরুচিপূর্ণ করার পরিবর্তে কোডটি অনুকূলিত করতে চান তবে এই পদ্ধতিটি সম্ভবত সবচেয়ে বেশি প্রযোজ্য।


1

আমি পার্টিতে লেট, তবে আমরা কিছু পরিষ্কার করার জন্য এনাম ফ্ল্যাগ এবং রেঞ্জ চেক ব্যবহার করতে পারি।

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

চেকিং (সিউডো কোড), অনুমান কোণটি অবাস্তব (0 এবং 360 এর মধ্যে):

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;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.