Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 47 additions & 2 deletions task-1/Time.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,48 @@
export class Time {
// Your code here
}
#secondsFromMidnight;

constructor(hours, minutes, seconds) {
this.#secondsFromMidnight = hours * 3600 + minutes * 60 + seconds;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the numeric constants are not that difficult to reason about, it would be even clearer if you created a couple of constants for these "magic" numbers and then used them throughout your code. For instance:

const SEC_PER_MINUTE = 60;
const SEC_PER_HOUR = 60 * SEC_PER_MINUTE;
const SEC_PER_DAY = 24 * SEC_PER_HOUR;

this.#normalize();
}

// Private helper to keep seconds in 0..86399
#normalize() {
this.#secondsFromMidnight %= 86400;
if (this.#secondsFromMidnight < 0) {
this.#secondsFromMidnight += 86400;
}
}

getHours() {
return Math.floor(this.#secondsFromMidnight / 3600);
}

getMinutes() {
return Math.floor((this.#secondsFromMidnight % 3600) / 60);
}

getSeconds() {
return this.#secondsFromMidnight % 60;
}

addSeconds(seconds) {
this.#secondsFromMidnight += seconds;
this.#normalize();
}

addMinutes(minutes) {
this.addSeconds(minutes * 60);
}

addHours(hours) {
this.addSeconds(hours * 3600);
}

toString() {
const hh = String(this.getHours()).padStart(2, "0");
const mm = String(this.getMinutes()).padStart(2, "0");
const ss = String(this.getSeconds()).padStart(2, "0");
return `${hh}:${mm}:${ss}`;
}
}
1 change: 1 addition & 0 deletions task-2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
246 changes: 245 additions & 1 deletion task-2/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,245 @@
// Write your code here. You may create as many files as you like.
// ===============================================
// AI QUIZ GAME — GitHub Models Edition
// Final Clean Version with English Comments
// ===============================================

import OpenAI from "openai";
import dotenv from "dotenv";
import readline from "readline";
import chalk from "chalk";

// Load environment variables
dotenv.config();

// Read GitHub token
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;

if (!GITHUB_TOKEN) {
console.error("⚠️ Please set GITHUB_TOKEN in your .env file");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annoying, but AI tools often generate emojis like this in console.log statements.

process.exit(1);
}

// ----------------------------------------------------
// Initialize GitHub Models client
// IMPORTANT: baseURL must stop at /inference
// The SDK automatically appends /chat/completions
// ----------------------------------------------------
const client = new OpenAI({
baseURL: "https://models.github.ai/inference",
apiKey: GITHUB_TOKEN,
});

// CLI interface
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

// Helper for asking questions in CLI
function ask(questionText) {
return new Promise((resolve) => rl.question(questionText, resolve));
}

let score = 0;

// ----------------------------------------------------
// Generate quiz questions using GitHub LLM
// Includes JSON cleanup and validation
// ----------------------------------------------------
async function generateQuestions(topic, difficulty) {
console.log("\n🎲 Generating questions via GitHub LLM...");

const prompt = `
Generate exactly 10 ${difficulty} quiz questions about ${topic}.
Format each question EXACTLY like this:

Q1: What is ...?
A) Option 1
B) Option 2
C) Option 3
D) Option 4
Correct: B

Do NOT use JSON.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed this later. It is simpler if you ask the LLM to return (only) JSON. Then you do not have to parse the text response yourself, but instead can use JSON.parse().

Do NOT add explanations.
Do NOT add extra text.
`;

try {
const response = await client.chat.completions.create({
model: "openai/gpt-4o-mini",
messages: [
{ role: "system", content: "Follow the format strictly." },
{ role: "user", content: prompt },
],
temperature: 0.8,
});

const text = response.choices[0].message.content;

// ---------------------------------------------
// Parse the text into JSON
// ---------------------------------------------
const blocks = text.split(/Q\d+:/).slice(1);

const questions = blocks.map((block, index) => {
const lines = block.trim().split("\n");

const question = lines[0].trim();

const answers = [
lines[1].replace("A)", "").trim(),
lines[2].replace("B)", "").trim(),
lines[3].replace("C)", "").trim(),
lines[4].replace("D)", "").trim(),
];

const correctLine = lines.find((l) => l.startsWith("Correct"));
const correctLetter = correctLine.split(":")[1].trim();

const map = { A: 1, B: 2, C: 3, D: 4 };

return {
question,
answers,
correctAnswer: map[correctLetter],
};
});

if (questions.length !== 10) {
throw new Error("Model did not return 10 questions");
}

return questions;
} catch (err) {
console.error("⚠️ Could not generate questions from GitHub LLM.");
console.error(chalk.yellow("Using fallback questions."));
console.error(chalk.red(err.message));

return [
{
question: "Which country has the city of Kyoto?",
answers: ["China", "Japan", "South Korea", "Thailand"],
correctAnswer: 2,
},
{
question: "What is the largest planet in our solar system?",
answers: ["Earth", "Jupiter", "Saturn", "Mars"],
correctAnswer: 2,
},
];
}
}

// ----------------------------------------------------
// Ask a single question (supports hints)
// ----------------------------------------------------
async function askQuestion(qObj, index) {
console.log(`\nQuestion ${index + 1}: ${qObj.question}`);
qObj.answers.forEach((ans, i) => console.log(`${i + 1}. ${ans}`));

while (true) {
const answer = await ask("Your answer (1-4, h for hint, q to quit): ");

// Quit
if (answer.toLowerCase() === "q") {
console.log("\nExiting quiz...");
rl.close();
return null;
}

// Hint
if (answer.toLowerCase() === "h") {
const correctIndex = qObj.correctAnswer - 1;

// Randomly hide 2 wrong answers
const hide = [0, 1, 2, 3]
.filter((i) => i !== correctIndex)
.sort(() => 0.5 - Math.random())
.slice(0, 2);

console.log("Hint: possible answers:");
qObj.answers.forEach((ans, i) => {
if (!hide.includes(i)) console.log(`${i + 1}. ${ans}`);
});

continue;
}

// Validate answer
const num = parseInt(answer);

if ([1, 2, 3, 4].includes(num)) {
if (num === qObj.correctAnswer) {
console.log(chalk.green("✅ Correct!"));
score++;
} else {
console.log(
chalk.red(
`❌ Wrong! Correct answer: ${qObj.correctAnswer}. ${qObj.answers[qObj.correctAnswer - 1]}`,
),
);
}
break;
} else {
console.log("⚠️ Please enter 1-4, h for hint, or q to quit.");
}
}
}

// ----------------------------------------------------
// Main quiz flow
// ----------------------------------------------------
async function startQuiz() {
console.log("🎮 AI Quiz Game");

const topics = ["General Knowledge", "Programming", "Geography"];
topics.forEach((t, i) => console.log(`${i + 1}. ${t}`));

// Select topic
let topic = "";
while (true) {
const tInput = await ask("Select topic (1-3 or q to quit): ");
if (tInput.toLowerCase() === "q") return rl.close();
const tNum = parseInt(tInput);
if (tNum >= 1 && tNum <= topics.length) {
topic = topics[tNum - 1];
break;
}
}

// Select difficulty
const difficulties = ["easy", "medium", "hard"];
difficulties.forEach((d, i) =>
console.log(`${i + 1}. ${d[0].toUpperCase() + d.slice(1)}`),
);

let difficulty = "";
while (true) {
const dInput = await ask("Select difficulty (1-3 or q to quit): ");
if (dInput.toLowerCase() === "q") return rl.close();
const dNum = parseInt(dInput);
if (dNum >= 1 && dNum <= difficulties.length) {
difficulty = difficulties[dNum - 1];
break;
}
}

console.log(`\nStarting quiz: ${topic} | Difficulty: ${difficulty}`);

const questions = await generateQuestions(topic, difficulty);

for (let i = 0; i < questions.length; i++) {
const res = await askQuestion(questions[i], i);
if (res === null) break;
}

console.log(`\n🏆 Quiz finished! Your score: ${score} / ${questions.length}`);
rl.close();
}

// Exit handler
rl.on("close", () => process.exit(0));

// Start the game
startQuiz();
Loading