// ============== CONFIGURATION ==============
const CONFIG = {
// Styling for Problem Column (Column A)
PROBLEM_BG: "#fce4d6",
PROBLEM_TEXT_COLOR: "#000000",
// Styling for Submission Status Column (Column B)
STATUS_BG_DEFAULT: "#f4f4f4",
STATUS_BG_AC: "#a9d18e", // For accepted submissions.
STATUS_BG_WA: "#f4b084", // For wrong answer, runtime error, compilation
error.
STATUS_BG_TLE: "#ffff99", // For time limit exceeded.
STATUS_BG_MLE: "#d1c4e9", // For memory limit exceeded.
// Font settings (applied to rich text)
FONT_BOLD: true,
FONT_SIZE_STATUS: 10
};
// ============================================
function updateSubmissions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Use your CodeForces handle here:
var cfHandle = "Ahmed_Aasim";
// Fetch all submissions for your handle using the CodeForces API
var apiUrl = "https://codeforces.com/api/user.status?handle=" + cfHandle;
var response = UrlFetchApp.fetch(apiUrl);
var data = JSON.parse(response.getContentText());
if (data.status !== "OK") {
Logger.log("Error fetching submissions: " + data.comment);
return;
}
var submissions = data.result;
// Build a map keyed by "contestId + problemIndex", e.g. "69A".
// Each key stores:
// - latestSubmission,
// - latestAccepted (if exists),
// - rating: taken from the submission's problem (if present)
var submissionMap = {};
submissions.forEach(function (sub) {
if (!sub.problem || !sub.problem.contestId || !sub.problem.index) return;
var key = sub.problem.contestId.toString() + sub.problem.index.toUpperCase();
if (!submissionMap[key]) {
submissionMap[key] = {
latestSubmission: sub,
latestAccepted: null,
rating: sub.problem.rating || "N/A"
};
} else {
if (sub.creationTimeSeconds >
submissionMap[key].latestSubmission.creationTimeSeconds) {
submissionMap[key].latestSubmission = sub;
// Update rating if available (it may change if a new submission has a
rating)
submissionMap[key].rating = sub.problem.rating || "N/A";
}
}
if (sub.verdict === "OK") {
if (!submissionMap[key].latestAccepted ||
sub.creationTimeSeconds >
submissionMap[key].latestAccepted.creationTimeSeconds) {
submissionMap[key].latestAccepted = sub;
}
}
});
// Fetch the complete list of CodeForces problems to get their full names and
ratings.
// This is useful if you haven't solved or attempted a problem.
var allProblems = {};
try {
var responseProblems =
UrlFetchApp.fetch("https://codeforces.com/api/problemset.problems");
var dataProblems = JSON.parse(responseProblems.getContentText());
if (dataProblems.status === "OK") {
dataProblems.result.problems.forEach(function (prob) {
if (prob.contestId && prob.index) {
var key = prob.contestId.toString() + prob.index.toUpperCase();
allProblems[key] = {
name: prob.name,
rating: prob.rating || "N/A"
};
}
});
}
} catch (e) {
Logger.log("Error fetching problemset problems: " + e);
}
// Get all values in column A starting from row 2.
var dataRange = sheet.getRange("A2:A");
var problemIds = dataRange.getValues();
// Process each row in column A.
for (var i = 0; i < problemIds.length; i++) {
var value = problemIds[i][0].toString().trim();
if (value === "") continue; // Skip empty cells.
// Expect problem IDs in the format "69A"
var match = value.match(/^(\d+)([A-Za-z]+)$/);
if (!match) continue;
var contestId = match[1];
var problemIndex = match[2].toUpperCase();
var key = contestId + problemIndex;
// Build the URL for the problem statement.
var probUrl = "https://codeforces.com/problemset/problem/" + contestId + "/" +
problemIndex;
var cellA = sheet.getRange(i + 2, 1); // Column A
// Determine the full problem name and rating.
var problemName = null;
var problemRating = "N/A";
if (submissionMap.hasOwnProperty(key)) {
problemName = submissionMap[key].latestSubmission.problem.name;
problemRating = submissionMap[key].rating;
} else if (allProblems.hasOwnProperty(key)) {
problemName = allProblems[key].name;
problemRating = allProblems[key].rating;
}
var displayText = value;
if (problemName) {
displayText = value + " - " + problemName;
}
// Build the text style for Column A.
var textStyleA = SpreadsheetApp.newTextStyle()
.setForegroundColor(CONFIG.PROBLEM_TEXT_COLOR)
.setUnderline(false)
.setBold(CONFIG.FONT_BOLD)
.build();
var richTextA = SpreadsheetApp.newRichTextValue()
.setText(displayText)
.setLinkUrl(probUrl)
.setTextStyle(0, displayText.length, textStyleA)
.build();
cellA.setRichTextValue(richTextA);
cellA.setHorizontalAlignment("center");
cellA.setBackground(CONFIG.PROBLEM_BG);
// -----------------------------
// Column B: Submission Status
// -----------------------------
var cellB = sheet.getRange(i + 2, 2);
var shortStatus = "N/A";
var emoji = "❔";
var bgColorStatus = CONFIG.STATUS_BG_DEFAULT;
var statusText = "";
var richTextB = null;
var chosenSub = null;
var submissionDateTime = null;
if (submissionMap.hasOwnProperty(key)) {
var record = submissionMap[key];
if (record.latestAccepted) {
chosenSub = record.latestAccepted;
shortStatus = "AC";
emoji = "✅";
bgColorStatus = CONFIG.STATUS_BG_AC;
} else if (record.latestSubmission) {
chosenSub = record.latestSubmission;
submissionDateTime = new Date(chosenSub.creationTimeSeconds * 1000);
var verdict = chosenSub.verdict;
switch (verdict) {
case "WRONG_ANSWER":
shortStatus = "WA";
emoji = "❌";
bgColorStatus = CONFIG.STATUS_BG_WA;
break;
case "TIME_LIMIT_EXCEEDED":
shortStatus = "TLE";
emoji = "⌛";
bgColorStatus = CONFIG.STATUS_BG_TLE;
break;
case "MEMORY_LIMIT_EXCEEDED":
shortStatus = "MLE";
emoji = "💾";
bgColorStatus = CONFIG.STATUS_BG_MLE;
break;
case "RUNTIME_ERROR":
shortStatus = "RE";
emoji = "⚠️";
bgColorStatus = CONFIG.STATUS_BG_WA;
break;
case "COMPILATION_ERROR":
shortStatus = "CE";
emoji = "🚫";
bgColorStatus = CONFIG.STATUS_BG_WA;
break;
default:
shortStatus = verdict.substring(0, 3).toUpperCase();
emoji = "❓";
bgColorStatus = CONFIG.STATUS_BG_WA;
break;
}
}
statusText = shortStatus + " " + emoji;
// Build the hyperlink for the status (linking to the submission).
if (chosenSub) {
var submissionUrl = "https://codeforces.com/contest/" + contestId +
"/submission/" + chosenSub.id;
var textStyleB = SpreadsheetApp.newTextStyle()
.setForegroundColor(CONFIG.PROBLEM_TEXT_COLOR)
.setUnderline(false)
.setBold(CONFIG.FONT_BOLD)
.build();
richTextB = SpreadsheetApp.newRichTextValue()
.setText(statusText)
.setLinkUrl(submissionUrl)
.setTextStyle(0, statusText.length, textStyleB)
.build();
cellB.setRichTextValue(richTextB);
} else {
cellB.setValue(statusText);
}
} else {
statusText = "N/A ❌";
cellB.setValue(statusText);
}
cellB.setHorizontalAlignment("center");
cellB.setFontSize(CONFIG.FONT_SIZE_STATUS);
cellB.setBackground(bgColorStatus);
// -----------------------------
// Column C: Problem Rating
// -----------------------------
var cellC = sheet.getRange(i + 2, 3);
cellC.setValue(problemRating);
cellC.setHorizontalAlignment("center");
cellC.setFontSize(CONFIG.FONT_SIZE_STATUS);
// -----------------------------
// Column D: Submission Date & Time
// -----------------------------
var cellD = sheet.getRange(i + 2, 4);
if (chosenSub && submissionDateTime) {
// Format the date as "dd/MM/yyyy - HH:mm"
var formattedDate = Utilities.formatDate(
submissionDateTime,
Session.getScriptTimeZone(),
"dd/MM/yyyy - HH:mm"
);
cellD.setValue(formattedDate);
} else {
cellD.setValue("N/A");
}
cellD.setHorizontalAlignment("center");
}
}