1 Commits

Author SHA1 Message Date
ee5e17f444 Assignment2 algorithm solution. 2022-12-04 20:53:01 +01:00
4 changed files with 160 additions and 101 deletions

View File

@@ -1,8 +1,12 @@
# Advent of Code 2022 - Assignment8 javascript # Advent of Code 2022 - assignment2 javascript
## Description ## Description
This problem is all about walking through a grid. In this solution, we look through an entire column and row until we find a node with height <= height. 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).
## References ## References
- https://www.w3schools.com/jsref/jsref_charat.asp - 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://stackabuse.com/javascript-check-if-variable-is-a-number/ - https://www.sohamkamani.com/javascript/enums/
- https://www.w3schools.com/jsref/jsref_abs.asp - 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

View File

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

201
script.js
View File

@@ -1,7 +1,55 @@
const ASSIGNMENT = 'assignment'; const ASSIGNMENT = 'assignment';
const ANSWER = 'answer'; const ANSWER = 'answer';
const ALGORITHM_CHECKBOX = 'algorithm'; 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 NEWLINE_CHARACTER = '\n'; 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;
/** /**
* Main function * Main function
@@ -18,8 +66,8 @@ window.onload = function () {
function calculateAnswer(event) { function calculateAnswer(event) {
console.info("Calculating answer for input..."); console.info("Calculating answer for input...");
let assignment = document.getElementById(ASSIGNMENT).value; let assignment = document.getElementById(ASSIGNMENT).value;
let getHighestScenicScore = document.getElementById(ALGORITHM_CHECKBOX).checked; let interpret_as_rps = document.getElementById(ALGORITHM_CHECKBOX).checked;
let answer = algorithm(assignment, getHighestScenicScore); let answer = algorithm(assignment, interpret_as_rps);
document.getElementById(ANSWER).innerText = answer; document.getElementById(ANSWER).innerText = answer;
} }
@@ -29,106 +77,115 @@ function calculateAnswer(event) {
* @param assignment the input from the assignment. * @param assignment the input from the assignment.
* @return string the answer * @return string the answer
*/ */
function algorithm(assignment, getHighestScenicScore) { function algorithm(assignment, interpret_as_rps) {
let errors = 0;
let lines = assignment.trim().split(NEWLINE_CHARACTER); let lines = assignment.trim().split(NEWLINE_CHARACTER);
let score = 0;
console.info("Linecount:" + lines.length); console.info("Linecount:" + lines.length);
let visibleTreeCount = 0;
let highestScenicScore = 0;
for(let i=0; i<lines.length; i++) { for(let i=0; i<lines.length; i++) {
let row = lines[i].trim(); let rps_match = lines[i].replace(/\s/g, ''); // remove all whitespace
if(rps_match.length < 2) {
for (let j = 0; j < row.length; j++) { console.error(ERROR_MESSAGE_TOO_FEW_CHARACTERS_IN_LINE + i + ", skipped.");
if (i <= 0 || i >= lines.length - 1 || j <= 0 || j >= row.length - 1) { // Edge node errors++;
//console.debug("Edge node found.");
visibleTreeCount++;
continue; continue;
} }
let height = parseInt(lines[i].charAt(j)); // Assign characters from line
if (!walkRowVisible(height, j, row) && !walkColumnVisible(height, i, j, lines)) { let opponent_hand = map_hand_character(rps_match[0]);
console.log("Found invisible tree, height:" + height + ", i:" + i + ", j:" + j); let player_input = rps_match[1];
visibleTreeCount--; 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;
} }
if (getHighestScenicScore) { // How should we interpret input? match_option or Rock Paper Scissors.
let scenicScore = walkRowCount(height, j, row) * walkColumnCount(height, i, j, lines); if(interpret_as_rps) {
if (scenicScore > highestScenicScore) { player_hand = interpret_player_hand_as_rps_input(player_input);
console.debug("Found new highest scenic score: " + scenicScore); } else {
highestScenicScore = scenicScore; player_hand = interpret_player_hand_as_match_input(player_input, opponent_hand);
}
} }
// Tree is on edge. if(player_hand<0) { // Invalid input
visibleTreeCount++; console.error(ERROR_MESSAGE_NO_SUCH_CHARACTER_IN_RPS + rps_match[1] + " for line: " + i);
} errors++;
continue;
} }
if (getHighestScenicScore) { score += rps_result(player_hand, opponent_hand);
return "Highest scenic score: " + highestScenicScore;
} }
return "Amount of visible trees in the grid: " + visibleTreeCount; if(errors > 0) {
return errors.toString() + " Error(s) in input, see console for details."
} }
function walkColumnCount(height, index, rowIndex, column) { return "Player score: " + score;
return walkCount(height, index, column, false, rowIndex);
} }
function walkRowCount(height, index, row) { /**
return walkCount(height, index, row, true, -1); * 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 walkColumnVisible(height, index, rowIndex, column) { /**
return walkVisible(height, index, column, false, rowIndex); * 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 walkRowVisible(height, index, row) { return player_hand;
return walkVisible(height, index, row, true, -1);
} }
function walkCount(height, index, line, isRow, rowIndex) { /**
let visibleLeftCount = __walkHelper(height, index, line, isRow, -1, rowIndex, 0); * Maps the chosen hand character to
let visibleRightCount = __walkHelper(height, index, line, isRow, 1, rowIndex, 0); * @param hand_character the chosen character
* @return RPS the rock paper scissor hand or -1 if invalid
return visibleLeftCount * visibleRightCount; */
} function map_hand_character(hand_character) {
if(!(hand_character in RPS_ALIAS_MAP)) {
function walkVisible(height, index, line, isRow, rowIndex) {
let visibleLeft = __walkHelper(height, index, line, isRow, -1, rowIndex);
let visibleRight = __walkHelper(height, index, line, isRow, 1, rowIndex);
return visibleLeft || visibleRight;
}
function __walkHelper(height, index, line, isRow, direction, rowIndex, count) {
if (direction == 0) {
console.error("Invalid direction 0 in __walkhelper");
return -1; return -1;
} }
direction = direction / Math.abs(direction); return RPS_ALIAS_MAP[hand_character];
// Edge reached
if ((direction < 0 && index <= 0) || (direction > 0 && index >= line.length - 1)) {
return (count == undefined) ? true : count;
} }
let nextIndex = index + direction; /**
let nextHeightCharacter = (isRow) ? line.charAt(nextIndex) : line[nextIndex].trim().charAt(rowIndex); * Calculate the result of rock paper scissor match
let nextHeight = parseInt(nextHeightCharacter); * @param RPS player_hand the player's choice
* @param RPS opponent_hand the opponent's choice
if (isNaN(height) || isNaN(nextHeightCharacter)) { * @return score
console.error("Invalid height found, height:" + height + ", nextHeight: " + nextHeightCharacter); */
return -1; 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
} }
if (height <= nextHeight) { console.debug("score:" + score + ", player: " + player_hand + ", opponent: " + opponent_hand);
if (count == undefined) return score;
return false;
return count + 1;
}
return __walkHelper(height, nextIndex, line, isRow, direction, rowIndex, (count !=undefined)? count + 1 : undefined);
} }

View File

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