কন্ডিশনাল লজিক

কন্ডিশনাল লজিক

‘হ্যাঁ’ ও ‘না’ কথা দুটো সবচেয়ে পুরোনো এবং সবচেয়ে ছোট। কিন্তু এই কথা দুটো বলতেই সবচেয়ে বেশি ভাবতে হয়। - পিথাগোরাস

কন্ডিশনাল লজিক বা বাংলায় শর্তসাপেক্ষ যুক্তি বা অন্য কথায় বলা যায় সিদ্ধান্ত গ্রহণ প্রক্রিয়া, যেকোন প্রোগ্রামিং ল্যাঙ্গুয়েজের খুবই গুরুত্বপূর্ণ একটা বিষয়। আসলে, কম্পিউটার বিজ্ঞানে কন্ডিশনাল লজিকই সবকিছুর ভিত্তি। শুধু কম্পিউটারই নয়, সারা দুনিয়াই চলছে কন্ডিশনাল লজিকের উপর। আমরা মাঝে মাঝে বলি, ‘যদি রেজাল্ট ভাল হয়, তাইলে বান্দরবান ঘুরতে যাব’। এখানে একটা বিবেচ্য বিষয় আছে। বান্দরবানে ঘুরতে আমরা তখনই যাব যখন আমাদের রেজাল্ট ভাল হবে।

এবার বাক্যটাকে প্রোগ্রামিংয়ের দৃষ্টিকোন থেকে হিসাব করা যাক। ‘রেজাল্ট ভাল হয়’ এটা হচ্ছে লজিকাল এক্সপ্রেশন বা কন্ডিশন আর ‘বান্দরবান ঘুরতে যাব’ এটা হচ্ছে অ্যাকশন। অ্যাকশনটা কার্যকর হবার জন্য কন্ডিশনটাকে সত্য হতে হবে। আর কন্ডিশনটা সত্য তখনই হবে যখন রেজাল্ট ভাল হবে।

পাইথনে আমরা তিনটা কন্ডিশনাল স্টেটমেন্ট পাব (লুপকে হিসাবের বাহিরে রাখছি আপাতত)। প্রতিটার ভিন্ন ভিন্ন মানে ও কাজ আছে। এক নজরে দেখে নেয়া যাক:

  • if: যদি এটা সত্য হয়, তবে ওটা কর।

  • elif: যদি if এর কন্ডিশন সত্য না হয়ে এটা সত্য হয়, তবে ওটা কর। elif সবসময় if এর পরে আসবে। আর কেবলমাত্র if এর কন্ডিশন সত্য না হলেই elif এর কন্ডিশন এক্সিকিউট হবার সুযোগ পাবে।

  • else: যদি কোনটিই সত্য না হয়, তবে ওটা কর। elseও সবসময় if আর elif এর পরে আসবে (আসলে সবার শেষে)।

এখন আমরা ডিটেইলসে এগুলো নিয়ে আলোচনা করব। তবে তার আগে একটা তথ্য দেয়া দরকার। প্রতিটা কন্ডিশনাল স্টেটমেন্টের শেষে কোলন (:) চিহ্ন দিতে হয়। কন্ডিশনাল স্টেটমেন্ট বলতে if, elifelse যুক্ত স্টেটমেন্ট বোঝাচ্ছি আমরা।

যদি হয় (if)

একটা সমস্যার কথা চিন্তা করা যাক। আমরা a ভ্যারিয়েবলে 5 অ্যাসাইন করব। এখন, যদি a ভ্যারিয়েবলের মান, 10 এর চেয়ে ছোট হয় তাহলে স্ক্রীনে a is less than 10. প্রিন্ট করব। কিভাবে করা যায় কাজটা? হুম, কন্ডিশনাল লজিক ব্যবহার করতে হবে আমাদের।

>>> a = 5
>>> a
5
>>> if a < 10:
... print('a is less than 10.')
  File "<stdin>", line 2
    print('a is less than 10.')
        ^
IndentationError: expected an indented block

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

>>> if a < 10:
...     print('a is less than 10.')
...
a is less than 10.

এবার আমরা আমাদের কাঙ্ক্ষিত আউটপুট পেয়েছি।

যদি হয় … না হলে (if … else)

