Tasks Initiated This Trimester
Gamify
While developing the game engine, it was my job to make a leaderboard.
-
Iteration 1: The leaderboard initially started off as a solely input-based feature that was yet to be connected to the save score feature. Pretty much a prototype, couldn’t be used in real-time yet.
-
Iteration 2: BE API and data table were established, the leaderboard now pulled the name and the scores from the “save_score” table in the backend. The two features were integrated, leaderboard worked in real-time.
-
Iteration 3: Division of leaderboard into two distinct types: DYNAMIC & ELEMENTARY! Dynamic would be the user playing a game, saving their score, and their entry automatically showing up on the leaderboard if it’s in the top 10 scores. Elementary was targetted for CSSE students for them to deepen their understanding of CRUD operations and see their inputs come to life. Input-style leaderboard from iteration 1 was brought back. User now got an option to pick between either for their game screen.
-
Iteration 4: Specific table in the backend for leaderboard was deleted and instead I used the common table created by my peer. Functionality for toggling leaderboard was added. The correct name is now displayed on dynamic as it pulls from the authorized user’s credentials.

Adding a Score through Elementary Option
async addElementaryScore() {
console.log('=== ADD ELEMENTARY SCORE ===');
const nameInput = document.getElementById('player-name');
const scoreInput = document.getElementById('player-score');
const name = nameInput.value.trim();
const score = parseInt(scoreInput.value);
if (!name || isNaN(score)) {
alert('Please enter both name and score');
return;
}
const endpoint = '/api/events/ELEMENTARY_LEADERBOARD';
console.log('POST endpoint:', endpoint);
// If backend is unavailable, save locally in localStorage and update UI
if (!this.hasBackend && !window.javaBackendUrl) {
const storageKey = `elementary_leaderboard_${this.gameName}`;
const stored = JSON.parse(localStorage.getItem(storageKey) || '[]');
const entry = {
id: `local-${Date.now()}`,
payload: { user: name, score: score, gameName: this.gameName },
timestamp: new Date().toISOString()
};
stored.push(entry);
localStorage.setItem(storageKey, JSON.stringify(stored));
// Clear inputs and refresh local display
nameInput.value = '';
scoreInput.value = '';
await this.fetchElementaryLeaderboard();
return;
}
try {
const base =
window.javaBackendUrl ||
(location.hostname === 'localhost' ? 'http://localhost:8585' : javaURI);
const url = `${base.replace(/\/$/, '')}${endpoint}`;
console.log('Full URL:', url);
// Create payload matching Java backend AlgorithmicEvent structure
const requestBody = {
payload: {
user: name,
score: score,
gameName: this.gameName
}
};
console.log('Payload:', JSON.stringify(requestBody));
// POST to backend - using fetchOptions for proper authentication
const res = await fetch(
url,
{
...fetchOptions,
method: 'POST',
headers: {
...fetchOptions?.headers,
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody)
}
);Deleting a Score through Elementary Leaderboard
async deleteElementaryScore(id) {
if (!confirm('Are you sure you want to delete this score?')) {
return;
}
console.log('=== DELETE SCORE ===');
console.log('Deleting ID:', id);
try {
// If backend unavailable, delete from localStorage
if (!this.hasBackend && !window.javaBackendUrl) {
const storageKey = `elementary_leaderboard_${this.gameName}`;
const stored = JSON.parse(localStorage.getItem(storageKey) || '[]');
const filtered = stored.filter(e => e.id !== id);
localStorage.setItem(storageKey, JSON.stringify(filtered));
await this.fetchElementaryLeaderboard();
return;
}
const base =
window.javaBackendUrl ||
(location.hostname === 'localhost' ? 'http://localhost:8585' : javaURI);
const url = `${base.replace(/\/$/, '')}/api/events/ELEMENTARY_LEADERBOARD/${id}`;
console.log('DELETE URL:', url);
// DELETE from backend - using fetchOptions for proper authentication
const res = await fetch(
url,
{
...fetchOptions,
method: 'DELETE'
}
);
if (!res.ok) {
const errorText = await res.text();
console.error('Delete failed:', res.status, errorText);
throw new Error(`Failed to delete: ${res.status} - ${errorText}`);
}
console.log('Score deleted successfully');
// Fetch updated leaderboard from backend
await this.fetchElementaryLeaderboard();
} catch (error) {
console.error('Error deleting score:', error);
alert(`Failed to delete score: ${error.message}`);
}
}Fetching User and Score through Dynamic Leaderboard
async fetchLeaderboard() {
if (this.mode !== 'dynamic') return;
const list = document.getElementById('leaderboard-list');
if (!list) return;
try {
// If backend unavailable, load local scores
if (!this.hasBackend && !window.javaBackendUrl) {
const storageKey = `score_counter_${this.gameName}`;
const stored = JSON.parse(localStorage.getItem(storageKey) || '[]');
const transformed = stored.map(e => ({
id: e.id,
payload: { user: e.payload.user, score: e.payload.score, gameName: e.payload.gameName },
timestamp: e.timestamp
}));
this.displayLeaderboard(transformed);
return;
}
const base =
window.javaBackendUrl ||
(location.hostname === 'localhost' ? 'http://localhost:8585' : javaURI);
const res = await fetch(
`${base.replace(/\/$/, '')}/api/events/SCORE_COUNTER`,
{
...fetchOptions,
method: 'GET'
}
);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
const data = await res.json();
this.displayLeaderboard(data);
} catch (err) {
console.error('Error fetching dynamic leaderboard:', err);
// Check for authentication errors (401 or 403 status)
if (err.message && (err.message.includes('401') || err.message.includes('403'))) {
list.innerHTML = `<p class="error">Please login to access this feature.</p>`;
} else {
list.innerHTML = `<p class="error">Failed to load leaderboard</p>`;
}
}
}Implemented “e” Interact Feature for the Chicken and the End Portal
MCQ + FRQ Reflection
Going Forward Into Trimester 3
Team Methology & Tasks for Future