javascript

exercises

exercises.js
/**
 * 14.2 Math Object - Exercises
 *
 * Practice using Math methods for various calculations.
 */

/**
 * Exercise 1: Dice Roller
 *
 * Create a function that simulates rolling multiple dice.
 *
 * @param {number} numDice - Number of dice to roll
 * @param {number} sides - Number of sides per die (default: 6)
 * @returns {object} - { rolls: number[], total: number, average: number }
 */
function rollDice(numDice, sides = 6) {
  // Your code here
}

// console.log(rollDice(3));
// { rolls: [4, 2, 6], total: 12, average: 4 }

// console.log(rollDice(2, 20));  // D20 dice
// { rolls: [15, 8], total: 23, average: 11.5 }

/**
 * Exercise 2: Temperature Converter
 *
 * Create functions to convert between Celsius, Fahrenheit, and Kelvin.
 * Round results to 2 decimal places.
 *
 * Formulas:
 * - F = C × 9/5 + 32
 * - C = (F - 32) × 5/9
 * - K = C + 273.15
 */
function celsiusToFahrenheit(celsius) {
  // Your code here
}

function fahrenheitToCelsius(fahrenheit) {
  // Your code here
}

function celsiusToKelvin(celsius) {
  // Your code here
}

function kelvinToCelsius(kelvin) {
  // Your code here
}

// console.log(celsiusToFahrenheit(100));   // 212
// console.log(fahrenheitToCelsius(32));    // 0
// console.log(celsiusToKelvin(0));         // 273.15
// console.log(kelvinToCelsius(0));         // -273.15

/**
 * Exercise 3: Geometry Calculator
 *
 * Create a geometry object with methods for various shape calculations.
 * Round all results to 4 decimal places.
 */
const geometry = {
  // Circle methods
  circleArea(radius) {
    // Your code here
  },

  circumference(radius) {
    // Your code here
  },

  // Rectangle methods
  rectangleArea(width, height) {
    // Your code here
  },

  rectanglePerimeter(width, height) {
    // Your code here
  },

  rectangleDiagonal(width, height) {
    // Your code here
  },

  // Triangle methods
  triangleArea(base, height) {
    // Your code here
  },

  // Pythagorean: find missing side
  pythagorean(a, b, findHypotenuse = true) {
    // Your code here
    // If findHypotenuse is true, find c given a and b
    // If false, find b given a (leg) and c (hypotenuse as 'b' parameter)
  },

  // Sphere methods
  sphereVolume(radius) {
    // Your code here
  },

  sphereSurfaceArea(radius) {
    // Your code here
  },
};

// console.log(geometry.circleArea(5));           // 78.5398
// console.log(geometry.circumference(5));        // 31.4159
// console.log(geometry.rectangleDiagonal(3, 4)); // 5
// console.log(geometry.triangleArea(10, 5));     // 25
// console.log(geometry.pythagorean(3, 4));       // 5 (hypotenuse)
// console.log(geometry.pythagorean(3, 5, false)); // 4 (other leg)
// console.log(geometry.sphereVolume(3));         // 113.0973

/**
 * Exercise 4: Statistical Functions
 *
 * Create statistical functions that work with arrays of numbers.
 */
function mean(numbers) {
  // Your code here
}

function median(numbers) {
  // Your code here
}

function mode(numbers) {
  // Your code here - return array of mode(s)
}

function standardDeviation(numbers) {
  // Your code here
}

function variance(numbers) {
  // Your code here
}

// console.log(mean([1, 2, 3, 4, 5]));              // 3
// console.log(median([1, 2, 3, 4, 5]));            // 3
// console.log(median([1, 2, 3, 4]));               // 2.5
// console.log(mode([1, 2, 2, 3, 3, 3, 4]));        // [3]
// console.log(mode([1, 1, 2, 2]));                 // [1, 2]
// console.log(standardDeviation([2, 4, 4, 4, 5, 5, 7, 9])); // ~2
// console.log(variance([2, 4, 4, 4, 5, 5, 7, 9])); // 4

/**
 * Exercise 5: Angle Utilities
 *
 * Create functions for working with angles.
 */
function degreesToRadians(degrees) {
  // Your code here
}

function radiansToDegrees(radians) {
  // Your code here
}

function normalizeAngle(degrees) {
  // Normalize angle to 0-360 range
  // Your code here
}

function angleBetweenPoints(x1, y1, x2, y2) {
  // Return angle in degrees from point 1 to point 2
  // Your code here
}

function rotatePoint(x, y, angleDegrees, centerX = 0, centerY = 0) {
  // Rotate point around center by angle
  // Return { x, y }
  // Your code here
}