উপরের প্রোগ্রামটায় কিন্তু একটা ঘাপলা আছে। যদি a, 10 এর চেয়ে ছোট না হয়, তবে কিন্তু কোন আউটপুটই দেখাবে না। কি বিশ্বাস হচ্ছে না? কোড চালিয়ে দেখলেই তো হয়।

>>> a = 15
>>> if a < 10:
...     print('a is less than 10.')
...

সত্যি, তাই না? আমরা কোন আউটপুট পাইনি। এর কারণ হল আমরা শুধু কন্ডিশন সত্য হবার ক্ষত্রে অ্যাকশন বলে দিয়েছি। কিন্তু কোন কারণে কন্ডিশন মিথ্যা হলে কি অ্যাকশন হবে তা কিন্তু বলে দেইনি। যদি বলে দিতাম তাহলে অবশ্যই সেই অ্যাকশনটা কাজ করত।

এবার নতুন একটা সমস্যার কথা চিন্তা করা যাক। আমরা a ভ্যারিয়েবলে 5 অ্যাসাইন করব। এখন, যদি a ভ্যারিয়েবলের মান, 10 এর চেয়ে ছোট হয় তাহলে স্ক্রীনে a is less than 10. প্রিন্ট করব। আর a যদি 10 এর চেয়ে বড় হয় তাহলে a is greater than 10. প্রিন্ট করব। কিভাবে করা যায় কাজটা? সবাই মিলে চেষ্টা করতে হবে তো!

>>> a = 5
>>> if a < 10:
...     print('a is less than 10.')
... else:
...     print('a is greater than 10.')
...
a is less than 10.
>>> a = 15
>>> if a < 10:
...     print('a is less than 10.')
... else:
...     print('a is greater than 10.')
...
a is greater than 10.

এখানে, আর a যদি 10 এর চেয়ে বড় হওয়ায় প্রিন্ট করেছে a is greater than 10.

যদি হয় … না হলে যদি হয় … না হলে (if … elif … else)

একটা জটিল সমস্যার কথা চিন্তা করা যাক। আমরা a ভ্যারিয়েবলের মান ইউজারের থেকে ইনপুট নেব। এখন, যদি a ভ্যারিয়েবলের মান 5 হয় তাহলে স্ক্রীনে a is equal to 5. প্রিন্ট করব। a এর মান যদি 5 এর চেয়ে ছোট হয় তাহলে a is less than 5. প্রিন্ট করব। আর a যদি 10 এর চেয়ে বড় হয় তাহলে a is greater than 10. প্রিন্ট করব। আগের সমস্যাগুলোর তুলনায় কিন্তু জটিল এটা। তবে আমরা পারবই।

বইয়ের শুরুতেই বলেছিলাম যে প্রথম দিকের চ্যাপ্টারগুলোতে আমরা পাইথন ইন্টারেক্টিভ শেলে কোড লিখব আর তারপরের চ্যাপ্টারগুলো থেকে পাইথন IDLE এ কোড লিখব। তো এখন সেই সময় উপস্থিত। এখন থেকে আমরা পাইথন IDLE এ কোড লেখা শুরু করব।

a = int(input())
if a == 5:
    print('a is equal to 5.')
elif a < 5:
    print('a is less than 5.')
elif a > 5 and a < 10:
    print('a is inbetween 5 and 10.')
else:
    print('a is greater than 10.')

আউটপুট

5
a is equal to 5.
2
a is less than 5.
17
a is greater than 10.

লজিক যখন পাখির বাসা (nested if)

পাখির বাসা তো আমরা কমবেশি সবাই দেখেছি। পাখি খরকুটো দিয়ে পেঁচিয়ে বাসা বানায়। খড়ের পর খড়, তারপর খড় - এভাবে পাখি তার বাসা তৈরি করে। ঠিক এইভাবে আমরা যদি লজিকের ভেতর লজিক, তার ভেতর লজিক দিয়ে কোডব্লক লিখি তখন সেটা হবে nested if।

