mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-21 23:00:43 -08:00
295 lines
10 KiB
JavaScript
295 lines
10 KiB
JavaScript
// WEEKDAY
|
|
//
|
|
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
|
|
//
|
|
|
|
function print(str) {
|
|
document.getElementById("output").appendChild(document.createTextNode(str));
|
|
}
|
|
|
|
function input() {
|
|
return new Promise(function (resolve) {
|
|
const input_element = document.createElement("INPUT");
|
|
|
|
print("? ");
|
|
input_element.setAttribute("type", "text");
|
|
input_element.setAttribute("length", "50");
|
|
document.getElementById("output").appendChild(input_element);
|
|
input_element.focus();
|
|
input_element.addEventListener("keydown", function (event) {
|
|
if (event.keyCode === 13) {
|
|
const input_str = input_element.value;
|
|
document.getElementById("output").removeChild(input_element);
|
|
print(input_str);
|
|
print("\n");
|
|
resolve(input_str);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function tab(space) {
|
|
let str = "";
|
|
while (space-- > 0)
|
|
str += " ";
|
|
return str;
|
|
}
|
|
|
|
// in a non-leap year the day of the week for the first of each month moves by the following amounts.
|
|
const COMMON_YEAR_MONTH_OFFSET = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5];
|
|
|
|
/**
|
|
* Reads a date, and extracts the date information.
|
|
* This expects date parts to be comma separated, using US date ordering,
|
|
* i.e. Month,Day,Year.
|
|
* @returns {Promise<[number,number,number]>} [year, month, dayOfMonth]
|
|
*/
|
|
async function readDateElements() {
|
|
let dateString = await input();
|
|
const month = parseInt(dateString);
|
|
const dayOfMonth = parseInt(dateString.substr(dateString.indexOf(",") + 1));
|
|
const year = parseInt(dateString.substr(dateString.lastIndexOf(",") + 1));
|
|
return [year, month, dayOfMonth];
|
|
}
|
|
|
|
/**
|
|
* Returns a US formatted date, i.e. Month/Day/Year.
|
|
* @param year
|
|
* @param month
|
|
* @param day
|
|
* @returns {string}
|
|
*/
|
|
function getFormattedDate(year, month, day) {
|
|
return month + "/" + day + "/" + year;
|
|
}
|
|
|
|
/**
|
|
* Calculate years, months and days as factor of days.
|
|
* This is a naive calculation which assumes all months are 30 days.
|
|
* @param factor
|
|
* @param dayCount
|
|
* @returns {{years: number, months: number, days: number}}
|
|
*/
|
|
function time_spent(factor, dayCount) {
|
|
let totalDays = Math.floor(factor * dayCount);
|
|
const years = Math.floor(totalDays / 365);
|
|
totalDays -= years * 365;
|
|
const months = Math.floor(totalDays / 30);
|
|
const days = totalDays - (months * 30);
|
|
return {years, months, days}
|
|
}
|
|
|
|
/**
|
|
* Print the supplied time
|
|
* @param years
|
|
* @param months
|
|
* @param days
|
|
*/
|
|
function printTimeSpent({years, months, days}) {
|
|
print(years + "\t" + months + "\t" + days + "\n");
|
|
}
|
|
|
|
/**
|
|
* Adjust unaccounted time by remove years, months and days supplied.
|
|
* @param {{years:number, months:number, days:number}} unaccountedTime
|
|
* @param {{years:number, months:number, days:number}} timeToRemove
|
|
*/
|
|
function adjustUnaccountedTime(unaccountedTime, timeToRemove) {
|
|
unaccountedTime.years -= timeToRemove.years;
|
|
unaccountedTime.months -= timeToRemove.months;
|
|
unaccountedTime.days -= timeToRemove.days;
|
|
if (unaccountedTime.days < 0) {
|
|
unaccountedTime.days += 30;
|
|
unaccountedTime.months--;
|
|
}
|
|
if (unaccountedTime.months <= 0) {
|
|
unaccountedTime.months += 12;
|
|
unaccountedTime.years--;
|
|
}
|
|
}
|
|
|
|
function isLeapYear(year) {
|
|
if ((year % 4) !== 0) {
|
|
return false;
|
|
} else if ((year % 100) !== 0) {
|
|
return true;
|
|
} else if ((year % 400) !== 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Determine the day of the week.
|
|
* This calculation returns a number between 1 and 7 where Sunday=1, Monday=2, ..., Saturday=7.
|
|
* First it calculates a known date near the start of the century (defined as a year ending "00").
|
|
* January 1st in "00" years is always one of: Saturday (years divisible by 400), Friday, Wednesday, or Monday.
|
|
* This is a combination of years being 52 weeks and either 1 (non-leap years) or 2 (leap years) days,
|
|
* and years ending "00" only being leap years if they are also divisible by 400.
|
|
* @param year
|
|
* @param month
|
|
* @param day
|
|
* @returns {number} Value between 1 and 7 representing Sunday to Saturday.
|
|
*/
|
|
function getDayOfWeek(year, month, day) {
|
|
const centuriesSince1500 = Math.floor((year - 1500) / 100);
|
|
let centuryOffset = centuriesSince1500 * 5 + (centuriesSince1500 + 3) / 4;
|
|
centuryOffset = Math.floor(centuryOffset % 7);
|
|
// January 1st moves forward by approximately 1.25 days per year
|
|
const yearInCentury = year % 100;
|
|
const yearInCenturyOffsets = yearInCentury / 4 + yearInCentury;
|
|
|
|
let dayOfWeek = centuryOffset + yearInCenturyOffsets + day + COMMON_YEAR_MONTH_OFFSET[month-1];
|
|
dayOfWeek = Math.floor(dayOfWeek % 7) + 1;
|
|
if (month <= 2 && isLeapYear(year)) {
|
|
dayOfWeek--;
|
|
}
|
|
if (dayOfWeek === 0) {
|
|
dayOfWeek = 7;
|
|
}
|
|
return dayOfWeek;
|
|
}
|
|
|
|
/**
|
|
* The following performs a special hash on the day parts which guarantees
|
|
* that different days will return different numbers, and the numbers returned are in ordered.
|
|
* @param year
|
|
* @param month
|
|
* @param day
|
|
* @returns {*}
|
|
*/
|
|
function getNormalisedDay(year, month, day) {
|
|
return (year * 12 + month) * 31 + day;
|
|
}
|
|
|
|
// Main control section
|
|
async function main() {
|
|
print(tab(32) + "WEEKDAY\n");
|
|
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
|
|
print("\n");
|
|
print("\n");
|
|
print("\n");
|
|
print("WEEKDAY IS A COMPUTER DEMONSTRATION THAT\n");
|
|
print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\n");
|
|
print("\n");
|
|
print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 ");
|
|
const [todayYear, todayMonth, todayDayOfMonth] = await readDateElements();
|
|
// This program determines the day of the week
|
|
// for a date after 1582
|
|
print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)");
|
|
const [dobYear, dobMonth, dobDayOfMonth] = await readDateElements();
|
|
print("\n");
|
|
// Test for date before current calendar.
|
|
// Note: this test is unreliable - the Gregorian calendar was introduced on Friday 15 October 1582
|
|
// and the weekday algorithm fails for dates prior to that
|
|
if (dobYear - 1582 < 0) {
|
|
print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.\n");
|
|
} else {
|
|
const dayOfWeek = getDayOfWeek(dobYear, dobMonth, dobDayOfMonth);
|
|
|
|
const normalisedToday = getNormalisedDay(todayYear, todayMonth, todayDayOfMonth);
|
|
const normalisedDob = getNormalisedDay(dobYear, dobMonth, dobDayOfMonth);
|
|
|
|
if (normalisedToday < normalisedDob) {
|
|
print(getFormattedDate(dobYear, dobMonth, dobDayOfMonth) + " WILL BE A ");
|
|
} else if (normalisedToday === normalisedDob) {
|
|
print(getFormattedDate(dobYear, dobMonth, dobDayOfMonth) + " IS A ");
|
|
} else {
|
|
print(getFormattedDate(dobYear, dobMonth, dobDayOfMonth) + " WAS A ");
|
|
}
|
|
switch (dayOfWeek) {
|
|
case 1:
|
|
print("SUNDAY.\n");
|
|
break;
|
|
case 2:
|
|
print("MONDAY.\n");
|
|
break;
|
|
case 3:
|
|
print("TUESDAY.\n");
|
|
break;
|
|
case 4:
|
|
print("WEDNESDAY.\n");
|
|
break;
|
|
case 5:
|
|
print("THURSDAY.\n");
|
|
break;
|
|
case 6:
|
|
if (dobDayOfMonth === 13) {
|
|
print("FRIDAY THE THIRTEENTH---BEWARE!\n");
|
|
} else {
|
|
print("FRIDAY.\n");
|
|
}
|
|
break;
|
|
case 7:
|
|
print("SATURDAY.\n");
|
|
break;
|
|
}
|
|
if (normalisedToday !== normalisedDob) {
|
|
let yearsBetweenDates = todayYear - dobYear;
|
|
print("\n");
|
|
let monthsBetweenDates = todayMonth - dobMonth;
|
|
let daysBetweenDates = todayDayOfMonth - dobDayOfMonth;
|
|
if (daysBetweenDates < 0) {
|
|
monthsBetweenDates--;
|
|
daysBetweenDates += 30;
|
|
}
|
|
if (monthsBetweenDates < 0) {
|
|
yearsBetweenDates--;
|
|
monthsBetweenDates += 12;
|
|
}
|
|
if (yearsBetweenDates >= 0) {
|
|
if (daysBetweenDates === 0 && monthsBetweenDates === 0) {
|
|
print("***HAPPY BIRTHDAY***\n");
|
|
}
|
|
print(" \tYEARS\tMONTHS\tDAYS\n");
|
|
print(" \t-----\t------\t----\n");
|
|
print("YOUR AGE (IF BIRTHDATE) \t" + yearsBetweenDates + "\t" + monthsBetweenDates + "\t" + daysBetweenDates + "\n");
|
|
const approximateDaysBetween = (yearsBetweenDates * 365) + (monthsBetweenDates * 30) + daysBetweenDates + Math.floor(monthsBetweenDates / 2);
|
|
// Create an object containing time unaccounted for
|
|
const unaccountedTime = {years: yearsBetweenDates, months: monthsBetweenDates, days: daysBetweenDates};
|
|
|
|
// Calculate time spent in the following functions.
|
|
print("YOU HAVE SLEPT \t\t\t");
|
|
const sleepTimeSpent = time_spent(0.35, approximateDaysBetween);
|
|
printTimeSpent(sleepTimeSpent);
|
|
|
|
adjustUnaccountedTime(unaccountedTime, sleepTimeSpent);
|
|
print("YOU HAVE EATEN \t\t\t");
|
|
const eatenTimeSpent = time_spent(0.17, approximateDaysBetween);
|
|
printTimeSpent(eatenTimeSpent);
|
|
|
|
adjustUnaccountedTime(unaccountedTime, eatenTimeSpent);
|
|
if (unaccountedTime.years <= 3) {
|
|
print("YOU HAVE PLAYED \t\t\t");
|
|
} else if (unaccountedTime.years <= 9) {
|
|
print("YOU HAVE PLAYED/STUDIED \t\t");
|
|
} else {
|
|
print("YOU HAVE WORKED/PLAYED \t\t");
|
|
}
|
|
const workPlayTimeSpent = time_spent(0.23, approximateDaysBetween);
|
|
printTimeSpent(workPlayTimeSpent);
|
|
|
|
adjustUnaccountedTime(unaccountedTime, workPlayTimeSpent);
|
|
if (unaccountedTime.months === 12) {
|
|
unaccountedTime.years++;
|
|
unaccountedTime.months = 0;
|
|
}
|
|
print("YOU HAVE RELAXED \t\t");
|
|
printTimeSpent(unaccountedTime)
|
|
|
|
const retirementYear = dobYear + 65;
|
|
print("\n");
|
|
print(tab(16) + "*** YOU MAY RETIRE IN " + retirementYear + " ***\n");
|
|
print("\n");
|
|
}
|
|
}
|
|
}
|
|
print("\n");
|
|
print("\n");
|
|
print("\n");
|
|
print("\n");
|
|
print("\n");
|
|
}
|
|
|
|
main();
|