1 Commits

Author SHA1 Message Date
63de472207 Solution for assignment4. 2022-12-05 01:00:05 +01:00
4 changed files with 66 additions and 156 deletions

View File

@@ -1,12 +1,9 @@
# Advent of Code 2022 - assignment2 javascript
# Advent of Code 2022 - Assignment 4 - javascript
## Description
Assignment2 involves a game of rock paper scissors. The solution uses an enum for rock, paper, scissor values it defines two functions for selecting a winning and losing hand. The winning and losing hand take advantage of the fact that each next value in the rock, paper, scissor trio beats the previous (looping back to rock). For losing it is the other way around. The winning_hand function is also used to determine the score for player. In the GUI there is a checkbox for selecting solution options (part1,part2).
The problem for assignment4 deals with overlaps and string parsing. The provided solution for this argument uses substring to parse ranges from file. Furthermore it has a checkbox to trigger whether ranges should fully overlap.
## References
- https://www.psychologytoday.com/us/blog/the-blame-game/201504/the-surprising-psychology-rock-paper-scissors#:~:text=There%20are%20four%20possible%20outcomes,Douglas%20Walker%20and%20Graham%20Walker.
- https://www.sohamkamani.com/javascript/enums/
- https://codingbeautydev.com/blog/javascript-remove-all-whitespace-from-string/#:~:text=To%20remove%20all%20whitespace%20from%20a%20string%20in%20JavaScript%2C%20call,all%20whitespace%20removed%20from%20str%20.
- https://www.geeksforgeeks.org/how-to-check-a-key-exists-in-javascript-object/#:~:text=There%20are%20mainly%20two%20methods,property%20is%20in%20the%20object.
- https://stackoverflow.com/questions/5765398/whats-the-best-way-to-convert-a-number-to-a-string-in-javascript
- https://www.w3schools.com/jsref/jsref_switch.asp
- https://www.w3schools.com/tags/att_input_type_checkbox.asp
- https://www.w3schools.com/jsref/jsref_indexof.asp
- https://www.geeksforgeeks.org/convert-a-string-to-an-integer-in-javascript/#:~:text=In%20JavaScript%20parseInt()%20function,argument%20of%20parseInt()%20function.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring
- https://medium.com/@raihan_tazdid/overlapping-numbers-in-ranges-5d0f2efc294e

View File

@@ -9,7 +9,8 @@
<p>Assignment:</p>
<textarea rows="15" cols="50" id="assignment"></textarea>
<input type="checkbox" id="algorithm"/>
<label for="algorithm">Interpret X,Y,Z as Rock Paper Scissor.</label>
<label for="algorithm">Full overlap</label>
<p>Answer:</p>
<div id="answer">Provide input first</div>
<script src="script.js"></script>

203
script.js
View File

