গল্ফ একটি বেগুনি দোভাষী


13

গল্ফ একটি বেগুনি দোভাষী

বেগুনি একটি এসোলাং যা দুটি মূল উদ্দেশ্যে ডিজাইন করা হয়েছে:

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

আপনার লক্ষ্য এই ভাষার জন্য একজন দোভাষী লিখতে হবে।

বেগুনি সম্পর্কিত তথ্য:

বেগুনি প্রোগ্রাম হ'ল অক্ষরগুলির একটি অনুক্রম যা অসীম, ঠিকানাযোগ্য মেমরি অ্যারেতে রাখা হয় যে প্রোগ্রামের প্রথম অক্ষরটি শূন্যের ঠিকানায় স্থাপন করা হয়। অ্যারের বাকি অংশ (উভয় আগে এবং পরে বেগুনি প্রোগ্রামটি সংরক্ষণ করা হয়) শূন্যে আরম্ভ করা হয়।

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

প্রতিটি চক্র, দোভাষী নির্দেশ পয়েন্টার দ্বারা নির্দেশিত মেমরি অবস্থান থেকে শুরু করে তিনটি স্বতন্ত্র অক্ষরের ক্রম পড়বে এবং বেগুনি নির্দেশ হিসাবে এই ক্রমটি কার্যকর করার চেষ্টা করবে। এরপরে, নির্দেশ পয়েন্টারটি সর্বদা 3 দ্বারা বাড়ানো হয়।

কৃত্রিমভাবে, বেগুনি নির্দেশনায় " xyz " এর মতো একটি সারিতে তিনটি অক্ষর (বা এর এনকোডিং) থাকে ।

প্রথম অক্ষর এক্স নিম্নলিখিত যে কোনও একটি হতে পারে:

abABio

এই প্রতীকগুলির নিম্নলিখিত অর্থ রয়েছে:

a - Place the result in register a.
b - Place the result in register b.
A - Place the result in the location in memory referred to by register a.
B - Place the result in the location in memory referred to by register b.
i - Set the instruction pointer to the result.
o - Output the result to stdout.

অন্য দুটি বাইট y এবং z নিম্নলিখিত যে কোনও হতে পারে:

abABio1

এই চিহ্নগুলির প্রত্যেকটির নীচের অর্থ রয়েছে:

a - Return the contents of register a.
b - Return the contents of register b.
A - Return the contents of the memory array at the address stored in register a.
B - Return the contents of the memory array at the address stored in register b.
i - Return the contents of register i (the instruction pointer).
o - Return the value of a single character read from stdin.
1 - Return the literal numeric value 1.

নির্দেশ আনার সময় পর বেগুনি অনুবাদক মূল্যায়ন করবে Y এবং তারপর z- র , ফল বিয়োগ z- র ফল থেকে Y , এবং তারপর কর্ম দ্বারা নির্দেশিত সঞ্চালন এক্স পার্থক্য।

যদি তিনটি অক্ষরের ক্রম (বা এর এনকোডিংগুলি) একটি বৈধ বেগুনী নির্দেশ না হয়, দোভাষী ত্রুটি না করে সঙ্গে সঙ্গেই থামে।

আপনার দোভাষী অবশ্যই:

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

আপনি আপনার ইচ্ছামত যে কোনও ফর্মটি প্রোগ্রামটি দোভাষীকে সরবরাহ করতে পারেন: এটি কোনও ফাইল থেকে পড়ুন, প্রোগ্রামটিকে স্ট্রিং হিসাবে এম্বেড করুন বা স্টিডিন থেকে পড়ুন read

পরীক্ষার কেস:

কার্যক্রম

ooo

ইনপুট দিয়ে চালানো যখন

z!

ফলন করা উচিত

Y

কার্যক্রম

bbboobiii

ইনপুট দিয়ে চালানো যখন

It's a cat program.

(বা অন্য কোনও ইনপুট) ফলন করা উচিত

It's a cat program.

(বা এটি যে কোনও ইনপুট পেয়েছে) এবং তারপরে আবার শুরু করুন এবং আবার একই জিনিসটি করুন


কার্যক্রম

Aoab11bi1bABoAaiba

ইনপুট দিয়ে চালানো যখন

0

ফলন করা উচিত

0

এবং তারপরে থামুন, তবে যখন ইনপুট দিয়ে চালাবেন

1

আউটপুট চালিয়ে যাওয়া উচিত

1

চিরতরে.


