Module ১ · প্রথম program: console, let আর const, type, typeof
input পড়া: যে starter প্রতিটা problem-এ থাকে, এক লাইন করে
এই lesson-এ যা শিখবে
- Track-এর বাঁধা starter দিয়ে সংখ্যা আর শব্দ পড়তে পারবে, আর প্রতিটা উত্তর
out-এ push করতে পারবে। - Starter-এর প্রতিটা লাইন কী করে, বলতে পারবে, আর space-ওয়ালা input-এর জন্য lines variant-এ যেতে পারবে।
- মাপা একটা সময় দেখিয়ে বুঝিয়ে বলতে পারবে, উত্তরগুলো কেন শেষে একটা
console.logদিয়ে ছাপা হয়।
Zara ওর প্রথম judge করা problem খোলে: কয়েকটা সংখ্যা পড়ো, ওদের যোগফল ছাপো। যোগ করতে ও জানে। আটকে যায় প্রথম লাইনেই: program সংখ্যাগুলো পায় কোথা থেকে? এই track-এ প্রতিটা problem-ই এই প্রশ্নের একই উত্তর দেয়: উপরে একই ছয়টা লাইন, নিচে একটা, আর এদের একসঙ্গে বলে starter। Zara ওটা paste করে, মাঝে চার লাইন লেখে, আর ওর program শেষ। এই lesson starter-টা খুলে খুলে দেখাবে, যাতে ওটা আর কখনো রহস্য না থাকে।
পুরো starter, একসঙ্গে
এই যে। এই track-এর judge করা প্রতিটা JavaScript problem শুরু হয় হুবহু এই লাইনগুলো দিয়ে, আর comment যেখানে বলে, তোমার code বসে সেখানে।
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
const a = nextInt();
const b = nextInt();
out.push(a + b);
console.log(out.join("\n"));
12
এই output এসেছে input 5 7 দিলে। Playground-এ input যায় editor-এর নিচের stdin box-এ, আর judge প্রতিটা লুকানো test-এর input একইভাবে দেয়। মাঝের তিনটা লাইনই "দুইটা সংখ্যা যোগ করো"-এর পুরো সমাধান।
Starter, লাইন ধরে ধরে
const input = require("fs").readFileSync(0, "utf8"); 1 all of stdin, as one string
const tokens = input.split(/\s+/).filter(Boolean); 2 the string cut into words
let at = 0; 3 which token comes next
const next = () => tokens[at++]; 4 hand over the next token
const nextInt = () => Number(next()); 5 the next token, as a number
const out = []; 6 the answer lines, collected
console.log(out.join("\n")); last print them all at once
- লাইন 1 আর 2 একবারই চলে, আর সবকিছু পড়ে ফেলে। তোমার code কখনো input-এর জন্য বসে থাকে না।
- লাইন 3 থেকে 5 তোমাকে দেয়
next()আরnextInt(): পড়ার জন্য তোমার শুধু এই দুইটা call-ই লাগবে। - লাইন 6 আর শেষ লাইন তোমার উত্তরগুলো জমায়, তারপর একসঙ্গে ছাপে।
- এই লাইনগুলো তুমি বদলাবে না। তোমার code বসে এদের মাঝখানে।
তাই starter পুরো input-কে শব্দের একটা তালিকা বানায়, একটা একটা করে শব্দ তোমার হাতে দেয়, আর তুমি যা জমালে সেটা ছাপে। পরের অংশগুলো একেকটা টুকরো খুলে দেখাবে।
লাইন 1: পুরো input একটা string-এ
require("fs") load করে fs, file নিয়ে কাজের জন্য Node-এর নিজের module; নামটা এসেছে file system থেকে। readFileSync একটা পুরো file এক টানে পড়ে। "Sync" মানে, পড়া শেষ না হওয়া পর্যন্ত program অপেক্ষা করে।
এখানে file হলো 0। প্রতিটা program শুরু হয় তিনটা খোলা stream নিয়ে, নম্বর 0, 1 আর 2: standard input, standard output আর standard error। File 0 পড়া মানে standard input পড়া, মানে Playground-এর stdin box, নয়তো judge-এর test। "utf8" বলে byte-গুলোকে লেখা হিসেবে পড়তে, তাই ফল হয় একটা string, আর বাংলা অক্ষরও ঠিকঠাক পৌঁছায়।
const input = require("fs").readFileSync(0, "utf8");
console.log(input.length);
console.log(input);
11
3
10 20 30
এই output এসেছে input 3 আর 10 20 30 দিলে। String-টায় আছে 11টা character: অঙ্কগুলো, দুইটা space আর দুইটা line break। ছাপলে দুইটা লাইন দেখা যায়, আর শেষের ফাঁকা লাইনটা input-এর নিজের শেষ line break। তাই লাইন 1 তোমাকে দেয় যা টাইপ করা হয়েছে তার সবটা, এক string-এ, line break-সহ।
লাইন 2: input কেটে token বানানো
ওই string থেকে হাতে বেছে বেছে সংখ্যা তুলতে কেউ চায় না। লাইন 2 এটাকে কেটে বানায় tokens: space আর line break-এর মাঝের টুকরোগুলো।
const input = require("fs").readFileSync(0, "utf8");
console.log(input.split(/\s+/));
console.log(input.split(/\s+/).filter(Boolean));
[ '3', '10', '20', '30', '' ]
[ '3', '10', '20', '30' ]
এই output এসেছে input 3 আর 10 20 30 দিলে। split একটা string কাটে সেখানে, যেখানে তার pattern মেলে। /\s+/ হলো "এক বা একাধিক space, tab বা line break" pattern-টা, regular expression হিসেবে লেখা (Module 16)। Square bracket দেখায় value-র একটা তালিকা, মানে একটা array, আর Node তালিকার ভেতরের string-গুলো ছাপে single quote দিয়ে।
প্রথম তালিকাটা শেষ হয় একটা খালি string '' দিয়ে, যেটা এসেছে শেষের line break থেকে। .filter(Boolean) খালি টুকরোগুলো ফেলে দেয়, আর লাইন 2-এ এটা এজন্যই আছে। এটা না থাকলে, শুরুতে একটা space বা বাড়তি একটা ফাঁকা লাইন থাকা input তোমার হাতে একটা খালি token ধরিয়ে দিত। তাই লাইন 2-এর পরে tokens হলো input-এর প্রতিটা শব্দ, ক্রম ধরে, string হিসেবে।
লাইন 3 থেকে 5: next() আর nextInt()
at একটা counter, শুরু হয় 0 থেকে: এরপর যে token হাতে দেওয়া হবে, তার জায়গা। next আর nextInt ছোট দুইটা function, arrow-এর ছোট রূপে লেখা, () => ...। Arrow বুঝিয়ে বলবে Module 5; এখানে তুমি শুধু এদের call করবে।
next()ফেরত দেয়atজায়গার token-টা, তারপরat-এর সঙ্গে 1 যোগ করে। প্রতিটা call পরের শব্দটা হাতে দেয়, একটা string হিসেবে।nextInt()call করেnext()-কে, আরNumberদিয়ে শব্দটাকে একটা number বানায়। নাম যা-ই বলুক,2.5-কেও এটা 2.5 হিসেবেই পড়ে।
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
const name = next();
const age = nextInt();
const height = nextInt();
out.push(name);
out.push(typeof age);
out.push(age + 1);
out.push(height);
console.log(out.join("\n"));
Zara
number
15
1.55
এই output এসেছে input Zara 14 1.55 দিলে। প্রতিটা call পরের token-টা নেয়, বাঁ থেকে ডানে। শব্দের জন্য next(), সংখ্যার জন্য nextInt()। পার্থক্যটা জরুরি: 14-এর উপর next() দেয় string "14", আর দুইটা string পেলে + কী করে, দেখাবে "যে ভুলগুলো সবাই করে"। তাই input পড়ো একবারে একটা token, আর token-টা কী হওয়ার কথা, সেটা দেখে call বেছে নাও।
লাইন 6 আর শেষ লাইন: জমাও, তারপর একবারে ছাপো
out শুরু হয় একটা খালি array হিসেবে। প্রতিটা out.push(x) তালিকার শেষে একটা করে উত্তরের লাইন যোগ করে। একদম শেষে out.join("\n") লাইনগুলো জোড়া লাগায়, প্রতি দুই লাইনের মাঝে একটা line break দিয়ে, আর একটা console.log সবটা ছাপে।
প্রতিটা উত্তরের জন্য আলাদা করে console.log call করলে সমস্যা কী? কাজ করে, কিন্তু লাইন অনেক হলে ধীর। প্রতিটা call standard output-এ আলাদা একটা write। আমরা এটা মেপেছি Playground-এ, sign in না করে, 2026-10-07 তারিখে: প্রতিটা program একবার করে চালিয়ে, যেটা 1 থেকে 100000 পর্যন্ত সংখ্যা ছাপে।
| Program 100000 লাইন কীভাবে ছাপে | Program-এর ভেতরের সময় | পুরো run, Playground যা দেখায় |
|---|---|---|
console.log(i), প্রতি লাইনে একবার | 790 ms | 1024 ms |
out.push(i), তারপর একটা console.log(out.join("\n")) | 65 ms | 153 ms |
Program-এর ভেতরে প্রায় বারো গুণ ধীর, একই output-এর জন্য। Judge প্রতিটা test-এ একটা time limit দেয়, আর শুধু ছাপতেই 800 ms গেলে, তোমার আসল সমাধান test হওয়ার আগেই সময়ের বেশিরভাগ খরচ হয়ে যেতে পারে। তাই প্রতিটা উত্তর যায় out-এ, আর শেষ লাইন সবগুলো একবারে ছাপে।
Input শেষ না হওয়া পর্যন্ত পড়া
কিছু problem বলে দেয় কয়টা value আসবে: "প্রথম লাইনে আছে n"। অন্যগুলো বলে "শব্দ, input শেষ না হওয়া পর্যন্ত"। দুই ক্ষেত্রেই কয়েকটা লাইন বারবার চালাতে হয়, আর সেটাই করে একটা loop। Loop ঠিকঠাক শেখাবে Module 4; এখানে শুধু দুইটা গড়ন দিলাম, যেমন আছে তেমনই ব্যবহার করো।
n দেওয়া থাকলে, একটা for loop দিয়ে n বার চালাও। i গোনে 0, 1, 2, আর n-এ পৌঁছানোর আগেই থামে।
const n = nextInt();
for (let i = 0; i < n; i++) {
const x = nextInt();
// use x here
}
Input যখন এমনি শেষ হয়ে যায়, তখন কাজে লাগাও এই কথাটা: token ফুরিয়ে গেলে next() দেয় undefined। একটা token পড়ো, আর যতক্ষণ সেটা undefined না, চালিয়ে যাও।
let word = next();
while (word !== undefined) {
// use word here
word = next();
}
!== মানে "হুবহু এক না", ===-এর উল্টো। Loop-এর ভেতরের শেষ লাইনটা পরের token পড়ে, তাই প্রতি পাকে নতুন একটা শব্দ আসে। Input ফুরিয়ে গেলে word হয়ে যায় undefined, আর loop থামে। তাই "n-টা value" মানে একটা for loop, যেটা n বার চলে, আর "শেষ পর্যন্ত" মানে একটা while loop, যেটা undefined-এ থামে।
Lines variant: পুরো লাইন ধরে পড়া
Token-এ শব্দের মাঝের space হারিয়ে যায়। Problem-এর input যখন space-ওয়ালা একটা লাইন, যেমন একটা বাক্য, তখন লাইনটা আস্ত লাগে। ওই problem-গুলোতে token-এ ভাগ করার লাইনটার জায়গায় থাকে এমন একটা লাইন, যেটা input কাটে line break-এ, তাই next() হাতে দেয় পুরো একটা লাইন, space-সহ। ওদের statement সেটা বলেও দেয়।
const input = require("fs").readFileSync(0, "utf8");
const lines = input.split("\n");
let at = 0;
const next = () => lines[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
// Lines variant: next() returns the next whole line, empty lines included.
const sentence = next();
out.push(sentence);
out.push(sentence.length);
console.log(out.join("\n"));
the quick brown fox
19
এই output এসেছে input the quick brown fox দিলে। Starter-এর দুইটা লাইন বদলেছে: লাইন 2 input-কে line break-এ কেটে বানায় lines, আর লাইন 4-এর next() সেটার উপর দিয়ে এগোয়, প্রতি call-এ পুরো একটা লাইন। .length লাইনটার character গোনে, space-ও ধরে, lesson 03-এ যেমন দেখেছ। তাই space-ওয়ালা লেখার জন্য পড়ো লাইন, token না।
Kenji-র stall-এ n-টা বিক্রির হিসাব লেখা থাকে। ও মোটটা চায়। এটা for-এর গড়ন, সঙ্গে একটা let, যেটা বাড়তে থাকে, lesson 02-এর চলতি যোগফলের মতো।
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
const n = nextInt();
let total = 0;
for (let i = 0; i < n; i++) {
total = total + nextInt();
}
out.push(total);
console.log(out.join("\n"));
460
এই output এসেছে input 5 আর 120 80 45 200 15 দিলে। Loop ঠিক n বার nextInt() call করে, তাই পাঁচটা বিক্রি পড়ে, তার বেশি কিছু না। Input-এর line break-এ কিছু যায় আসে না: token আসে ক্রম ধরে, যে লাইনেই থাকুক।
Maria শব্দের একটা তালিকা paste করে, সামনে কোনো সংখ্যা নেই। ও জানতে চায় শব্দ কয়টা, আর কোনটা প্রথমে এসেছিল, কোনটা শেষে।
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
const first = next();
let last = first;
let count = 0;
let word = first;
while (word !== undefined) {
count = count + 1;
last = word;
word = next();
}
out.push(count);
out.push(first);
out.push(last);
console.log(out.join("\n"));
4
mango
lychee
এই output এসেছে input mango banana আর guava lychee দিলে। next() ফুরিয়ে গিয়ে undefined দিলেই loop থামে। Zara একটা খালি input চালিয়ে দেখে: first হয় undefined, loop একবারও চলে না, আর program ছাপে 0 আর দুইটা ফাঁকা লাইন। join-এর হাতে undefined পড়লে সেটা খালি string হয়ে যায়। আসল problem বলে দিত, তখন কী ছাপতে হবে।
Amara-র program দুই লাইনে একটা title আর একটা নাম পড়ে, দুইটাতেই space থাকতে পারে, তারপর একটা banner ছাপে। এটা lines variant।
const input = require("fs").readFileSync(0, "utf8");
const lines = input.split("\n");
let at = 0;
const next = () => lines[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
// Lines variant: next() returns the next whole line, empty lines included.
const title = next();
const author = next();
out.push("Title: " + title);
out.push("By: " + author);
out.push("Characters in the title: " + title.length);
console.log(out.join("\n"));
Title: A Garden in Sylhet
By: Amara
Characters in the title: 18
এই output এসেছে input A Garden in Sylhet আর Amara দিলে। একটা string আর আরেকটা value-র মাঝে + দুইটাকে জুড়ে একটা string বানায়; পুরোটা দেখাবে Module 2। Token দিয়ে পড়লে title-টা আসত চারটা আলাদা শব্দ হয়ে।
এটা কোথায় কাজে লাগে
- এই track-এর judge করা প্রতিটা problem. Starter জেনেবুঝেই বাঁধা, যাতে input পড়ার একটাই উপায় তোমাকে চিনতে হয়, আর প্রতিটা problem-এর সমাধান শুরু হয় একই ছয় লাইনের পরে।
- Log file পড়া Node script.
0-এর জায়গায় একটা file-এর নাম বসাও,readFileSync("access.log", "utf8"), আরsplit("\n")প্রতিটা entry-র জন্য একটা করে log লাইন দেয়। ছোটখাটো server report প্রায়ই হুবহু এভাবেই লেখা হয়। - Command line-এর pipe. macOS আর Linux-এ
cat access.log | node count.jsএকটা file-কে program-এর standard input-এ ঢুকিয়ে দেয়। Program সেটা পড়ে সেই একইreadFileSync(0, "utf8")দিয়ে, আর কখনো জানেই না লেখাটা কোথা থেকে এল।
যে ভুলগুলো সবাই করে
১. সংখ্যা চাওয়ার জায়গায় next()।
const a = next();
const b = next();
out.push(a + b);
কোনো message নেই। Input 10 20 দিলে এটা ছাপে 1020, আর judge উত্তর দেয় Wrong Answer। next() দেয় string, আর + দুইটা string-কে পরপর জুড়ে দেয়। প্রতিটা সংখ্যার জন্য nextInt() লেখো। তুমি next()-ই ধরবে, কারণ input দেখতে তো সংখ্যার মতোই।
২. Bracket ছাড়া next।
const word = next;
out.push(word);
কোনো message নেই। Program ছাপে () => tokens[at++], মানে function-টার নিজের লেখা। () না দিলে তুমি পাও function-টা, ওর ফল না। লেখো next()। Bracket তুমি বাদ দেবে, কারণ অন্য সব জায়গায় শুধু নামটা লিখলেই তার value পাওয়া যায়।
৩. একবার বেশি পড়া।
for (let i = 0; i <= n; i++) {
total = total + nextInt();
}
কোনো message নেই। <= থাকলে loop চলে n + 1 বার। শেষ nextInt() কোনো token পায় না, পায় Number(undefined), মানে NaN, আর যোগফল ছাপা হয় NaN। লেখো i < n। তুমি <= লিখে ফেলবে, কারণ "n বার" শুনলে মনে হয় n-এ গিয়ে থামবে, আর এই শিক্ষা Bob প্রতিটা track-এ নতুন করে পায়।
৪. Starter-এর উপরে একটা import লাইন।
import os from "os";
const input = require("fs").readFileSync(0, "utf8");
Playground-এ: Runtime error, সাথে ReferenceError: require is not defined in ES module scope, you can use import instead। Node 22 import দেখে পুরো file-টা ES module হিসেবে চালায়, আর সেখানে require বলে কিছু নেই। Starter require ব্যবহার করে, তাই judge করা program-এ import রেখো না। দুই module system বুঝিয়ে বলবে Module 11। লাইনটা তুমি বসাবে, কারণ আজকালকার tutorial শুরুই হয় import দিয়ে।
Alice-এর আছে n-টা পরীক্ষার নম্বর। প্রথম লাইনে ওদের যোগফল ছাপো, দ্বিতীয় লাইনে গড়, দশমিকের পরে হুবহু দুই অঙ্ক। x.toFixed(2) number x-কে দেয় দুই দশমিকের একটা string হিসেবে; পুরোটা দেখাবে Module 2।
Input. n, তারপর n-টা পূর্ণসংখ্যা।
Output. দুই লাইন: যোগফল, তারপর দুই দশমিকে গড়।
Sample. Input 3 আর 72 65 80 দিলে 217 আর 72.33।
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
// Read n, add up n marks with the for shape, then push the sum
// and (sum / n).toFixed(2).
console.log(out.join("\n"));
Grade হয় average-of-n হিসেবে, module test-এও এটা আছে। লুকানো test-এ n = 1 আর negative নম্বরও আছে।
Kenji input শেষ না হওয়া পর্যন্ত শব্দ পড়ে, আর সবচেয়ে লম্বাটা চায়। সবচেয়ে বেশি দৈর্ঘ্য দুইটা শব্দের সমান হলে, যেটা আগে এসেছে সেটা ছাপো।
Input. Space আর line break দিয়ে আলাদা করা শব্দ।
Output. সবচেয়ে লম্বা শব্দটা।
Sample. Input tea biscuit cake দিলে biscuit।
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
// Keep the best word so far in a let. Use the while shape.
// word.length gives a word's length.
console.log(out.join("\n"));
Grade হয় longest-word হিসেবে, যার statement এটাও বলে দেয়, input-এ একটাও শব্দ না থাকলে কী ছাপতে হবে।
সচরাচর যে প্রশ্নগুলো আসে
Tutorial-গুলো input পড়ে
readlineবাprocess.stdin.onদিয়ে। এখানে কেন না?ওগুলো input টুকরো টুকরো করে আসার জন্য অপেক্ষা করে, আর প্রতিটা টুকরো এলে তোমার code চালায়, যেটা বুঝতে লাগে Module 12-এর ধারণা। Starter আগে সবকিছু পড়ে ফেলে, এক লাইনেই, তারপর তোমার code উপর থেকে নিচে চলে, এখন পর্যন্ত প্রতিটা program যেভাবে চলেছে।
importনা লিখেrequireকেন?requireহলো CommonJS-এর, মানে Node-এর আদি module system-এর, আর এখানে judge করা program একটাই সাদামাটা file।importহলো ES module-এর, নতুন system-টার। দুইটাই শেখাবে Module 11, সঙ্গে এটাও যে judge কেন CommonJS-এই থাকে; দুইটা মেশালে কী হয়, দেখিয়েছে "যে ভুলগুলো সবাই করে"।নিজের computer-এ file চালালে input দেব কীভাবে?
Input একটা file-এ save করো, তারপর সেটা ভেতরে পাঠাও:
node main.js < input.txtকাজ করে macOS বা Linux-এর terminal-এ, আর Windows-এর Command Prompt-এ। PowerShell-এ এই কাজের জন্য<নেই, তাই সেখানে লেখোGet-Content input.txt | node main.js।nextInt()কি দশমিক পড়তে পারে না?পারে। এটা আসলে
Number(next()), তাই"2.5"হয়ে যায় 2.5, আর"abc"হয়ে যায়NaN। নামটা এসেছে অন্য ভাষার contest template থেকে, যেখানে পূর্ণসংখ্যা পড়াই সবচেয়ে চলতি কাজ।
মূল কথা
- লাইন 1 পুরো standard input, মানে file 0, পড়ে একটা string হিসেবে; লাইন 2 সেটা কেটে token বানায়।
next()পরের token-টা দেয় string হিসেবে;nextInt()দেয় number হিসেবে।- প্রতিটা উত্তর
pushদিয়ে যায়out-এ, আর শেষ লাইন সবগুলো একবারে ছাপে। - Playground-এর একটা run-এ, 100000 লাইনের জন্য প্রতি লাইনে একটা করে
console.logছিল প্রায় বারো গুণ ধীর। - n দেওয়া থাকলে
forloop; না থাকলে এমন একটাwhileloop, যেটাundefined-এ থামে। - Space-ওয়ালা লেখার জন্য lines variant input কাটে line break-এ, তাই
next()হাতে দেয় পুরো একটা লাইন।
এরপর lesson 06-এর বিষয় সেই পাঠক, judge-এর পরে যে সবচেয়ে জরুরি: যে মানুষটা এরপর তোমার code পড়বে।
lesson ৫ শেষ
শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।
পরেরটা: comment, নাম আর এমন code যা মানুষ পড়তে পারে