@@ -1,55 +1,10 @@
const ASSIGNMENT = 'assignment';
const ANSWER = 'answer';
const ALGORITHM_CHECKBOX = 'algorithm';
const ERROR_MESSAGE_NO_SUCH_CHARACTER_IN_RPS = "Non existant character in rock paper scissor game selected: ";
const ERROR_MESSAGE_TOO_FEW_CHARACTERS_IN_LINE = "Too few characters in line: ";
const ERROR_MESSAGE_INVALID_RANGE = "Invalid range, ";
const COMMA_CHARACTER = ',';
const NEWLINE_CHARACTER = '\n';
const OPTION_LOSE = 'X';
const OPTION_TIE = 'Y';
const OPTION_WIN = 'Z';
const RPS = Object.freeze({
ROCK: 1,
PAPER: 2,
SCISSORS: 3,
/**
* Select winning hand for given hand.
* @param hand the chosen hand
* @return RPS the winning hand
*/
winning_hand: function(hand) {
hand++;
if(hand > RPS.SCISSORS) {
hand = RPS.ROCK;
}
return hand;
},
/**
* Select losing hand for given hand.
* @param hand the chosen hand
* @return RPS the losing hand
*/
losing_hand: function(hand) {
hand--;
if(hand < RPS.ROCK) {
hand = RPS.SCISSORS;
}
return hand;
}
});
const RPS_ALIAS_MAP = Object.freeze({
"A": RPS.ROCK,
"B": RPS.PAPER,
"C": RPS.SCISSORS,
"X": RPS.ROCK,
"Y": RPS.PAPER,
"Z": RPS.SCISSORS,
})
const SCORE_LOSE = 0;
const SCORE_TIE = 3;
const SCORE_WIN = 6;
const RANGE_CHARACTER = '-';
/**
* Main function
@@ -66,8 +21,8 @@ window.onload = function() {
function calculateAnswer(event) {
console.info("Calculating answer for input...");
let assignment = document.getElementById(ASSIGNMENT).value;
let interpret_as_rps = document.getElementById(ALGORITHM_CHECKBOX).checked;
let answer = algorithm(assignment, interpret_as_rps);
let fullOverlap = document.getElementById(ALGORITHM_CHECKBOX).checked;
let answer = algorithm(assignment, fullOverlap);
document.getElementById(ANSWER).innerText = answer;
}
@@ -75,117 +30,73 @@ function calculateAnswer(event) {
/**
* Calculate the answer to assignment.
* @param assignment the input from the assignment.
* @param fullOverlap if input needs to fully overlap.
* @return string the answer
*/
function algorithm(assignment, interpret_as_rps) {
let errors = 0;
function algorithm(assignment, fullOverlap) {
let lines = assignment.trim().split(NEWLINE_CHARACTER);
let score = 0;
console.info("Linecount:" + lines.length);
let containedPairs = 0;
for(let i=0; i<lines.length; i++) {
let rps_match = lines[i].replace(/\s/g, ''); // remove all whitespace
if(rps_match.length < 2) {
console.error(ERROR_MESSAGE_TOO_FEW_CHARACTERS_IN_LINE + i + ", skipped.");
errors++;
let error = false;
let ranges = lines[i].trim();
// Search for separation charactes -,-
let range1CharacterIndex = ranges.indexOf(RANGE_CHARACTER);
let range1EndCharacterIndex = ranges.indexOf(COMMA_CHARACTER);
let range2CharacterIndex = ranges.indexOf(RANGE_CHARACTER, range1CharacterIndex+1);
// Get range substrings
let range1LowerString = ranges.substring(0,range1CharacterIndex);
let range1HigherString = ranges.substring(range1CharacterIndex+1, range1EndCharacterIndex);
let range2LowerString = ranges.substring(range1EndCharacterIndex+1, range2CharacterIndex);
let range2HigherString = ranges.substring(range2CharacterIndex+1);
console.debug("Parsed values: " + range1LowerString + "-" + range1HigherString + "," + range2LowerString + "-" + range2HigherString);
// Parse to int
let range1Lower = parseInt(range1LowerString);
let range1Higher = parseInt(range1HigherString);
let range2Lower = parseInt(range2LowerString);
let range2Higher = parseInt(range2HigherString);
// Validation
if(range1Lower > range1Higher) {
console.error(ERROR_MESSAGE_INVALID_RANGE + range1Lower + "-" + range1Higher + " on line:" + i + " for range1");
error = true;
}
if(range2Lower > range2Higher) {
console.error(ERROR_MESSAGE_INVALID_RANGE + range2Lower + "-" + range2Higher + " on line:" + i + " for range2");
error = true;
}
if(error) {
continue;
}
// Assign characters from line
let opponent_hand = map_hand_character(rps_match[0]);
let player_input = rps_match[1];
let player_hand = -1;
// Validate hand
if(opponent_hand<0) {
console.error(ERROR_MESSAGE_NO_SUCH_CHARACTER_IN_RPS + rps_match[0] + " for line: " + i);
errors++;
continue;
// Check for overlap
if(fullOverlap && doesRangeFullyOverlap(range1Lower, range1Higher, range2Lower, range2Higher)
|| !fullOverlap && doesRangeOverlap(range1Lower, range1Higher, range2Lower, range2Higher)) {
console.debug("Found overlapping range:" + range1Lower + "-" + range1Higher + "," + range2Lower + "-" + range2Higher);
containedPairs++;
}
// How should we interpret input? match_option or Rock Paper Scissors.
if(interpret_as_rps) {
player_hand = interpret_player_hand_as_rps_input(player_input);
} else {
player_hand = interpret_player_hand_as_match_input(player_input, opponent_hand);
}
if(player_hand<0) { // Invalid input
console.error(ERROR_MESSAGE_NO_SUCH_CHARACTER_IN_RPS + rps_match[1] + " for line: " + i);
errors++;
continue;
}
score += rps_result(player_hand, opponent_hand);
}
if(errors > 0) {
return errors.toString() + " Error(s) in input, see console for details."
}
return "Player score: " + score;
return "Fully overlapping timeslot counts: " + containedPairs;
}
/**
* Interpret given input for player as a rock paper scissor character.
* @param char input the input for hand character (A,B,C,X,Y,Z)
* @return the player hand character or -1 if invalid.
*/
function interpret_player_hand_as_rps_input(input) {
return map_hand_character(input);
function doesRangeFullyOverlap(lower, higher, lower2, higher2) {
console.debug("Compare range: " + lower + "-" + higher + " with " + lower2 + "-" + higher2);
if(lower > higher || lower2 > higher2) {
return false;
}
return ((lower <= lower2 && higher >= higher2) || (lower2 <= lower && higher2 >= higher));
}
/**
* Interpret given input for player as a match option.
* @param char input the input for match option (X,Y,Z)
* @return the player hand character or -1 if invalid.
*/
function interpret_player_hand_as_match_input(input, opponent_hand) {
let player_hand = -1;
switch (input) {
case OPTION_LOSE:
player_hand = RPS.losing_hand(opponent_hand);
break;
case OPTION_WIN:
player_hand = RPS.winning_hand(opponent_hand);
break;
case OPTION_TIE:
player_hand = opponent_hand;
break;
}
function doesRangeOverlap(lower, higher, lower2, higher2) {
console.debug("Compare range: " + lower + "-" + higher + " with " + lower2 + "-" + higher2);
if(lower > higher || lower2 > higher2) {
return false;
}
return player_hand;
}
/**
* Maps the chosen hand character to
* @param hand_character the chosen character
* @return RPS the rock paper scissor hand or -1 if invalid
*/
function map_hand_character(hand_character) {
if(!(hand_character in RPS_ALIAS_MAP)) {
return -1;
}
return RPS_ALIAS_MAP[hand_character];
}
/**
* Calculate the result of rock paper scissor match
* @param RPS player_hand the player's choice
* @param RPS opponent_hand the opponent's choice
* @return score
*/
function rps_result(player_hand, opponent_hand) {
let score = 0;
if(player_hand == opponent_hand) {
score = SCORE_TIE + player_hand; // TIE
} else if(player_hand == RPS.winning_hand(opponent_hand)) {
score = SCORE_WIN + player_hand; // WIN
} else {
score = SCORE_LOSE + player_hand; // LOSE
}
console.debug("score:" + score + ", player: " + player_hand + ", opponent: " + opponent_hand);
return score;
return higher2 >= lower && lower2 <= higher;
}

View File

@@ -9,6 +9,7 @@ body {
textarea {
display: block;
}
#answer {
color: purple
}