কার্যক্রম

b1bbb1oAbabaa1ab1Ab1Bi1b

ফলন করা উচিত

b1bbb1oAbabaa1ab1Ab1Bi1b

কার্যক্রম

aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG

ফলন করা উচিত

Hello, World!

স্কোরিং:

এটি , বাইটের মধ্যে সবচেয়ে সংক্ষিপ্ত উত্স, নিম্নলিখিত বোনাস দ্বারা সম্ভাব্য সংশোধিত হিসাবে, জিতেছে।

বোনাস:

  • -10% যদি আপনার ইন্টারপ্রেটার স্ট্যান্ডিনের বা কমান্ড লাইন আর্গুমেন্ট থেকে ফাইলের নাম পড়ে এবং ফাইলটি থেকে প্রোগ্রামটি লোড করে।

1
মেমরি কোষের আকার কত? বাইটস, অক্ষর (ইউনিকোডগুলি?), (স্বেচ্ছাসেবী) বড় পূর্ণসংখ্যা? দেখে মনে হচ্ছে আপনি "অক্ষর" এবং "বাইট" একই অর্থ ব্যবহার করছেন।
পাওলো ইবারম্যান

@ পাওলোএবারম্যান আমার ধারণা এটি বাস্তবায়ন-নির্দিষ্ট; উদাহরণস্বরূপ আমাকে uint32অক্ষরের জন্য এবং ইনসগুলির জন্য MAXINT ব্যবহার করতে হবে
বিড়াল

2
@ সিসেরিক এটি কি সত্যিই একজন ব্লকার? আপনার বাস্তবায়নে কেবল দুটি টেপ থাকতে পারে, একটি নেতিবাচক এবং একটি ইতিবাচক সূচকগুলির জন্য। (হ্যাঁ, এটি কিছুটা বেশি কোড নেবে, তবে এতটা নয়, আমি মনে করি))
পাওলো ইবারম্যান

1
@ সিসেরিক মূলত, একটি বেগুনি স্ব-দোভাষী এমন একটি প্রোগ্রাম যা স্টিডিনের কাছ থেকে একটি বেগুনি প্রোগ্রাম পড়ে এবং তারপরে যা কিছু প্রোগ্রাম তা করে does প্রথম বেগুনি প্রোগ্রাম (দোভাষী) আপনার যেই দোভাষী দান করেন তাতে চলতে পারে। একটি প্রোগ্রাম যা সম্পূর্ণরূপে ইনপুটটির সাথে সর্বনিম্ন মেমরির ঠিকানাগুলিকে ওভাররাইট করে, তারপরে কোনওভাবে পড়ার কোডে ঝাঁপিয়ে পড়ার যোগ্যতা অর্জনের আগে নিজেকে মুছে ফেলে (যদিও আমি মনে করি এটি আসলে সম্ভব নয়)।
কুইন্টোপিয়া

2
আমি স্ব-ব্যাখ্যা করতে সক্ষম রানটাইম থাকার এত কাছে এসেছি, তবে আমার অনেক দেরি হয়েছিল।
বিড়াল

উত্তর:


7

পাইথ, 148 128 121 বাইট (বা 124 * .9 = 111.6, নীচে দেখুন)

J,00=kjb.z .eXHkCbz#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

পরীক্ষা স্যুট

STDIN এর প্রথম লাইনে দেওয়া কোড, বাকি STDIN এর বেগুনি প্রোগ্রামে ইনপুট। নতুন লাইনের সাথে কোড ব্যবহার করতে, নীচে বিকল্প সংস্করণ ব্যবহার করুন।

যুক্তিযুক্তভাবে গল্ফড স্পষ্টতার জন্য লাইন ব্রেক এবং ইন্ডেন্টেশন সহ এটি এখানে:

J,00
=kjb.z
 .eXHkCbz
#
  =b-Fm
    ?=zx"oabABi1"C@H+Zd
      @
        s[0Jm.x@Hk0JZ1H)
        z
      Ch~tk
    S2
   ?hKx"abAB"=YC@HZ
    ?PK
      XH@JKb
      XJKb
  ?qY\i=Zb
  ?qY\opCb
  vN
  =+Z3

মূলত, একটি #লুপ কার্যকর করে এবং ত্রুটি-বিরতির মাধ্যমে থামিয়ে দেয়।

