JS is so meh to write in, why learn it here. Instead, learn DRUL, the assembler made for solving Rudy The Red Dot:
code = compile(".:dddddrruuuul@.");
var colors = [];
var acc = 0;
function run(instructions) {
var pc = 0;
while (pc < instructions.length) {
var line = instructions[pc];
var op = line[0];
var args = line[1];
switch (op) {
case "a": // set accumulator (set to remainingDots() if no arg)
a(args[0]);
break;
case "+": // add to accumulator (+1 if no arg)
add(args[0]);
break;
case "-": // subtract from accumulator (-1 if no arg)
sub(args[0]);
break;
case "u": // up n squares (1 if no arg)
u(args[0]);
break;
case "d": // down n squares (1 if no arg)
d(args[0]);
break;
case "l": // left n squares (1 if no arg)
l(args[0]);
break;
case "r": // right n squares (1 if no arg)
r(args[0]);
break;
case "g": // get current square color: color index n, unshift if -1, or push if no arg
g(args[0]);
break;
case "s": // set current square color: color index n, pop if -1, or shift if no arg
s(args[0]);
break;
case "=": // if current square color is literal (b / r / g / y / w) or color index n then jump to label
if (eq(args[0])) {
pc = args[1];
continue;
}
break;
case "!": // if current square color is not literal (b / r / g / y / w) or color index n then jump to label
if (!eq(args[0])) {
pc = args[1];
continue;
}
break;
case "@": // jump to label
pc = args[0];
continue;
case "0": // if accumulator is 0 then jump to label
if (acc == 0) {
pc = args[0]
continue;
}
break;
case "~": // if accumulator is not 0 then jump to label
if (acc != 0) {
pc = args[0]
continue;
}
break;
}
pc++;
}
}
run(code);
function compile(code) {
var instructions = [];
var waiting_for_op = true;
var max_args = 0;
var skip_if_non_number = false;
var op = "";
var label = "";
code += " ";
var i = 0;
var line = [];
var args = [];
while (i < code.length) {
var c = code[i];
if (!waiting_for_op && skip_if_non_number && c != "-" && isNaN(parseInt(c))) {
line.push(args);
instructions.push(line);
line = [];
waiting_for_op = true;
}
if (waiting_for_op) {
if (c == " ") {
i++
continue;
}
if (code[i+1] == ":") {
label = c;
i += 2;
op = code[i];
}
else {
label = "";
op = c;
}
waiting_for_op = false;
line = [label, op];
args = [];
skip_if_non_number = (op == "u" || op == "d" || op == "l" || op == "r");
if (op == "=" || op == "!")
max_args = 2;
else
max_args = 1;
}
else {
if (c == " ") {
line.push(args);
instructions.push(line);
line = [];
waiting_for_op = true;
}
else {
var negate = false;
if (c == "-") {
negate = true;
i += 1;
c = code[i];
}
var num = parseInt(c);
if (isNaN(num)) {
if (c == "b")
args.push("blue");
else if (c == "r")
args.push("red");
else if (c == "y")
args.push("yellow");
else if (c == "g")
args.push("green");
else if (c == "w")
args.push("white");
else
args.push(c);
}
else {
c = "";
while (!isNaN(num)) {
c += code[i];
i++;
num = parseInt(code[i]);
}
num = parseInt(c);
if (negate) num = -num;
i--;
args.push(num);
}
if (max_args > 0 && args.length >= max_args) {
line.push(args);
instructions.push(line);
line = [];
waiting_for_op = true;
}
}
}
i++;
}
for (i = 0; i < instructions.length; i++) {
line = instructions[i];
op = line[1];
if (op == "=" || op == "!")
instructions[i][2][1] = get_label(instructions, instructions[i][2][1]);
else if (op == "@" || op == "0" || op == "~")
instructions[i][2][0] = get_label(instructions, instructions[i][2][0]);
}
for (i = 0; i < instructions.length; i++)
instructions[i].shift();
return instructions;
}
function get_label(lines, label) {
for (var i = 0; i < lines.length; i++) {
if (lines[i][0] == label)
return i;
}
return -1;
}
function repeat(fn, n) {
if (n == undefined)
fn();
else
for (var i = 0; i < n; i++)
fn();
}
function eq(color) {
if (typeof(color) == "number")
color = colors[color];
if (color == "white")
color = false;
return color == getColor();
}
function g(c) {
color = getColor();
if (!color)
color = "white";
if (c == undefined)
colors.push(getColor());
else if (c == -1)
colors.unshift(getColor());
else
colors[c] = getColor();
}
function s(c) {
if (c == undefined)
color = colors.shift();
else if (c == -1)
color = colors.pop();
else
color = colors[c];
if (color == "white")
color = false;
setColor(color);
}
function u(n) {
repeat(up, n);
}
function d(n) {
repeat(down, n);
}
function r(n) {
repeat(right, n);
}
function l(n) {
repeat(left, n);
}
function a(n) {
if (n == undefined)
acc = remainingDots();
else
acc = n;
}
function add(n) {
if (n == undefined)
acc++;
else
acc += n;
}
function sub(n) {
if (n == undefined)
acc--;
else
acc -= n;
}
// level 1 d7r5u2r2
// level 2 d6r3u2r2d3
// level 3 d2 g d3r2 s r2u
// level 4 d4r1g ds r2urg ds r2
// level 5 .:r2 =bB =rR r B:d @. R:u @.
// level 6 r =bB u4 =b> lu >:ru B:d4 =b< rd <:ld
// level 7 .:=r> d @. >:r2 u9 @.
// level 8 d8 r2 u7 r2 d7 r2 u7 r2 d7 r1
// level 9 .:r100 d100 @.
// level 10 a8 .:d g - ~. dr a8 #:s ru - ~# u
// level 11 .:=gG=yY=bB=rR G:r=wG@. Y:d=wY@. B:u=wB@. R:l=wR@.
The suggestion that self-sacrifice is ever a moral requirement is a pretty controversial statement. Self-sacrifice for a moral reason is almost always seen as laudable, but necessary?
I feel like the weighting of your statement is off (wrt being controversial); not sacrificing yourself is the norm, and not immoral, while taking the option to sacrifice yourself is noble. As opposed to "Yeah, that guy ran back into the building to try to save the last kid from the fire. It's a shame he died, but he was just doing what was morally required so doesn't deserve any adulation".