আমরা একটা সমস্যার কথা চিন্তা করি। ইউজার a এর একটা ভ্যালু ইনপুট দেবে। যদি ভ্যালুটা 10 এর চেয়ে ছোট হয় তখন আমরা চেক করে দেখব যে ভ্যালুটা 2 দিয়ে নিঃশেষে বিভাজ্য কিনা। বিভাজ্য হলে প্রিন্ট কর less, yes আর না হলে less, no। আবার ভ্যালুটা যদি 10 এর চেয়ে বড় হয় তখন আমরা চেক করে দেখব যে ভ্যালুটা 3 দিয়ে নিঃশেষে বিভাজ্য কিনা। বিভাজ্য হলে প্রিন্ট কর greater, yes আর না হলে greater, no

a = int(input())
if a < 10:
    if (a % 2) == 0:
        print('less, yes')
    else:
        print('less, no')
else:
    if (a % 3) == 0:
        print('greater, yes')
    else:
        print('greater, no')

আউটপুট

6
less, yes
12
greater, yes
5
less, no
17
greater, no

এই ছিল পাইথনের কন্ডিশনাল লজিকের মৌলিক ধারণা। একটা বিষয় খেয়াল রাখতে হবে যে পাইথনে সব নন-জিরো (non-zero) আর নন-নাল (non-null, অর্থাৎ not None) ভ্যালু হচ্ছে সত্য (True)। অন্যদিকে জিরো (zero) আর নাল (null, অর্থাৎ None) ভ্যালু হচ্ছে মিথ্যা (False)। একটা উদাহরণ দিলে ব্যাপারটা আমাদের সবার কাছে পরিষ্কার হয়ে যাবে। পাইথন ইন্টারেক্টিভ শেলে কোড লেখা যাক।

>>> a = 5
>>> if a:
...     print(True)
... else:
...     print(False)
...
True
>>> a = 0
>>> if a:
...     print(True)
... else:
...     print(False)
...
False
>>> a = not None
>>> if a:
...     print(True)
... else:
...     print(False)
...
True
>>> a = None
>>> if a:
...     print(True)
... else:
...     print(False)
...
False

আমাদের অনেকের কাছে is (ইজ) এবং == (ডাবল ইক্যুয়েশন) অপারেটর দুটির কাজ একই মনে হতে পারে। আসলে এরা এক জিনিস না। is অপারেটর চেক করে যে দুটি ভেরিয়েবল একই অবজেক্টকে পয়েন্ট করছে কি না। মূলত এটা আইডেন্টিটি কমপ্যারিজনে ব্যবহৃত হয়। অন্যদিকে, == (ডাবল ইক্যুয়েশন) অপারেটর চেক করে দেখে দুটি ভেরিয়েবল যে ভ্যালু বা অবজেক্টকে পয়েন্ট করছে তারা সমান কি না। স্টাক ওভারফ্লোতে পাওয়া একটি উদাহরণ দেখা যাক।

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
>>> b == a
True
>>> b = a[:]
>>> b is a
False
>>> b == a
True

আরেকটি উদাহরণ দেখা যাক—

>>> 4 is 2**2
True
>>> 4 == 2**2
True
>>> 1000 == 10**3
True
>>> 1000 is 10**3
False

শেষের কেসে কিন্তু আউটপুট উল্টাপাল্টা এল। এর কারণ হলো, পাইথন 256 পর্যন্ত সব ইন্টিজার ক্যাশে (cache) করে রাখে। এ জন্য ছোট ইন্টিজারের ক্ষেত্রে is অপারেটর প্রত্যাশা অনুযায়ী কাজ করে। কিন্তু বড়সড় ইন্টিজারের ক্ষেত্রে আউটপুট উল্টাপাল্টা হয়ে যায়।

if __name__ == "__main__"

if __name__ == "__main__":
    #do something

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

প্রবলেম সলভিং

কন্ডিশনাল লজিক সম্পর্কে আমরা এখন অনেকটাই জানি। এই অর্জিত জ্ঞান প্রয়োগ করে তাহলে কয়েকটা প্রবলেম সলভ করার চেষ্টা করা যাক। একটা প্রবলেম কয়েকভাবে সলভ করা যেতে পারে। এ নিয়ে রাজনীতি করার কিছু নেই!

প্রবলেম-১

ইউজার একটা পূর্ণসংখ্যা ইনপুট দেবে। সংখ্যাটি ৩ ও ৫ দ্বারা নিঃশেষে বিভাজ্য হলে আউটপুট হবে Yes আর না হলে আউটপুট হবে No।

number = int(input("Please input an integer: "))

if number%3 == 0 and number%5 == 0:
    print('Yes')