aএবং bএকটি একক ভেরিয়েবল, একত্রিত হয় JZনির্দেশ নির্দেশক। kবেগুনি প্রোগ্রাম ইনপুট হয়। Hঅভিধান হিসাবে উপস্থাপন টেপ, হয়। bবর্তমান ফলাফল। Yনির্দেশের বর্তমান প্রথম বাইট।

ফাইল থেকে পড়া:

J,00=kjb.z .eXHkCbjb'z#=b-Fm?q\o=zC@H+ZdCh~tk@s[Jm.x@Hk0JZ1H)x"abABi1"zS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

STDIN এর প্রথম লাইন হিসাবে ফাইলের নাম দিন। পরীক্ষা রান:

$ cat purple-final.pyth 
J,00=kjb.z .eXHkCbjb'z#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3
$ cat purple-code.txt 
aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG
$ pyth purple-final.pyth <<< 'purple-code.txt' 
Hello, World!

5

জাভাস্ক্রিপ্ট (ES6), 292 বাইট

eval(`a=b=i=d=0;v=n=>(x=m[i+n])==97?a_98?b_65?m[a]_66?m[b]_105?i_111?p()[c]()_49?1:d=1;for(m=[...(p=prompt)()].map(b=>b[c="charCodeAt"]());!d;i+=3)(y=v(1),d)||(z=v(2),d)?1:(x=m[r=y-z,i])==97?a=r_98?b=r_65?m[a]=r_66?m[b]=r_105?i=r-3_111?alert(String.fromCharCode(r)):d=1`.replace(/_/g,":x=="))

ব্যাখ্যা

জাভাস্ক্রিপ্ট উত্তর সবসময় অদ্ভুত যখন হয় STDINএবং STDOUTপ্রয়োজন হয় ...

প্রথম প্রম্পট হ'ল প্রোগ্রাম স্ট্রিংয়ের ইনপুট। কোনও oনির্দেশ থেকে প্রাপ্ত প্রতিটি প্রম্পট কেবল প্রথম অক্ষরটি পড়বে।

evalএকটি সাধারণ বাক্যাংশ প্রতিস্থাপন করতে ব্যবহৃত হয় যা কয়েকটি বাইট সংরক্ষণ করে। নিরবচ্ছিন্ন এবং evalপ্রোগ্রাম ছাড়াই দেখতে এমন দেখাচ্ছে:

// Initialisation
a=b=i=                            // initialise registers to 0
  d=0;                            // d is set to true when the program should die

// Gets the result of Y or Z
v=n=>                             // n = offset from i
  (x=m[i+n])==97?a:               // x = value of instruction
  x==98?b:
  x==65?m[a]:
  x==66?m[b]:
  x==105?i:
  x==111?p()[c]():
  x==49?1:
  d=1;                            // if it was none of the valid values, die

// Execution loop
for(
  m=                              // m = memory array
    [...(p=prompt)()]             // receive the program
    .map(b=>b[c="charCodeAt"]()); // initialise m to the ASCII values of the program
  !d;                             // finish if an error occured
  i+=3                            // increment i
)
  (y=v(1),d)||                    // get the value of Y and check for errors
  (z=v(2),d)?1:                   // get the value of Z and check for errors

    // Get the result of X
    (x=m[r=y-z,i])==97?a=r:       // r = result of y - z
    x==98?b=r:
    x==65?m[a]=r:
    x==66?m[b]=r:
    x==105?i=r-3:
    x==111?alert(String.fromCharCode(r)):
    d=1

2
দ্বিতীয়টি c="charCodeAt"কি প্রতিস্থাপন করা যাবে c?
ডেনড্রোবিয়াম

নেতিবাচক সূচকের সাথে অ্যারে অ্যাক্সেস কী জাভাস্ক্রিপ্টে কাজ করে?
নিমি

@ ডেনড্রোবিয়াম বাহ, আমি জানি না কীভাবে আমি এই হা হা মিস করেছি! ধন্যবাদ।
user81655

2
@ নিমিমি এটি কাজ করে। অ্যারে নিজেরাই নেতিবাচক সূচকগুলিকে সমর্থন করে না, তবে এই বিষয়টি তারা যে বস্তু হিসাবেও আচরণ করে তার সুবিধা নেয়। array[-1] = 1হিসাবে একই array = { "-1": 1 }। উভয় দিয়ে অ্যাক্সেস করা যেতে পারে array[-1]
ব্যবহারকারী 81655

@ ইউজার ৮১65৫৫: আহা সুন্দর, এটি জানতেন না।
নিমি

3

