/** * Global */ var ktane = ktane || {}; $('h2').on('dblclick', function () { $(this).closest('section').toggleClass('collapsed'); }).attr('title', 'Double-click to expand/collapse'); ktane.resetInputs = function ($container) { $container.find('textarea').val(''); $container.find('.selected').removeClass('selected'); return $container.find('input').each(function () { if (this.type === 'text') { $(this).val('').trigger('keyup'); } else if (this.type === 'checkbox') { this.checked = false; } else if (this.type === 'radio' && !this.value) { this.checked = true; } }); } ktane.resetInputs($('body')); $('.jsResetSection').on('click', function () { ktane.resetInputs($(this).closest('section')).filter('[type="text"]').first().focus(); }); (function () { /** * Wires */ var count = { red: 0, yellow: 0, blue: 0, white: 0, black: 0 }, $wireList = $('#wireList'); $('#wireOptions button').on('click', function () { var colour = this.getAttribute('data-colour'), letter = this.getAttribute('data-letter'), $li = $('
'); $wireList.append($li); count[colour]++; checkWireToCut(); }); $wireList.on('click', 'button', function () { var deleteIndex = $(this).parent().index(); $wireList.children('li:eq(' + deleteIndex + '), li:gt(' + deleteIndex + ')').each(function () { var button = this.firstChild; count[button.getAttribute('data-colour')]--; $(this).remove(); }); checkWireToCut(); }); function checkWireToCut() { var lastColour = $wireList.children(':last-child').children().first().data('colour'), oddPossible; $wireList.find('.wireToCut').removeClass('wireToCut odd even'); switch ($wireList.children().length) { case 3: oddPossible = false; if (!count['red']) { addWireToCut(2); } else if (lastColour === 'white') { addWireToCut(); } else if (count['blue'] > 1) { $wireList.find('[data-colour="blue"]').last().parent().addClass('wireToCut'); } else { addWireToCut(); } break; case 4: oddPossible = count['red'] > 1; if (oddPossible) { $wireList.find('[data-colour="red"]').parent().last().addClass('wireToCut odd'); } if (lastColour === 'yellow' && !count['red'] || count['blue'] === 1) { addWireToCut(1); } else if (count['yellow'] > 1) { addWireToCut(); } else { addWireToCut(2); } break; case 5: oddPossible = lastColour === 'black'; if (oddPossible) { addWireToCut(4, 'odd'); } if (count['red'] === 1 && count['yellow'] > 1) { addWireToCut(1); } else if (!count['black']) { addWireToCut(2); } else { addWireToCut(1); } break; case 6: oddPossible = !count['yellow']; if (oddPossible) { addWireToCut(3, 'odd'); } if (count['yellow'] === 1 && count['white'] > 1) { addWireToCut(4); } else if (!count['red']) { addWireToCut(); } else { addWireToCut(4); } break; default: break; } function addWireToCut(child, className) { if (typeof className === 'undefined') { className = 'even'; } $wireList.children(isNaN(child) ? ':last-child' : ':nth-child(' + child + ')') .addClass('wireToCut' + (className !== 'even' || oddPossible ? ' ' + className : '')); } } })(); (function () { /** * Button */ var $section = $('#sectionButton'), $instruction = $('#buttonInstruction'), instruction; $section.find('input').on('click', function () { var colour = $('input[name="buttonColour"]:checked').val(), text = $('input[name="buttonText"]:checked').val(); if (text === 'Detonate') { instruction = 'If there is more than 1 battery, press and release; otherwise, hold the button.' } else if (colour === 'white') { instruction = 'If there is a lit indicator with label CAR, hold the button. Otherwise, if there are more than 2 batteries and a lit indicator with label FRK, press and release the button. If neither apply, hold the button.' } else if (colour === 'blue' && text === 'Abort' || colour === 'yellow') { instruction = 'Hold the button.'; } else if (colour === 'red' && text === 'Hold') { instruction = 'Press and release the button.'; } else { instruction = 'If there are more than 2 batteries and a lit indicator with label FRK, press and release the button; otherwise, hold the button.'; } $instruction.html(instruction); }); })(); (function () { /** * Keypads */ var columns = [ ['balloon', 'at', 'upsidedowny', 'squigglyn', 'squidknife', 'hookn', 'leftc'], ['euro', 'balloon', 'leftc', 'cursive', 'hollowstar', 'hookn', 'questionmark'], ['copyright', 'pumpkin', 'cursive', 'doublek', 'meltedthree', 'upsidedowny', 'hollowstar'], ['six', 'paragraph', 'bt', 'squidknife', 'doublek', 'questionmark', 'smileyface'], ['pitchfork', 'smileyface', 'bt', 'rightc', 'paragraph', 'dragon', 'filledstar'], ['six', 'euro', 'tracks', 'ae', 'pitchfork', 'nwithhat', 'omega'] ], $section = $('#sectionKeypads'), $imageLists = {}; // name -> $('
');
$column.append($('').append($img));
name in $imageLists
? $imageLists[name].push($img)
: $imageLists[name] = [$img];
});
});
$section.on('click', 'img', function () {
var $img = $(this),
name = $img.data('name'),
endState = !$img.hasClass('selected'),
offset = endState ? 1 : -1;
$.each($imageLists[name], function (i, $img) {
var $column = $img.parent().parent();
$img.toggleClass('selected', endState);
$column.attr('data-count', parseInt($column.attr('data-count'), 10) + offset);
});
});
$section.find('.jsResetSection').on('click', function () {
// Also need to reset the indices after removing .selected
$section.find('ul').attr('data-count', 0);
});
})();
(function () {
/**
* Simon
*/
var $checkbox = $('#simonVowel'),
$strikeButtons = $('#sectionSimon input[name="simonStrikes"]'),
$arrows = [],
mappings = [ // (hasVowel, strikes) -> list of visible arrows by ID
// No vowel
[
['RB', 'BY', 'YR'],
['GY', 'YG'],
['RY', 'BG', 'GB', 'YR']
],
// Vowel
[
['RB', 'BR', 'GY', 'YG'],
['RY', 'BG', 'GB', 'YR'],
['RG', 'BR', 'GY', 'YB']
]
];
$('#simonBoard').find('.arrow').each(function (i, arrow) {
$arrows[arrow.id.replace(/^.*(?=..$)/, '')] = $(arrow);
});
$('#sectionSimon input').on('change', function () {
var hasVowel = +$checkbox.prop('checked'),
strikes = $strikeButtons.filter(':checked').val();
for (var id in $arrows) {
$arrows[id].removeClass('active');
}
$.each(mappings[hasVowel][strikes], function (i, id) {
$arrows[id].addClass('active');
});
}).first().trigger('change');
})();
(function () {
/**
* Memory
*/
var inputRegex = /^[1-4]$/,
$s = {}, // Cache jQuery objects for speed and convenience
answerData;
for (var i = 1; i <= 5; i++) {
$s[i] = {
d: $('#stage_' + i + '_display'),
p: $('#stage_' + i + '_pos'),
l: $('#stage_' + i + '_label')
};
if (i < 5) {
$s[i].p.add($s[i].l).on('keyup', {j: i + 1}, function (e) {
if (inputRegex.test(this.value)) {
$s[e.data.j].d.focus();
}
});
}
}
$('#sectionMemory input').on('focus', function () {
this.select();
});
answerData = { // {stage -> {display -> [element, value]} }
1: {
1: ['p', 2],
2: ['p', 2],
3: ['p', 3],
4: ['p', 4]
},
2: {
1: ['l', 4],
2: ['p', $s[1].p],
3: ['p', 1],
4: ['p', $s[1].p]
},
3: {
1: ['l', $s[2].l],
2: ['l', $s[1].l],
3: ['p', 3],
4: ['l', 4]
},
4: {
1: ['p', $s[1].p],
2: ['p', 1],
3: ['p', $s[2].p],
4: ['p', $s[2].p]
},
5: {
1: ['l', $s[1].l],
2: ['l', $s[2].l],
3: ['l', $s[4].l],
4: ['l', $s[3].l]
}
};
$('#sectionMemory input[id$="_display"]').on('keyup', function () {
if (!inputRegex.test(this.value)) {
return;
}
var index = parseInt(this.getAttribute('data-index'), 10),
data = answerData[index][this.value],
element = $s[index][data[0]],
value = data[1];
if (typeof value === 'object') {
value = value.val() || value.attr('id').replace(/(\d).+$/, '$1');
}
element.val(value);
$s[index][data[0] === 'p' ? 'l' : 'p'].focus();
});
})();
(function () {
/**
* Morse
*/
var freqs = {
shell: '3.505',
halls: '3.515',
slick: '3.522',
trick: '3.532',
boxes: '3.535',
leaks: '3.542',
strobe: '3.545',
bistro: '3.552',
flick: '3.555',
bombs: '3.565',
'break': '3.572',
brick: '3.575',
steak: '3.582',
sting: '3.592',
vector: '3.595',
beats: '3.600'
},
codes = {
'.-': 'a',
'-...': 'b',
'-.-.': 'c',
'.': 'e',
'..-.': 'f',
'--.': 'g',
'....': 'h',
'..': 'i',
'-.-': 'k',
'.-..': 'l',
'--': 'm',
'-.': 'n',
'---': 'o',
'.-.': 'r',
'...': 's',
'-': 't',
'...-': 'v',
'-..-': 'x'
},
codeRegex = new RegExp(' *(' + Object.keys(codes).join('|').replace(/\./g, '\\.') + ')(?![\.-]) *', 'g'),
$rows = {},
$table = $('#morseTable');
for (var word in freqs) {
var $row = $('