else:
    print('No')

আউটপুট

Please input an integer: 13
No
Please input an integer: 15
Yes
Please input an integer: 45
Yes
Please input an integer: 12
No

এটা খুবই সহজ একটা সমস্যা। ইউজারের কাছে থেকে একটা পূর্ণসংখ্যা ইনপুট নিয়েছি। তারপর চেক করে দেখেছি, সেটি 3 এবং 5 দ্বারা নিঃশেষে বিভাজ্য কিনা। বিভাজ্য হলে Yes প্রিন্ট করেছি, না হলে No প্রিন্ট করেছি।

প্রবলেম-২

ইউজার একটা সংখ্যা ইনপুট দেবে। সংখ্যাটি ধনাত্মক হলে আউটপুট হবে Positive, ঋণাত্মক হলে আউটপুট হবে Negative আর জিরো হলে আউটপুট Zero হবে।

print('Please, input the number:')
number = float(input())
if number > 0:
    print('Positive')
elif number < 0:
    print('Negative')
else:
    print('Zero')

আউটপুট

0
Zero
2
Positive
-10
Negative

কোনো সংখ্যা শূন্যের চেয়ে ছোট হলে তা ঋণাত্মক সংখ্যা। শূন্যের চেয়ে বড় হলে হয় অঋণাত্মক বা ধনাত্মক সংখ্যা। তাই আমরা চেক করে দেখেছি যে ইউজারের ইনপুট দেওয়া সংখ্যাটা শূন্যের বড় নাকি ছোট। অবশ্য শূন্যের সমান হলে সাফ সাফ জানিয়ে দিয়েছি যে এটা শূন্য বই আর কিছু নয়।

প্রবলেম-৩

ইউজার একটি পূর্ণসংখ্যা ইনপুট দেবে। সংখ্যাটি জোড় হলে আউটপুট হবে Even আর বিজোড় হলে আউটপুট Odd হবে।

print('Please, input the number:')
number = int(input())

if number % 2 == 0:
    print('Even')
else:
    print('Odd')

আউটপুট

0
Even
14
Even
17
Odd

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

প্রবলেম-৪

ইউজার একটি ক্যারেক্টার (আলফাবেট) ইনপুট দেবে। ক্যারেক্টারটা ছোট হাতের অক্ষর হলে আউটপুট হবে Lower Case আর বড় হাতের অক্ষর হলে হবে Upper Case। যদি ক্যারেক্টারটা আলফাবেটের মধ্যে না পড়ে, তবে আউটপুট Nothing হবে।

print('Please, input the character:')
character = input()

if character >= 'a' and character <= 'z' :
    print('Lower Case')
elif character >= 'A' and character <= 'Z' :
    print('Upper Case')
else:
    print('Nothing')

আউটপুট

g
Lower Case
F
Upper Case
6
Nothing

এখানে আমরা ASCII ভ্যালু হিসাব করে সিদ্ধান্ত নিয়েছি। প্রতিটি ক্যারেক্টারের নির্দিষ্ট ASCII ভ্যালু রয়েছে। যেমন : A-এর 65, a-এর 97। a-z-এর ASCII ভ্যালু 97-122 আর A-Z-এর ASCII ভ্যালু 65-90। তাই আমরা এই দুটি রেঞ্জের মধ্যে হিসাব করেছি। ASCII নিয়ে আরও জানতে আমরা এটা দেখতে পারি : http://www.asciitable.com/

প্রবলেম-৫

ইউজার একটি ক্যারেক্টার (আলফাবেট) ইনপুট দেবে। ক্যারেক্টারটা ভাওয়েল (Vowel) হলে আউটপুট হবে Vowel আর কনসোনেন্ট (Consonant) হলে হবে Consonant; যদি ক্যারেক্টারটা আলফাবেটের মধ্যে না পড়ে, তবে আউটপুট হবে Nothing.

print('Please, input the character:')
character = input()

if character >= 'a' and character <= 'z' or character >= 'A' and character <= 'z' :
    if character in 'aeiouAEIOU':
        print('Vowel')
    else:
        print('Consonant')
else:
    print('Nothing')

আউটপুট

a
Vowel
A
Vowel
z
Consonant
t
Consonant
9
Nothing