সিলোন, 827 792 671 বাইট

import ceylon.language{l=variable,I=Integer,x=nothing,p=process,m=map}shared void run(){try{if(exists d=p.arguments[0]){l value t=m{*d*.hash.indexed};l I a=0;l I b=0;l I i=0;I g(I j)=>t[j]else 0;l{I*}c=[];I o{if(c==[]){if(exists e=p.readLine()){c=e*.hash.chain{10};}else{c={-1}.cycled;}}assert(is I r=c.first);c=c.rest;return r;}value f=m{97->{a},98->{b},65->{g(a)},66->{g(b)},105->{i},111->{o},49->{1}};value s=m{97->((I v)=>a=v),98->((I v)=>b=v),65->((I v)=>t=m{a->v,*t}),66->((I v)=>t=m{b->v,*t}),105->((I v)=>i=v),111->((I v)=>p.write("``v.character``"))};I h(I v)=>f[v]?.first else x;while(0<1){(s[g(i)]else x)(h(g(i+1))-h(g(i+2)));i+=3;}}}catch(AssertionError e){}}

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

(স্ট্যান্ডআউটে এটি -১ লেখার চেষ্টা করার সময়, দোভাষীটি একটি ওভারফ্লো ইরির দিয়ে শেষ করবে, তবে ইউনিকোড সীমার বাইরে কোনও পূর্ণসংখ্যার আউটপুট হলে একই হবে will)

দোভাষী অনুবাদকটি প্রোগ্রামটিকে তার প্রথম কমান্ড লাইন আর্গুমেন্ট হিসাবে গ্রহণ করে (আপনার শেলের জন্য এটি সাদা অংশে বা অন্য আকর্ষণীয় স্টাফ রাখলে তা নিশ্চিত করে নিন)।

সিলোন-এ আমরা কেবল সহজেই ইনপুট লাইন-ভিত্তিক পড়তে পারি (আমার ধারণা এটি পরবর্তী সংস্করণগুলির মধ্যে একটিতে পরিবর্তিত হবে), সুতরাং যখন oপড়ার জন্য ব্যবহৃত হয়, আমি একটি সম্পূর্ণ লাইনটি পড়ছি এবং ভবিষ্যতের ব্যবহারের জন্য অংশগুলি বাফার করব। আমার ধারণা, টার্মিনালের সাথে সংযুক্ত হওয়ার সাথে পাইথন বাস্তবায়নে এটি একই রকম কাজ করে।


কোনও কমান্ড (অংশ) কার্যকর করার চেষ্টা করার সময় যা বৈধ অক্ষরগুলির মধ্যে একটি নয়, এটি nothingএকটি AssertionError নিক্ষেপ করবে, যা আমরা পরে মূল লুপের চারপাশে ক্যাচ ব্লকে ধরি।

আমি মনে করি এটি অগ্রাধিকার হিসাবে একটি কাস্টম এক্সসেপশন ধরণের হওয়া উচিত (যেমন আমি যদি বাগ থাকে তবে অন্য স্থানে AssertionErrorও ঘটতে পারে) তবে প্রথম সংস্করণ থেকে বেশিরভাগ উন্নতি করে খাওয়াতে আরও অনেক বেশি জায়গা লাগবে।

গল্ফ করার জন্য ব্যবহৃত কিছু কৌশল:

  • পূর্ববর্তী সংস্করণগুলি একটি সিলেন কোডোলকশন ব্যবহার করেছে H হ্যাশম্যাপ - পরিবর্তে আমরা এখন mapফাংশন দ্বারা নির্মিত হিসাবে একটি অপরিবর্তনীয় মানচিত্র ব্যবহার করি এবং প্রতিবার একটি নতুন তৈরি করি Aবা এক্সB হিসাবে ব্যবহৃত হয় ।
  • আমি যা একবার (তত্সহ চেয়ে বেশি ব্যবহার করা হয় ceylon.language থেকে সব শনাক্তকারী জন্য ওরফে-আমদানির ব্যবহার variableটীকা, যা এখন হয় l)।
  • আমি ক্লাস E(পরিবেশের জন্য) এবং s(পদক্ষেপ) পদ্ধতি থেকে মুক্তি পেয়েছি - সমস্ত কিছুই এখন runফাংশনের অভ্যন্তরে ঘটে ।
  • .integerকোনও চরিত্রের কোডপয়েন্ট পাওয়ার জন্য ব্যবহার .hashনা করে একই ফলাফল দেয়। এভাবে string*.hashএকই হিসাবে string.map(Character.integer)(একটি স্ট্রিং থেকে codepoints একজন iterable দেয়)।
  • যখন কোনও প্রকারের উপনাম-আমদানি করা হয়, is I ...তার চেয়ে কম হয় exists ...
  • xকোনও "``t``"কিছুর (উদাহরণস্বরূপ ) স্ট্রিংয়ে রূপান্তর করার সময় t.string(বা, আমি কোন চরিত্রের জন্য কী ব্যবহার করেছি String{t}) এর চেয়ে ছোট ।
  • কেবল একবার ব্যবহৃত ফাংশনগুলি প্রায়শই ইনলাইন করা যায়।