// console.log(degreesToRadians(180));                    // 3.14159...
// console.log(radiansToDegrees(Math.PI));                // 180
// console.log(normalizeAngle(450));                      // 90
// console.log(normalizeAngle(-90));                      // 270
// console.log(angleBetweenPoints(0, 0, 1, 1));           // 45
// console.log(rotatePoint(1, 0, 90));                    // { x: 0, y: 1 }

/**
 * Exercise 6: Random Utilities
 *
 * Create various random generation functions.
 */
function randomBetween(min, max, isInteger = true) {
  // Your code here
}

function randomColor() {
  // Return random hex color like "#A3F2C1"
  // Your code here
}

function randomRGB() {
  // Return { r, g, b } with values 0-255
  // Your code here
}

function weightedRandom(items, weights) {
  // Return random item based on weights
  // items = ['common', 'rare', 'legendary']
  // weights = [70, 25, 5] (percentages)
  // Your code here
}

function generatePassword(length, options = {}) {
  // options: { uppercase, lowercase, numbers, symbols }
  // Default: all true
  // Your code here
}

// console.log(randomBetween(1, 10));          // 1-10 integer
// console.log(randomBetween(0, 1, false));    // 0-1 float
// console.log(randomColor());                 // "#A3F2C1"
// console.log(randomRGB());                   // { r: 163, g: 242, b: 193 }
// console.log(weightedRandom(['common', 'rare', 'legendary'], [70, 25, 5]));
// console.log(generatePassword(12));          // "Kj3#mP9$nL2@"

/**
 * Exercise 7: Financial Calculator
 *
 * Create financial calculation functions.
 */
function compoundInterest(principal, rate, time, n = 12) {
  // A = P(1 + r/n)^(nt)
  // principal: initial amount
  // rate: annual interest rate (as decimal, e.g., 0.05 for 5%)
  // time: years
  // n: compounding frequency per year (default monthly)
  // Your code here
}

function loanPayment(principal, annualRate, months) {
  // Monthly payment for a loan
  // M = P * (r(1+r)^n) / ((1+r)^n - 1)
  // r = monthly rate, n = number of payments
  // Your code here
}

function futureValue(payment, rate, periods) {
  // Future value of regular payments
  // FV = PMT * ((1+r)^n - 1) / r
  // Your code here
}

// console.log(compoundInterest(1000, 0.05, 10));        // ~1647.01
// console.log(loanPayment(200000, 0.06, 360));          // ~1199.10
// console.log(futureValue(500, 0.005, 120));            // ~77641.14

/**
 * Exercise 8: Distance and Position
 *
 * Create functions for 2D/3D distance calculations.
 */
function distance2D(x1, y1, x2, y2) {
  // Your code here
}

function distance3D(x1, y1, z1, x2, y2, z2) {
  // Your code here
}

function midpoint(x1, y1, x2, y2) {
  // Return { x, y }
  // Your code here
}

function isInsideCircle(pointX, pointY, circleX, circleY, radius) {
  // Your code here
}

function isInsideRectangle(pointX, pointY, rectX, rectY, width, height) {
  // Your code here
}

// console.log(distance2D(0, 0, 3, 4));                  // 5
// console.log(distance3D(0, 0, 0, 1, 2, 2));            // 3
// console.log(midpoint(0, 0, 10, 10));                  // { x: 5, y: 5 }
// console.log(isInsideCircle(1, 1, 0, 0, 5));           // true
// console.log(isInsideRectangle(5, 5, 0, 0, 10, 10));   // true

/**
 * Exercise 9: Number Rounding Utilities
 *
 * Create flexible rounding functions.
 */
function roundTo(num, decimals) {
  // Your code here
}

function roundToNearest(num, nearest) {
  // Round to nearest multiple (e.g., nearest 5, 10, 0.25)
  // Your code here
}

function roundUp(num, decimals = 0) {
  // Your code here
}

function roundDown(num, decimals = 0) {
  // Your code here
}

function bankersRounding(num, decimals = 0) {
  // Round half to even (banker's rounding)
  // 2.5 -> 2, 3.5 -> 4, 4.5 -> 4, 5.5 -> 6
  // Your code here
}

// console.log(roundTo(3.14159, 2));             // 3.14
// console.log(roundToNearest(17, 5));           // 15
// console.log(roundToNearest(2.3, 0.25));       // 2.25
// console.log(roundUp(3.14, 1));                // 3.2
// console.log(roundDown(3.19, 1));              // 3.1
// console.log(bankersRounding(2.5));            // 2
// console.log(bankersRounding(3.5));            // 4

/**
 * Exercise 10: Math Expression Evaluator
 *
 * Create a simple math expression evaluator that supports:
 * - Basic operations: +, -, *, /
 * - Powers: ^
 * - Common functions: sqrt, abs, sin, cos, tan, log
 * - Constants: pi, e
 *
 * Note: This is a simplified evaluator for learning purposes.
 */
function evaluateMath(expression) {
  // Your code here
}

