Apps Home
|
Create an App
Battleship by CodeAnon
Author:
codeanon_master
Description
Source Code
Launch App
Current Users
Created by:
Codeanon_Master
cb.settings_choices = [ {name: 'cost', label: 'Cost to fire a missile', type: 'int', minvalue: 5, defaultValue: 10}, {name: 'goals', label: 'Goals after sunken ships', type: 'str', defaultValue: '5: topless'}, {name: 'wt', label: 'Font weight', type: 'choice', choice1: 'normal', choice2: 'bold', defaultValue: 'bold'}, {name: 'fg', label: 'Font color', type: 'str', required: false, defaultValue: '#000099'}, {name: 'subj', label: 'Room subject', type: 'str', required: false, defaultValue: 'Play #battleship to get me topless! Type /b for the board!'}, {name: 'tipType', label: 'Augment the token count...', type: 'choice', choice1: 'whenever somebody tips', choice2: 'only when firing missiles', defaultValue: 'whenever somebody tips'} ]; /********** ------------ SETUP ------------ **********/ var tipCount = 0; var cbs = JSON.parse(JSON.stringify(cb.settings)); var goals = function () { var output = []; if (cbs.goals) { cbs.goals.split(',').forEach(function (item) { var goal = item.split(':'); var num = Number(goal[0]); var val = goal[1]; if (val && num !== NaN) output.push({num: num, val: val.trim()}); }); } output.sort((a,b) => a.num - b.num); return output; }(); // ----- TEXT ----- var sym = (num) => String.fromCharCode(num); var headSep = sym(0xFFDC); var sep = sym(0x2002); var space = sym(12288); var hidden = mono('-'); var miss = mono('o'); var hit = sym(0xFFA7) + sym(0xFF7A); var sunken = sym(0xFF8E).repeat(2); var board; var ships; function reset() { // ----- BOARD ----- var rowIndex = 1; board = [row(),row(),row(),row(),row(),row(),row(),row(),row(),row()]; board.show = function (solution) { var arr = ['\u2007'.repeat(2) + sep + sep + mono('ABCDEFGHIJ').split('').join(headSep) + sep]; for (var i = 0; i < board.length; i++) arr.push((i > 8 ? (i + 1) + '' : '\u2007' + (i + 1)) + board[i].show(solution)); arr.push('\u2007'.repeat(2) + sep + sep + miss + ' = miss, ' + hit + ' = hit, ' + sunken + ' = sunk'); arr.push('Missile cost = ' + cbs.cost + ' (square in tip note!)'); if (goals[0]) arr.push(capFirst(goals[0].val) + ' @ ' + goals[0].num + ' sunken ship' + plural(goals[0].num) + '!'); return arr.join('\n'); }; board.toString = () => board.show(); board.squareNum = function (a, b) { if (board[b] && board[b][a]) return board[b][a]; return void 0; } board.squareText = function (a) { var y = Number(a.slice(1)); var x = 'ABCDEFGHIJ'.indexOf(a.charAt(0).toUpperCase()); if (y > 0 && x > -1) return board[y - 1][x]; }; // ----- SHIPS ----- ships = [ {name: 'CARRIER', size: 5, initSize: 5, sunken: false, squares: []}, {name: 'BATTLESHIP', size: 4, initSize: 4, sunken: false, squares: []}, {name: 'CRUISER', size: 3, initSize: 3, sunken: false, squares: []}, {name: 'SUBMARINE', size: 3, initSize: 3, sunken: false, squares: []}, {name: 'DESTROYER', size: 2, initSize: 2, sunken: false, squares: []} ]; say('Setting up ships. Please wait...', cb.room_slug); ships.forEach(function (ship) { placeRandomDir(getEmptySquare(), ship) /* if (getRandomInt(0, 1)) {placeRandomDir(getEmptySquare(), ship)} else {placeCenterPoint(getEmptySquare(), ship);} */ }); // ----- INIT ----- showOnEnter(); if (cbs.subj) cb.changeRoomSubject(cbs.subj); cb.drawPanel(); // ----- FUNCTIONS ----- function row() { var arr = []; for (var i = 0; i < 10; i++) arr.push(square('ABCDEFGHIJ'.charAt(i) + rowIndex)); arr.toString = () => arr.show(); arr.show = (solution) => headSep + sep + arr.map((obj) => obj.show(solution)).join(sep) + sep + headSep; arr.name = rowIndex; rowIndex++; return arr; } function square(i) { var obj = {ship: null, name: i, occupied: false, guessed: false}; obj.getShip = function () { if (obj.ship) { return ships.find((elm) => elm.name === obj.ship); } }; obj.show = function (solution) { if (solution) return obj.occupied && obj.ship ? mono(obj.ship.initSize) : hidden; if (!obj.guessed) return hidden; if (!obj.occupied) return miss; if (obj.ship.sunken) return sunken; return hit; }; obj.toString = () => obj.show(); return obj; } function rand (num) {return Math.floor(Math.random() * num)}; function getEmptySquare() { var square = void 0; while (!square) { var x = rand(9); var y = rand(9); newSquare = board.squareNum(x, y); if (newSquare && !newSquare.occupied) { square = newSquare; square.x = x; square.y = y; } } cb.log('FOUND SQUARE: (' + x + ',' + y + ')'); return square; } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function placeRandomDir(square, ship) { cb.log('Placing ' + ship.name + ' with directional algorithm.'); var dir = getRandomInt(0, 3); var fits = true; var destArr = [square]; for (var i = 1; i < ship.size && fits; i++) { (function () { var x = square.x; var y = square.y; switch(dir) { case 0: // up y = y - i; break; case 2: // down y = y + i; break; case 1: //left x = x - i; break; case 3: //right x = x + i; break; } var nextSquare = board.squareNum(x, y); if (!nextSquare || nextSquare.occupied) { fits = false; destArr = []; cb.log('Ship doesn\'t fit. Restarting.'); } else { destArr.push(nextSquare); } })(); } if (fits) { destArr.forEach(function (square) { square.occupied = true; square.ship = ship; ship.squares.push(square.name); }); } else { placeRandomDir(getEmptySquare(), ship); } } //function placeCenterPoint(square, ship) { // cb.log('Placing ' + ship.name + ' with centered algorithm.'); // var fits = true; // var destArr = []; // var dir = Math.floor(Math.random() * 2); // var centerNums = centerRange(dir ? square.x : square.y, ship.size); // for (var i = 0; i < centerNums.length && fits; i++) { // (function () { // var nextSquare = dir ? board.squareNum(centerNums[i], square.y) : board.squareNum(square.x, centerNums[i]); // if (!nextSquare || nextSquare.occupied) { // fits = false; // destArr = []; // cb.log('Ship doesn\'t fit. Restarting.'); // } else { // destArr.push(nextSquare); // } // })(); // } // fits ? destArr.forEach((square) => square.occupied = true, square.ship = ship.name) : placeCenterPoint(getEmptySquare(), ship); //} function centerRange (num, range) { var arr = [num]; for (var i = 1; i < range; i++) arr.push(num + i); return arr.map((n) => n - Math.floor(range/2)); } } /********** ------------ TIPS ------------ **********/ cb.onTip((tip) => doTip(tip)); function doTip(tip) { if (cbs.tipType === 'whenever somebody tips') tipCount += tip.amount; if (tip.amount === cbs.cost && tip.message) { if (cbs.tipType === 'only when firing missiles') tipCount += tip.amount; fireMissile(tip.from_user, tip.message); } } function fireMissile (user, message) { var square = board.squareText(message.toUpperCase().replace(/\W+/g, '')); if (square) { if (square.guessed) { say('Somebody already fired at ' + square.name + '!'); } else { square.guessed = true; if (square.occupied) { say(user + ' fired at ' + square.name + ' and hit the enemy!'); square.ship.size--; if (!square.ship.size && !square.ship.sunken) { square.ship.sunken = true; say(user + ' sunk the enemy\'s ' + square.ship.name + '!'); checkGoal(); } } else { say(user + ' fired at ' + square.name + showSnark()); } } say(board.show()); } } function numSunkenShips () { var n = 0; ships.forEach((ship) => ship.sunken ? n++ : void 0); return n; } function checkGoal () { if (goals[0] && numSunkenShips() >= goals[0].num) { say (':starx\nGOAL REACHED: ' + goals[0].val + '\n:starx'); goals.shift(); } cb.drawPanel(); } var snark = [' and killed a bunch of fish.', ', missing the enemy because he was distracted by a monkey.', '. He then stood there, embarrassed, because he hit nothing.', ' narrowly avoided awakening Cthulu.', '. Maybe he forgot to load the shell.']; function showSnark() { // snark.push(snark.shift()); // return snark[0]; return ' and missed.'; } /********** ------------ COMMANDS ------------ **********/ function cmd(params, user) { var command = params.slice(1).split(/\s+/); switch(command[0].toLowerCase()) { case 'bs#': evaluate(command.slice(1).join(' '), user); break; case 's': say(board.show(true), user); break; case 'i': var square = board.squareText(command[1]); if (square) say('--- Square ' + square.name + ' ---\n' + JSON.stringify(square, null, '\u2007\u2007\u2007\u2007'), user); break; case 'm': if (command[1]) fireMissile(user, command.slice(1).join(' ')); break; case 'h': showHelp(user); break; case 'addgoal': if (command[1] && command[2]) { var num = Number(command[1]); var val = command.slice(2).join(' ').trim(); if (num !== NaN && num > numSunkenShips() && val.length > 0) { var ind = goals.findIndex((elm) => elm.num === num); if (ind > -1) { goals[ind].val = capFirst(val); } else { goals.push({num: num, val: capFirst(val)}); goals.sort((a,b) => a.num - b.num); } say('Goals modified.', user); } } break; case 'remgoal': if (command[1]) { var num = Number(command[1]); if (num !== NaN) { var ind = goals.findIndex((elm) => elm.num === num); if (ind > -1) { goals.splice(ind, 1); say('Goals modified.', user); } } } break; case 'reset': reset(); break; } cb.drawPanel(); } function showHelp(user) { var text = [' :cdn_bslogo', '*********************', '/h or /help -- show this menu again', '/s -- show me the ship placement', '/m [square] -- fire a missile at a square', '/i [square] -- show me information about a square', '/reset -- starts a new game', '/addGoal [number] [text] -- adds/overwrites a goal at the specified number of sunken ships', '/remGoal [number] -- removes a goal at the specified number of sunken ships', '/bs# [script] -- execute JavaScript', '*********************', 'Questions? Problems? Email codeanon@protonmail.com!' ].join('\n'); say(text, user); } function evaluate(str, user) { try { var result = eval(str); var notice = 'INPUT: ' + str + '\nTYPE: ' + typeof result + '\nVALUE: '; result === void 0 ? notice += 'undefined' : notice += JSON.stringify(result, null, '\u2007\u2007\u2007\u2007'); cb.setTimeout(() => {cb.sendNotice(newLines(notice), user, '', '#00CC00', '', '')}, 100); } catch (e) { cb.setTimeout(() => {cb.sendNotice(newLines(e.name + ': ' + e.message), user, '', '#FF0000', '', '')}, 100); } } /********** ------------ COMMUNICATION ------------ **********/ var commanders = cbs.admins ? cbs.admins.trim().split(/\s*,\s*/) : []; commanders.push(cb.room_slug); cb.onMessage(function (msg) { if (msg.m.charAt(0) === '/') { msg['X-Spam'] = true; if (commanders.includes(msg.user)) cmd(msg.m, msg.user); if (msg.m === '/b') { say(board + '', msg.user) } } return msg; }); cb.onDrawPanel(function () { return { 'template': '3_rows_of_labels', 'row1_label': 'BATTLESHIP', 'row1_value': tipCount + ' tks recieved', 'row2_label': 'SHIPS REMAINING', 'row2_value': shipsLeft(), 'row3_label': goals[0] ? 'GOAL: ' + capFirst(goals[0].val) : '---', 'row3_value': goals[0] ? 'Sink ' + leftToGoal() + ' more for goal!': '---' }; }); function leftToGoal() { if (goals[0]) return goals[0].num - numSunkenShips(); } function shipsLeft() { var arr = []; ships.forEach((ship) => ship.sunken ? void 0 : arr.push(ship.initSize)); return '[' + arr.toString() + ']'; } function newLines(input) { return '\u00A0\u00A0\u00A0 ' + input.replace(/\n/g, '\n\u00A0\u00A0\u00A0 '); } function say(msg, user, color) { cb.sendNotice(newLines(msg), user, '', color || cbs.fg , cbs.wt, ''); } function capFirst(txt) { return txt.charAt(0).toUpperCase() + txt.slice(1); } function mono(text) { var output = ''; text = text + ''; for (var i = 0; i < text.length; i++) { if (text.charCodeAt(i) >= 33 && text.charCodeAt(i) <= 270) { output += String.fromCharCode(text.charCodeAt(i) + 65248); } else if (text.charCodeAt(i) == 32) { output += String.fromCharCode(12288); } } return output; } function plural (num) { return num === 1 ? '' : 's'; } cb.onEnter(function(user) { showOnEnter(user.user); }); function showOnEnter(user) { if (board) say('\u2007'.repeat(2) + sep + sep + sep + sep + ' :cdn_bslogo\n' + board.show(), user); } /********** ------------ INIT ------------ **********/ reset();
© Copyright Chaturbate 2011- 2025. All Rights Reserved.