এখানে ফর্ম্যাট করা (এবং মন্তব্য করা) সংস্করণ রয়েছে:

// Purple – a self-modifying, "one-instruction" language.
//
// Question:  http://codegolf.stackexchange.com/q/65411/2338
// My answer: http://codegolf.stackexchange.com/a/65492/2338

import ceylon.language {
    l=variable,
    I=Integer,
    x=nothing,
    p=process,
    m=map
}

shared void run() {
    try {
        // Reading code from file certainly takes more than 73 characters,
        // this isn't worth the 10% bonus.
        if (exists d = p.arguments[0]) {

            // The memory tape, as a Map<Integer, Integer>.
            // We can't modify the map itself, but we
            // can replace it by a new map when update is needed.
            l value t = m {
                // It is initialized with the code converted to Integers.
                // We use `.hash` instead of `.integer` because it is shorter.
                *d*.hash.indexed };

            // three registers
            l I a = 0;
            l I b = 0;
            l I i = 0;

            // get value from memory
            I g(I j) =>
                    t[j] else 0;

            // cached input which is still to be read
            l {I*} c = [];

            // get value from stdin.
            // we can only comfortably access stdin by line, so we read a whole line
            // and cache the rest for later.
            I o {
                if (c == []) {
                    if (exists e = p.readLine()) {
                        c = e*.hash.chain { 10 }; // convert string into ints, append \n
                    } else {
                        // EOF – return just -1 from now on.
                        c = { -1 }.cycled;
                    }
                }
                assert (is I r = c.first);
                c = c.rest;
                return r;
            }


            // Map of "functions" for fetching values.
            // We wrap the values in iterable constructors for lazy evaluation
            //  – this is shorter than using (() => ...).
            // The keys are the (Unicode/ASCII) code points of the mapped
            // source code characters.
            value f = m {
                // a
                97 -> { a },
                // b
                98 -> { b },
                // A
                65 -> { g(a) },
                // B
                66 -> { g(b) },
                // i
                105 -> { i },
                // o
                111 -> { o },
                // 1
                49 -> { 1 }
            };

            // Map of functions for "storing" results.
            // The values are void functions taking an Integer,
            // the keys are the ASCII/Unicode code points of the corresponding
            // source code characters.
            value s = m {
                // a
                97 -> ((I v) => a = v),
                // b
                98 -> ((I v) => b = v),
                // Modification of the memory works by replacing the map with a new one.
                // This is certainly not runtime-efficient, but shorter than importing
                // ceylon.collections.HashMap.
                // A
                65 -> ((I v) => t = m { a->v, *t }),
                // B
                66 -> ((I v) => t = m { b->v, *t }),
                // i
                105 -> ((I v) => i = v),
                // o – output as a character.
                111 -> ((I v) => p.write("``v.character``"))
            };

            // accessor function for the f map
            I h(I v) =>
                    f[v]?.first else x;

            // the main loop, can only be left by exception
            while (0 < 1) {
                (s[g(i)] else x)(h(g(i + 1)) - h(g(i + 2)));
                i += 3;
            }
        }
    } catch (AssertionError e) {
        // abort silently
    }
}

" থামানো সমান্তরাল দোভাষী" সমস্ত থামানোর প্রোগ্রাম খুঁজে পাওয়ার চেষ্টা করে আমি সেই কোডটির কিছু অংশ পুনরায় ব্যবহার করেছি । (তাদের মধ্যে অনেকগুলি রয়েছে)) (সেখানে আমি বেগুনির একটি নন-আই / ও সংস্করণ ব্যবহার করেছি, কারণ আমি / ও প্রচুর জায়গা নেয় এবং সেই কাজে ব্যবহৃত হয় না))
পাওলো ইবারম্যান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.