আমাদের প্রথম দরকার ছিল, ইউজার যে ক্যারেক্টারটা ইনপুট দেবে সেটা আসলে আলফাবেট কি না। তাই আমরা প্রথমেই সেটা চেক করে দেখেছি। যদি ইউজার আলফাবেটই ইনপুট দিয়ে থাকে, তখন চেক করে দেখেছি সেটা ভাওয়েল কি না। এ কাজটা আমরা করেছি একটু অন্যভাবে। ‘aeiouAEIOU’ স্ট্রিংয়ে সবগুলো ভাওয়েল আছে। আমরা শুধু চেক করেছি ইউজার ইনপুটটা এর ভেতর আছে কি না। থাকলে সেটা ভাওয়েল আর না থাকলে কনসোনেন্ট।

প্রবলেম-৬

ইউজার একটা পূর্ণসংখ্যা ইনপুট দেবে, এই ইনপুট হল তার লাঞ্চ বিল। এবার এটাকে আমাদের দেশের হিসেব অনুযায়ী কত টাকার কয়টা নোট দিয়ে বিল দেয়া যাবে সেটা বের করতে হবে।

a = int(input("Please input your a: "))

b = a
temp = a//1000
print(temp, '1000 Taka note(s).')
if temp > 0:
    a = a%1000
    b = a
else:
    a = b
temp = a//500
print(temp, '500 Taka note(s).')
if temp > 0:
    a = a%500
    b = a
else:
    a = b
temp = a//100
print(temp, '100 Taka note(s).')
if temp > 0:
    a = a%100
    b = a
else:
    a = b
temp = a//50
print(temp, '50 Taka note(s).')
if temp > 0:
    a = a%50
    b = a
else:
    a = b
temp = a//20
print(temp, '20 Taka note(s).')
if temp > 0:
    a = a%20
    b = a
else:
    a = b
temp = a//10
print(temp, '10 Taka note(s).')
if temp > 0:
    a = a%10
    b = a
else:
    a = b
temp = a//5
print(temp, '5 Taka note(s).')
if temp > 0:
    a = a%5
    b = a
else:
    a = b
temp = a//2
print(temp, '2 Taka note(s).')
if temp > 0:
    a = a%2
    b = a
else:
    a = b
temp = a//1
print(temp, '1 Taka note(s).')

ইউজারের কাছে থেকে তার লাঞ্চ বিল পূর্ণসংখ্যা হিসেবে a ভ্যারিয়েবলে ইনপুট নিয়েছি। হিসেবে সুবিধার জন্য ইউজার ইনপুটকে b ভ্যারিয়েবলে অ্যাসাইন করেছি। এখন হিসেবের পালা। আমাদের দেশে প্রচলিত নোটগুলোর ভিতরে ১০০০ টাকার নোটই সবচেয়ে বড়। তাই এটা দিয়েই হিসেব-নিকেশ শুরু করেছি আমরা। a-কে 1000 দিয়ে ফ্লোর ডিভিশন করে temp ভ্যারিয়েবলে অ্যাসাইন করেছি। এই temp-এর ভ্যালু হল ১০০০ টাকার কয়টি নোট লাগবে তার সংখ্যা। এখন temp এর ভ্যালু যদি শূন্যের চেয়ে বড় হয় (অর্থাৎ ন্যূনতম একটি ১০০০ টাকার নোট যদি লাগে), তাহলে a-কে 1000 দিয়ে ভাগ করে ভাগশেষ a-তেই অ্যাসাইন করেছি। তারপর a-কে আবার b-তে অ্যাসাইন করেছি। আর temp এর ভ্যালু শূন্যের চেয়ে ছোট হলে b-এর মান a-তে অ্যাসাইন করেছি। এভাবেই বাকি নোটগুলোর হিসেব করেছি আমরা।

অনুশীলনী

(১) ইউজার তার জন্মসাল ইনপুট দেবে। চেক করে দেখতে হবে সেটা লিপ-ইয়ার কিনা।

(২) ইউজার একটা সংখ্যা ইনপুট দেবে। সেটাকে আপনার স্কুল/কলেজ/বিশ্ববিদ্যালয়ের গ্রেডিং সিস্টেম অনুসারে হিসেব-নিকেশ করে A+ বা B- বা F ইত্যাদি আউটপুট দেখাতে হবে।

comments powered by Disqus