// console.log(evaluateMath("2 + 3"));           // 5
// console.log(evaluateMath("sqrt(16)"));        // 4
// console.log(evaluateMath("2^3"));             // 8
// console.log(evaluateMath("pi * 2"));          // 6.283...
// console.log(evaluateMath("sin(0)"));          // 0
// console.log(evaluateMath("abs(-5)"));         // 5

// ============================================
// SOLUTIONS
// ============================================

/*
// Solution 1
function rollDice(numDice, sides = 6) {
    const rolls = [];
    for (let i = 0; i < numDice; i++) {
        rolls.push(Math.floor(Math.random() * sides) + 1);
    }
    const total = rolls.reduce((sum, roll) => sum + roll, 0);
    return {
        rolls,
        total,
        average: total / numDice
    };
}

// Solution 2
function celsiusToFahrenheit(celsius) {
    return Math.round((celsius * 9/5 + 32) * 100) / 100;
}

function fahrenheitToCelsius(fahrenheit) {
    return Math.round(((fahrenheit - 32) * 5/9) * 100) / 100;
}

function celsiusToKelvin(celsius) {
    return Math.round((celsius + 273.15) * 100) / 100;
}

function kelvinToCelsius(kelvin) {
    return Math.round((kelvin - 273.15) * 100) / 100;
}

// Solution 3
const geometry = {
    circleArea(radius) {
        return Math.round(Math.PI * radius ** 2 * 10000) / 10000;
    },
    
    circumference(radius) {
        return Math.round(2 * Math.PI * radius * 10000) / 10000;
    },
    
    rectangleArea(width, height) {
        return Math.round(width * height * 10000) / 10000;
    },
    
    rectanglePerimeter(width, height) {
        return Math.round(2 * (width + height) * 10000) / 10000;
    },
    
    rectangleDiagonal(width, height) {
        return Math.round(Math.hypot(width, height) * 10000) / 10000;
    },
    
    triangleArea(base, height) {
        return Math.round(0.5 * base * height * 10000) / 10000;
    },
    
    pythagorean(a, b, findHypotenuse = true) {
        if (findHypotenuse) {
            return Math.round(Math.hypot(a, b) * 10000) / 10000;
        }
        return Math.round(Math.sqrt(b ** 2 - a ** 2) * 10000) / 10000;
    },
    
    sphereVolume(radius) {
        return Math.round((4/3) * Math.PI * radius ** 3 * 10000) / 10000;
    },
    
    sphereSurfaceArea(radius) {
        return Math.round(4 * Math.PI * radius ** 2 * 10000) / 10000;
    }
};

// Solution 4
function mean(numbers) {
    return numbers.reduce((sum, n) => sum + n, 0) / numbers.length;
}

function median(numbers) {
    const sorted = [...numbers].sort((a, b) => a - b);
    const mid = Math.floor(sorted.length / 2);
    return sorted.length % 2 === 0
        ? (sorted[mid - 1] + sorted[mid]) / 2
        : sorted[mid];
}

function mode(numbers) {
    const counts = {};
    let maxCount = 0;
    
    for (const num of numbers) {
        counts[num] = (counts[num] || 0) + 1;
        maxCount = Math.max(maxCount, counts[num]);
    }
    
    return Object.keys(counts)
        .filter(key => counts[key] === maxCount)
        .map(Number);
}

function variance(numbers) {
    const avg = mean(numbers);
    const squareDiffs = numbers.map(n => (n - avg) ** 2);
    return mean(squareDiffs);
}

function standardDeviation(numbers) {
    return Math.sqrt(variance(numbers));
}

// Solution 5
function degreesToRadians(degrees) {
    return degrees * (Math.PI / 180);
}

function radiansToDegrees(radians) {
    return radians * (180 / Math.PI);
}

function normalizeAngle(degrees) {
    return ((degrees % 360) + 360) % 360;
}

function angleBetweenPoints(x1, y1, x2, y2) {
    return radiansToDegrees(Math.atan2(y2 - y1, x2 - x1));
}

function rotatePoint(x, y, angleDegrees, centerX = 0, centerY = 0) {
    const radians = degreesToRadians(angleDegrees);
    const cos = Math.cos(radians);
    const sin = Math.sin(radians);
    
    const dx = x - centerX;
    const dy = y - centerY;
    
    return {
        x: Math.round((cos * dx - sin * dy + centerX) * 10000) / 10000,
        y: Math.round((sin * dx + cos * dy + centerY) * 10000) / 10000
    };
}

// Solution 6
function randomBetween(min, max, isInteger = true) {
    if (isInteger) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    return Math.random() * (max - min) + min;
}

function randomColor() {
    const hex = Math.floor(Math.random() * 0xFFFFFF).toString(16);
    return '#' + hex.padStart(6, '0').toUpperCase();
}

function randomRGB() {
    return {
        r: Math.floor(Math.random() * 256),
        g: Math.floor(Math.random() * 256),
        b: Math.floor(Math.random() * 256)
    };
}

function weightedRandom(items, weights) {
    const totalWeight = weights.reduce((sum, w) => sum + w, 0);
    let random = Math.random() * totalWeight;
    
    for (let i = 0; i < items.length; i++) {
        random -= weights[i];
        if (random <= 0) {
            return items[i];
        }
    }
    return items[items.length - 1];
}

function generatePassword(length, options = {}) {
    const {
        uppercase = true,
        lowercase = true,
        numbers = true,
        symbols = true
    } = options;
    
    let chars = '';
    if (uppercase) chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    if (lowercase) chars += 'abcdefghijklmnopqrstuvwxyz';
    if (numbers) chars += '0123456789';
    if (symbols) chars += '!@#$%^&*()_+-=[]{}|;:,.<>?';
    
    if (!chars) return '';
    
    let password = '';
    for (let i = 0; i < length; i++) {
        password += chars[Math.floor(Math.random() * chars.length)];
    }
    return password;
}

// Solution 7
function compoundInterest(principal, rate, time, n = 12) {
    return Math.round(principal * Math.pow(1 + rate / n, n * time) * 100) / 100;
}

function loanPayment(principal, annualRate, months) {
    const monthlyRate = annualRate / 12;
    const payment = principal * 
        (monthlyRate * Math.pow(1 + monthlyRate, months)) / 
        (Math.pow(1 + monthlyRate, months) - 1);
    return Math.round(payment * 100) / 100;
}

function futureValue(payment, rate, periods) {
    const fv = payment * ((Math.pow(1 + rate, periods) - 1) / rate);
    return Math.round(fv * 100) / 100;
}

// Solution 8
function distance2D(x1, y1, x2, y2) {
    return Math.hypot(x2 - x1, y2 - y1);
}

function distance3D(x1, y1, z1, x2, y2, z2) {
    return Math.hypot(x2 - x1, y2 - y1, z2 - z1);
}

function midpoint(x1, y1, x2, y2) {
    return {
        x: (x1 + x2) / 2,
        y: (y1 + y2) / 2
    };
}

function isInsideCircle(pointX, pointY, circleX, circleY, radius) {
    return distance2D(pointX, pointY, circleX, circleY) <= radius;
}

function isInsideRectangle(pointX, pointY, rectX, rectY, width, height) {
    return pointX >= rectX && 
           pointX <= rectX + width && 
           pointY >= rectY && 
           pointY <= rectY + height;
}

// Solution 9
function roundTo(num, decimals) {
    const factor = Math.pow(10, decimals);
    return Math.round(num * factor) / factor;
}

function roundToNearest(num, nearest) {
    return Math.round(num / nearest) * nearest;
}

function roundUp(num, decimals = 0) {
    const factor = Math.pow(10, decimals);
    return Math.ceil(num * factor) / factor;
}

function roundDown(num, decimals = 0) {
    const factor = Math.pow(10, decimals);
    return Math.floor(num * factor) / factor;
}

function bankersRounding(num, decimals = 0) {
    const factor = Math.pow(10, decimals);
    const shifted = num * factor;
    const floor = Math.floor(shifted);
    const decimal = shifted - floor;
    
    if (decimal === 0.5) {
        // Round to even
        return (floor % 2 === 0 ? floor : floor + 1) / factor;
    }
    return Math.round(shifted) / factor;
}

// Solution 10
function evaluateMath(expression) {
    // Replace constants
    let expr = expression
        .replace(/\bpi\b/gi, Math.PI.toString())
        .replace(/\be\b/gi, Math.E.toString());
    
    // Replace functions
    expr = expr.replace(/sqrt\(([^)]+)\)/gi, (_, arg) => Math.sqrt(parseFloat(arg)));
    expr = expr.replace(/abs\(([^)]+)\)/gi, (_, arg) => Math.abs(parseFloat(arg)));
    expr = expr.replace(/sin\(([^)]+)\)/gi, (_, arg) => Math.sin(parseFloat(arg)));
    expr = expr.replace(/cos\(([^)]+)\)/gi, (_, arg) => Math.cos(parseFloat(arg)));
    expr = expr.replace(/tan\(([^)]+)\)/gi, (_, arg) => Math.tan(parseFloat(arg)));
    expr = expr.replace(/log\(([^)]+)\)/gi, (_, arg) => Math.log(parseFloat(arg)));
    
    // Replace ^ with **
    expr = expr.replace(/\^/g, '**');
    
    // Evaluate (simple and unsafe - for learning only!)
    try {
        return Function('"use strict"; return (' + expr + ')')();
    } catch (e) {
        return NaN;
    }
}
*/
Exercises - JavaScript Tutorial | DeepML