Skip to content

Instantly share code, notes, and snippets.

@Zirak
Created December 24, 2011 22:47
Show Gist options
  • Select an option

  • Save Zirak/1518493 to your computer and use it in GitHub Desktop.

Select an option

Save Zirak/1518493 to your computer and use it in GitHub Desktop.
SO chat hangman bot
var bot = {
name : 'Zirak',
commandRegex : /^\/([\w\-\_]+)\s*(.+)?$/,
commands : {}, //will be filled as needed
codifyOutput : false,
//common elements
elems : {
input : document.getElementById( 'input' ),
codify : document.getElementById( 'codify-button' ),
send : document.getElementById( 'sayit-button' )
},
stopped : false,
parseMessage : function ( msgObj ) {
console.log( msgObj, 'parseMessage input' );
if ( !this.validateMessage(msgObj) ) {
console.log( msgObj, 'parseMessage invalid' );
return;
}
var msg = msgObj.content.trim(),
usr = msgObj.user_name;
msg = msg.slice( this.name.length + 1 ).trim();
console.log( msg, 'parseMessage valid' );
try {
//it's a command
if ( msg.startsWith('/') ) {
console.log( msg, 'parseMessage command' );
this.parseCommand( msg, usr );
return;
}
console.log( msg, 'parseMessage guess' );
//if it's valid and not a comment, then assume it's a game thing
game.receiveMessage( msg, usr );
}
catch ( e ) {
var err = 'Could not process input. Error: ';
err += e.message;
if ( e.lineNumber ) {
err += ' on line ' + e.lineNumber;
}
this.reply( err, usr );
throw e;
}
},
parseCommand : function ( cmd, usr ) {
console.log( cmd, 'parseCommand input' );
var commandParts = cmd.match( this.commandRegex ),
commandName = commandParts[ 1 ].toLowerCase(),
commandArgs = commandParts[ 2 ];
console.log( commandParts, 'parseCommand matched' );
if ( !this.commands.hasOwnProperty(commandName) ) {
this.reply( 'Invalid command ' + commandName, usr );
return;
}
this.commands[ commandName ]( commandArgs, usr );
},
validateMessage : function ( msgObj ) {
if ( this.stopped ) {
return false;
}
var msg = msgObj.content.toLowerCase().trim();
//all we really care about
if ( !msg.startsWith( '!' + this.name.toLowerCase()) ) {
return false;
}
return true;
},
reply : function ( msg, usr ) {
this.output( '@' + usr + ' ' + msg );
},
output : function ( msg ) {
IO.out.receive( msg );
},
//prepare msg to be sent
addOutput : function ( msg ) {
this.elems.input.value += msg + '\n';
},
//actually send the output
sendOutput : function () {
//document.getElementById( 'output' ).textContent += this.elems.input.value;
//return;
if ( this.codifyOutput ) {
this.elems.codify.click();
this.codifyOutput = false;
}
this.elems.send.click();
this.elems.input.value = '';
},
//some sugar
addCommand : function ( cmdName, cmd ) {
this.commands[ cmdName ] = cmd;
},
stop : function () {
this.stopped = true;
}
};
IO.register( 'receiveinput', bot.validateMessage, bot );
IO.register( 'input', bot.parseMessage, bot );
IO.register( 'output', bot.addOutput, bot );
IO.register( 'afteroutput', bot.sendOutput, bot );
var commands = {
die : function ( args, usr ) {
bot.reply( 'I\'m dead!', usr );
bot.stopped = true;
},
learn : function ( args, usr ) {
console.log( args, 'learn input' );
Object.keys( htmlEntities ).forEach(function ( entity ) {
var regex = new RegExp( entity, 'g' );
args = args.replace( regex, htmlEntities[entity] );
});
console.log( args, 'learn filtered' );
var command;
try {
command = JSON.parse( args );
}
catch ( e ) {
bot.reply( e.message, usr );
throw e;
}
if ( !command.name || !command.input || !command.output ) {
bot.reply( 'Illegal /learn object ' + args, usr );
return;
}
if ( commands[command.name] ) {
bot.reply( 'Command ' + command.name + 'already exists', usr );
}
//a shitty way to do it, I know
if ( !(command.input instanceof Object) ) {
command.input = {
pattern : command.input,
flags : ''
};
}
command.input.pattern = command.input.pattern.replace(
/~./g,
function ( c ) {
c = c.charAt( 1 );
if ( c === '~' ) {
return '~';
}
return '\\' + c;
}
);
var pattern;
try {
pattern = new RegExp( command.input.pattern, command.input.flags );
}
catch ( e ) {
bot.reply( e.message, usr );
throw e;
}
console.log( pattern );
var out = command.output;
bot.addCommand( command.name, function ( args, usr ) {
console.log( args, command.name + ' input' );
var msg = args.replace( pattern, function () {
var parts = arguments;
console.log( parts, command.name + ' replace #1' );
return out.replace( /\$(\d+)/g, function ( $0, $1 ) {
return parts[ $1 ];
});
});
console.log( msg, command.name + ' output' );
bot.reply( msg, usr );
});
bot.reply( 'Command ' + command.name + ' learned', usr );
},
mdn : function ( args, usr ) {
var parts = args.trim().split( '.' ),
base = 'https://developer.mozilla.org/en/',
url;
console.log( args, parts, 'mdn input' );
if (
parts[0] === 'document' ||
parts[0] === 'Node' ||
parts[0] === 'element'
) {
url = base + 'DOM/' + args;
console.log( url, 'mdn DOM' );
}
else if ( window[parts[0]] ) {
url = base +
'JavaScript/Reference/Global_Objects/' +
parts.join( '/' );
console.log( url, 'mdn global' );
}
else {
url = 'https://developer.mozilla.org/en-US/search?q=' + args;
console.log( url, 'mdn unknown' );
}
bot.reply( url, usr );
},
jquery : function ( args, usr ) {
args = args.trim().replace( /^\$/, 'jQuery' );
var parts = args.split( '.' ), exists = false, msg;
//parts will contain two likely components, depending on the user input
// user gave jQuery.prop - parts[0] will be jQuery, parts[1] will
// be prop
// user gave prop - parts[0] will be prop
// user gave jQuery.fn.prop - that's a special case
console.log( args, parts, 'jQuery input' );
//jQuery API urls works like this:
// if it's on the jQuery object, then the url is /jQuery.property
// if it's on the proto, then the url is /property
//user gave something like jQuery.fn.prop, turn that to just prop
if ( parts.length === 3 ) {
parts = [ parts[2] ];
}
//check to see if it's a property on the jQuery object itself
if ( parts[0] === 'jQuery' && jQuery[parts[1]] ) {
exists = true;
}
//user wants something on the prototype?
else if ( parts.length === 1 && jQuery.prototype[parts[0]] ) {
exists = true;
}
//user just wanted a property? maybe.
else if ( jQuery[parts[0]] ) {
args = 'jQuery.' + parts[0];
exists = true;
}
if ( exists ) {
msg = 'http://api.jquery.com/' + args;
}
else {
msg = 'Could not find specified jQuery property ' + args;
}
console.log( msg, 'jQuery link' );
bot.reply( msg, usr );
}
};
Object.keys( commands ).forEach(function ( cmdName ) {
bot.addCommand( cmdName, commands[cmdName] );
});
var htmlEntities = {
'"' : '"'
};
var randomWord = (function () {
var words = ['abbreviation','abbreviations','abettor','abettors','abilities','ability','abrasion','abrasions','abrasive','abrasives','absence','absences','abuse','abuser','abusers','abuses','acceleration','accelerations','acceptance','acceptances','acceptor','acceptors','access','accesses','accessories','accessory','accident','accidents','accommodation','accomplishment','accomplishments','accord','accordance','account','accountabilities','accountability','accounts','accrual','accruals','accruement','accumulation','accumulations','accuracy','accusation','accusations','acid','acids','acquisition','acquisitions','acquittal','acquittals','acre','acres','acronym','acronyms','act','action','actions','activities','activity','acts','adaption','adaptions','addition','additions','additive','additives','address','addressee','addressees','addresses','adherence','adherences','adhesive','adhesives','adjective','adjectives','adjustment','adjustments','administration','administrations','administrator','administrators','admiral','admirals','admiralties','admiralty','admission','admissions','advance','advancement','advancements','advances','advantage','advantages','adverb','adverbs','advertisement','advertisements','adviser','advisers','affair','affairs','affiant','affiants','afternoon','afternoons','age','agent','agents','ages','aggravation','aggravations','agreement','agreements','aid','aids','aim','aims','air','aircraft','airfield','airfields','airplane','airplanes','airport','airports','airs','airship','airships','airspeed','airspeeds','alarm','alarms','alcohol','alcoholic','alcoholics','alcoholism','alcohols','alert','alerts','algebra','algorithm','algorithms','alias','aliases','alibi','alibis','alignment','alignments','alkalinity','allegation','allegations','alley','alleys','allies','allocation','allocations','allotment','allotments','allowance','allowances','alloy','alloys','ally','alphabet','alphabets','alternate','alternates','alternation','alternations','alternative','alternatives','altimeter','altimeters','altitude','altitudes','aluminum','aluminums','ambiguity','americans','ammonia','ammunition','amount','amounts','amperage','amperages','ampere','amperes','amplifier','amplifiers','amplitude','amplitudes','amusement','amusements','analog','analogs','analyses','analysis','analyst','analysts','analyzer','analyzers','anchor','anchors','angle','angles','animal','animals','annex','annexs','answer','answers','antenna','antennas','anthem','anthems','anticipation','apostrophe','apostrophes','apparatus','apparatuses','appeal','appeals','appearance','appearances','appellate','apple','apples','applicant','applicants','application','applications','apportionment','apportionments','appraisal','appraisals','apprehension','apprehensions','apprenticeship','apprenticeships','approach','approaches','appropriation','appropriations','approval','approvals','april','apron','aprons','aptitude','aptitudes','arc','arch','arches','architecture','arcs','area','areas','argument','arguments','arithmetic','arm','armament','armaments','armful','armfuls','armies','armor','armories','armors','armory','arms','army','arraignment','arraignments','arrangement','arrangements','array','arrays','arrest','arrests','arrival','arrivals','arrow','arrows','art','article','articles','artilleries','artillery','arts','assault','assaults','assemblies','assembly','assignment','assignments','assistance','assistant','assistants','associate','associates','asterisk','asterisks','athwartship','atmosphere','atmospheres','atom','atoms','attachment','attachments','attack','attacker','attackers','attempt','attempts','attention','attesting','attitude','attitudes','attorney','attorneys','attraction','attractions','attribute','attributes','audit','auditor','auditors','audits','augmentation','augmentations','august','authorities','authority','authorization','authorizations','auto','automation','automobile','automobiles','autos','auxiliaries','average','averages','aviation','award','awards','ax','axes','axis','azimuth','azimuths','babies','baby','back','background','backgrounds','backs','backup','backups','badge','badges','bag','bags','bail','bailing','bails','balance','balances','ball','ballast','balloon','balloons','balls','band','bandage','bandages','bands','bang','bangs','bank','banks','bar','barge','barges','barometer','barometers','barrel','barrels','barrier','barriers','bars','base','baseline','basement','basements','bases','basics','basin','basins','basis','basket','baskets','bat','batch','batches','bath','bather','baths','bats','batteries','battery','battle','battles','battleship','battleships','baud','bauds','bay','bays','beach','beaches','beacon','beacons','bead','beads','beam','beams','bean','beans','bear','bearings','bears','beat','beats','bed','beds','beginner','beginners','behavior','behaviors','being','beings','belief','beliefs','bell','bells','belt','belts','bench','benches','bend','bends','benefit','benefits','berries','berry','berth','berthings','berths','bet','bets','bias','biases','bigamies','bigamy','bilge','bill','billet','billets','bills','bin','binder','binders','binoculars','bins','birth','births','bit','bite','bites','bits','blackboard','blackboards','blade','blades','blank','blanket','blankets','blanks','blast','blasts','blaze','blazes','blindfold','blindfolds','blink','blinks','block','blocks','blood','blot','blots','blow','blower','blowers','blows','blueprint','blueprints','blur','blurs','board','boards','boat','boats','boatswain','boatswains','bodies','body','boil','boiler','boilers','boils','bolt','bolts','bomb','bombs','bond','bonds','bone','bones','book','books','boom','booms','boost','boosts','boot','boots','bore','boresight','boresights','bottle','bottles','bottom','bottoms','bow','bowl','bowls','bows','box','boxcar','boxcars','boxes','boy','boys','brace','braces','bracket','brackets','braid','braids','brain','brains','brake','brakes','branch','branches','brass','breach','breaches','bread','breads','break','breakdown','breakdowns','breaks','breast','breasts','breath','breaths','breeze','breezes','brick','bricks','bridge','bridges','briefings','brightness','bristle','bristles','broadcasts','bronze','brook','brooks','broom','brooms','brother','brothers','brush','brushes','bubble','bubbles','bucket','buckets','buckle','buckles','bud','budget','budgets','buds','buffer','buffers','builder','builders','building','buildings','bulb','bulbs','bulk','bulkhead','bulkheads','bullet','bullets','bump','bumps','bunch','bunches','bundle','bundles','bunk','bunks','buoy','buoys','bureau','bureaus','burglaries','burglary','burn','burns','bus','buses','bush','bushel','bushels','bushes','bushing','bushings','business','businesses','butt','butter','butters','button','buttons','butts','buy','buys','buzz','buzzer','buzzers','buzzes','bypass','bypasses','byte','bytes','cab','cabinet','cabinets','cable','cables','cabs','cage','cages','cake','cakes','calculation','calculations','calculator','calculators','calendar','calendars','caliber','calibers','calibration','calibrations','call','calls','calorie','calories','cam','camera','cameras','camp','camps','cams','canal','canals','candidate','candidates','candle','candles','cane','canister','canisters','cannon','cannons','cans','canvas','canvases','canyon','canyons','cap','capabilities','capability','capacitance','capacitances','capacities','capacitor','capacitors','capacity','cape','capes','capital','capitals','caps','capstan','capstans','captain','captains','capture','captures','car','carbon','carbons','carburetor','carburetors','card','cardboard','cards','care','career','careers','carelessness','cares','cargo','cargoes','carload','carloads','carpet','carpets','carriage','carriages','carrier','carriers','cars','cart','cartridge','cartridges','carts','case','cases','cash','cashier','cashiers','casts','casualties','casualty','catalog','catalogs','catch','catcher','catchers','catches','categories','category','cathode','cathodes','cause','causes','caution','cautions','cave','caves','cavities','cavity','ceiling','ceilings','cell','cellar','cellars','cells','cement','cements','cent','center','centerline','centerlines','centers','centimeter','centimeters','cents','ceramics','ceremonies','ceremony','certificate','certificates','certification','certifications','chain','chains','chair','chairman','chairmen','chairperson','chairpersons','chairs','chairwoman','chairwomen','chalk','chalks','challenge','challenges','chamber','chambers','chance','chances','change','changes','channel','channels','chaplain','chaplains','chapter','chapters','character','characteristic','characteristics','characters','charge','charges','chart','charts','chase','chases','chattel','chattels','chatter','cheat','cheater','cheaters','cheats','check','checker','checkers','checkout','checkouts','checkpoint','checkpoints','checks','cheek','cheeks','cheese','cheeses','chemical','chemicals','chemistry','chest','chests','chief','chiefs','child','children','chill','chills','chimney','chimneys','chin','chins','chip','chips','chit','chits','chock','chocks','choice','choices','choke','chokes','church','churches','churn','churns','circle','circles','circuit','circuitries','circuitry','circuits','circulation','circulations','circumference','circumferences','circumstance','circumstances','cities','citizen','citizens','city','civilian','civilians','claim','claims','clamp','clamps','clang','clangs','clap','claps','class','classes','classification','classifications','classroom','classrooms','claw','claws','clay','cleanliness','cleanser','cleansers','clearance','clearances','cleat','cleats','clericals','clerk','clerks','click','clicks','cliff','cliffs','clip','clips','clock','clocks','closure','closures','cloth','clothes','clothing','cloths','cloud','cloudiness','clouds','club','clubs','clump','clumps','coal','coals','coast','coasts','coat','coating','coats','cockpit','cockpits','code','coder','coders','codes','coil','coils','coin','coins','colds','collar','collars','collection','collections','collector','collectors','college','colleges','collision','collisions','colon','colons','color','colors','column','columns','comb','combat','combatant','combatants','combination','combinations','combs','combustion','comfort','comforts','comma','command','commander','commanders','commands','commas','commendation','commendations','comment','comments','commission','commissions','commitment','commitments','committee','committees','communication','communications','communities','community','companies','company','comparison','comparisons','compartment','compartments','compass','compasses','compensation','compensations','competition','competitions','compiler','compilers','complaint','complaints','complement','complements','completion','completions','complexes','compliance','compliances','component','components','composites','composition','compositions','compounds','compress','compresses','compression','compressions','compressor','compressors','compromise','compromises','computation','computations','computer','computers','concentration','concentrations','concept','concepts','concern','concerns','concurrence','condensation','condensations','condenser','condensers','condition','conditions','conduct','conductor','conductors','conducts','cone','cones','conference','conferences','confession','confessions','confidence','confidences','configuration','configurations','confinement','confinements','conflict','conflicts','confusion','confusions','congress','conjecture','conjectures','conjunction','conjunctions','conn','connection','connections','consequence','consequences','consideration','console','consoles','consolidation','conspiracies','conspiracy','constitution','construction','contact','contacts','container','containers','contamination','contempt','content','contention','contents','continuity','contraband','contract','contracts','contrast','contrasts','contribution','contributions','control','controls','convenience','conveniences','convention','conventions','conversion','conversions','convulsion','convulsions','coordinate','coordinates','coordination','coordinations','coordinator','coordinators','copies','copper','copy','cord','cords','core','cores','cork','corks','corner','corners','corps','correction','corrections','correlation','correlations','correspondence','corrosion','cosal','cosals','costs','cot','cots','cotton','cottons','cough','coughs','counsel','counselor','counselors','counsels','count','counter','countermeasure','countermeasures','counters','countries','country','counts','couple','couples','couplings','course','courses','court','courtesies','courtesy','courts','cover','coxswain','coxswains','crack','cracks','cradle','cradles','craft','crafts','cramp','cramps','crank','cranks','crash','crashes','crawl','credibility','credit','credits','creek','creeks','crew','crewmember','crewmembers','crews','cries','crime','crimes','crop','crops','cross','crosses','crowd','crowds','crown','crowns','cruise','cruiser','cruisers','cruises','crust','crusts','cry','crystal','crystals','cube','cubes','cuff','cuffs','cup','cupful','cupfuls','cups','cure','cures','curl','curls','currencies','currency','currents','curtain','curtains','curvature','curvatures','curve','curves','cushion','cushions','custodian','custodians','custody','custom','customer','customers','customs','cuts','cycle','cycles','cylinder','cylinders','dab','dabs','dam','damage','damages','dams','danger','dangers','dare','dares','dart','darts','dash','data','date','dates','daughter','daughters','davit','davits','dawn','dawns','day','daybreak','days','daytime','deal','dealer','dealers','deals','dears','death','deaths','debit','debits','debris','debt','debts','decay','december','decibel','decibels','decimals','decision','decisions','deck','decks','decoder','decoders','decontamination','decoration','decorations','decrease','decreases','decrement','decrements','dedication','dedications','deduction','deductions','deed','deeds','default','defaults','defeat','defeats','defect','defection','defections','defects','defense','defenses','deficiencies','definition','definitions','deflector','deflectors','degree','degrees','delay','delays','delegate','delegates','deletion','deletions','delight','delights','delimiter','delimiters','deliveries','delivery','democracies','democracy','demonstration','demonstrations','densities','density','dent','dents','department','departments','departure','departures','dependence','dependencies','dependents','depletion','depletions','deployment','deployments','deposit','deposition','depositions','deposits','depot','depots','depth','depths','deputies','deputy','dereliction','description','descriptions','desert','deserter','deserters','desertion','desertions','deserts','designation','designations','designator','designators','desire','desires','desk','desks','destination','destinations','destroyer','destroyers','destruction','detachment','detachments','detail','details','detection','detent','detention','detentions','detents','detonation','detonations','development','developments','deviation','deviations','device','devices','dew','diagnoses','diagnosis','diagnostics','diagonals','diagram','diagrams','dial','dials','diameter','diameters','diamond','diamonds','diaphragm','diaphragms','diaries','diary','dictionaries','dictionary','diesel','diesels','difference','differences','difficulties','difficulty','digestion','digit','digits','dimension','dimensions','diode','diodes','dioxide','dioxides','dip','dips','direction','directions','directive','directives','directories','directory','dirt','disabilities','disability','disadvantage','disadvantages','disassemblies','disassembly','disaster','disasters','discard','discards','discharge','discharges','discipline','disciplines','discontinuance','discontinuances','discontinuation','discontinuations','discount','discounts','discoveries','discovery','discrepancies','discrepancy','discretion','discrimination','discriminations','discussion','discussions','disease','diseases','disgust','dish','dishes','disk','disks','dispatch','dispatcher','dispatchers','dispatches','displacement','displacements','display','displays','disposal','dissemination','dissipation','distance','distances','distortion','distortions','distress','distresses','distribution','distributions','distributor','distributors','district','districts','ditch','ditches','ditto','dittos','dive','diver','divers','dives','divider','dividers','division','divisions','dock','dockings','docks','document','documentation','documentations','documents','dollar','dollars','dollies','dolly','dominion','dominions','donor','donors','door','doorknob','doorknobs','doors','doorstep','doorsteps','dope','dopes','dose','doses','dot','dots','doubt','downgrade','downgrades','dozen','dozens','draft','drafts','drag','drags','drain','drainage','drainer','drainers','drains','drawer','drawers','drawings','dress','dresses','drift','drifts','drill','driller','drillers','drills','drink','drinks','drip','drips','drive','driver','drivers','drives','drop','drops','drug','drugs','drum','drums','drunkeness','drunks','drydock','drydocks','dump','duplicate','duplicates','durability','duration','duress','dust','dusts','duties','duty','dwell','dye','dyes','dynamics','dynamometer','dynamometers','ear','ears','earth','ease','eases','east','echelon','echelons','echo','echoes','economies','economy','eddies','eddy','edge','edges','editor','editors','education','educator','educators','effect','effectiveness','effects','efficiencies','efficiency','effort','efforts','egg','eggs','eighths','eighties','eights','ejection','elapse','elapses','elbow','elbows','election','elections','electrician','electricians','electricity','electrode','electrodes','electrolyte','electrolytes','electron','electronics','electrons','element','elements','elevation','eleven','eligibility','elimination','eliminator','eliminators','embosses','emergencies','emergency','emitter','emitters','employee','employees','enclosure','enclosures','encounter','encounters','end','endeavor','endeavors','endings','ends','enemies','enemy','energies','energizer','energizers','energy','engine','engineer','engineers','engines','enlistment','enlistments','ensign','ensigns','entrance','entrances','entrapment','entrapments','entries','entry','envelope','envelopes','environment','environments','equation','equations','equator','equipment','equivalent','equivalents','eraser','erasers','error','errors','escape','escapes','escort','escorts','establishment','establishments','evacuation','evacuations','evaluation','evaluations','evaporation','eve','evening','evenings','event','events','eves','evidence','examination','examinations','example','examples','exception','exceptions','excess','excesses','exchange','exchanger','exchangers','exchanges','excuse','excuses','execution','executions','executive','executives','exercise','exercises','exhaust','exhausts','exhibit','exhibits','existence','exit','exits','expansion','expansions','expenditure','expenditures','expense','expenses','experience','experiences','expert','experts','expiration','explanation','explanations','explosion','explosions','explosives','exposure','exposures','extension','extensions','extent','extenuation','extenuations','exterior','exteriors','extras','eye','eyes','fabrication','fabrications','face','facepiece','facepieces','faces','facilitation','facilities','facility','fact','factor','factories','factors','factory','facts','failure','failures','fake','fakes','fall','fallout','falls','families','family','fan','fans','fantail','fantails','farad','farads','fare','fares','farm','farms','fashion','fashions','fastener','fasteners','father','fathers','fathom','fathoms','fatigue','fatigues','fats','fault','faults','fear','fears','feather','feathers','feature','features','february','fee','feed','feedback','feeder','feeders','feeds','feelings','fees','feet','fellow','fellows','fence','fences','fetch','fetches','fiber','fibers','fiction','field','fields','fifteen','fifths','fifties','fifty','fight','fighter','fighters','fighting','fights','figure','figures','file','files','filler','fillers','film','films','filter','filters','fines','finger','fingers','finish','finishes','fire','firearm','firearms','fireball','fireballs','firefighting','fireplug','fireplugs','firer','firers','fires','firings','firmware','fish','fishes','fist','fists','fits','fittings','fives','fixture','flag','flags','flake','flakes','flame','flames','flange','flanges','flap','flaps','flare','flares','flash','flashes','flashlight','flashlights','fleet','fleets','flesh','flicker','flickers','flight','flights','float','floats','flood','floods','floor','floors','flow','flowchart','flower','flowers','fluid','fluids','flush','foam','focus','focuses','fog','fogs','fold','folder','folders','folds','food','foods','foot','footing','footings','force','forces','forearm','forearms','forecastle','forecastles','forecasts','foreground','forehead','foreheads','forest','forests','fork','forks','form','format','formation','formations','formats','forms','formula','formulas','fort','forties','forts','forty','fountain','fountains','fours','fourths','fraction','fractions','fracture','fractures','frame','frames','freedom','freeze','freezes','freight','freights','frequencies','frequency','freshwater','friction','friday','fridays','friend','friends','frigate','frigates','front','fronts','frost','frosts','fruit','fruits','fuel','fuels','fumes','function','functions','fund','funding','funds','fur','furnace','furnaces','furs','fuse','fuses','future','futures','gage','gages','galley','galleys','gallon','gallons','gallows','game','games','gang','gangs','gangway','gangways','gap','gaps','garage','garages','garden','gardens','gas','gases','gasket','gaskets','gasoline','gasolines','gate','gates','gear','gears','generals','generation','generations','generator','generators','geography','giant','giants','girl','girls','glance','glances','gland','glands','glass','glasses','glaze','glazes','gleam','gleams','glide','glides','glossaries','glossary','glove','gloves','glow','glows','glue','glues','goal','goals','goggles','gold','goods','government','governments','governor','governors','grade','grades','grain','grains','gram','grams','grant','grants','graph','graphs','grasp','grasps','grass','grasses','gravel','gravity','grease','greases','greenwich','grid','grids','grinder','grinders','grip','grips','groan','groans','groceries','groom','grooms','groove','grooves','gross','grounds','group','groups','grove','groves','growth','growths','guard','guards','guess','guesses','guest','guests','guidance','guide','guideline','guidelines','guides','guilt','gulf','gulfs','gum','gums','gun','gunfire','gunnery','gunpowder','guns','guy','guys','gyro','gyros','gyroscope','gyroscopes','habit','habits','hail','hair','hairpin','hairpins','hairs','half','hall','halls','halt','halts','halves','halyard','halyards','hammer','hammers','hand','handful','handfuls','handle','handler','handlers','handles','hands','handwriting','hangar','hangars','harbor','harbors','hardcopies','hardcopy','hardness','hardship','hardships','hardware','harm','harmonies','harmony','harness','harnesses','harpoon','harpoons','hashmark','hashmarks','haste','hat','hatch','hatches','hatchet','hatchets','hate','hats','haul','hauls','hazard','hazards','head','header','headers','headings','headquarters','heads','headset','headsets','health','heap','heaps','heart','hearts','heat','heater','heaters','heats','heel','heels','height','heights','helicopter','helicopters','hello','helm','helmet','helmets','helms','helmsman','helmsmen','help','hem','hems','henry','henrys','here','hertz','hickories','hickory','hierarchies','hierarchy','highline','highlines','highway','highways','hill','hills','hillside','hillsides','hilltop','hilltops','hinge','hinges','hint','hints','hip','hips','hiss','hisses','histories','history','hitch','hitches','hits','hoist','hoists','hold','holddown','holddowns','holder','holders','holds','hole','holes','home','homes','honk','honks','honor','honors','hood','hoods','hoof','hoofs','hook','hooks','hoop','hoops','hope','hopes','horizon','horizons','horn','horns','horsepower','hose','hoses','hospital','hospitals','hotel','hotels','hour','hours','house','housefall','housefalls','houses','housing','housings','howl','howls','hub','hubs','hug','hugs','hull','hulls','hum','human','humans','humidity','humor','hump','humps','hums','hundred','hundreds','hunk','hunks','hunt','hunts','hush','hushes','hut','huts','hydraulics','hydrometer','hydrometers','hygiene','hyphen','hyphens','ice','ices','icing','idea'];
var n = words.length;
return function () {
return words[ Math.floor(Math.random() * n) ];
};
}());
var game = {
//the dude is just a template to be filled with parts
dude :
" +---+\n" +
" | |\n" +
" | 413\n" +
" | 2\n" +
" | 5 6\n" +
"__+__\n",
parts : [ '', 'O', '|', '/', '\\', '/', '\\' ],
word : '',
revealed : '',
guesses : [],
guessNum : 0,
maxGuess : 6,
guessMade : false,
gameEnd : true,
validGuessRegex : /^[\w\s]+$/,
//start a new game
new : function () {
this.word = randomWord();
this.revealed = new Array( this.word.length + 1 ).join( '-' );
this.guesses = [];
this.guessNum = 0;
this.gameEnd = false;
//oh look, another dirty hack...this one is to make sure the hangman
// is codified
this.guessMade = true;
IO.register( 'beforeoutput', this.buildOutput, this );
},
//this is just a medium function
receiveMessage : function ( msg, usr ) {
if ( this.gameEnd ) {
bot.reply(
'Game finished or didn\'t start. Ping me with /new to start',
usr
);
return;
}
this.handleGuess( msg, usr );
},
handleGuess : function ( guess, usr ) {
console.log( guess, usr, 'handleGuess' );
guess = guess.toLowerCase();
if ( !this.validGuessRegex.test(guess) ) {
bot.reply(
'Only alphanumeric and whitespace characters allowed',
usr
);
return;
}
//check if it was already submitted
if ( this.guesses.indexOf(guess) > -1 ) {
bot.reply( guess + ' was already submitted', usr );
return;
}
//replace all occurences of guest within the hidden word with their
// actual characters
var indexes = this.word.indexesOf( guess );
if ( indexes.length ) {
indexes.forEach(function ( index ) {
this.uncoverPart( guess, index );
}, this);
}
//not found in secret word, penalize the evil doers!
else {
this.guessNum++;
}
this.guesses.push( guess );
this.guessMade = true;
//plain vanilla lose-win checks
if ( this.loseCheck() ) {
this.lose();
return;
}
if ( this.winCheck() ) {
this.win( usr );
return;
}
},
//unearth a portion of the secret word
uncoverPart : function ( guess, startIndex ) {
var revealed = '';
revealed += this.revealed.slice( 0, startIndex );
revealed += guess;
revealed += this.revealed.slice( startIndex + guess.length );
this.revealed = revealed;
},
//attach the hangman drawing to the already guessed list and to the revealed
// portion of the secret word
preparePrint : function () {
var msg = '', that = this;
msg += this.dude.replace( /\d/g, function ( part ) {
return part > that.guessNum ? ' ' : that.parts[ part ];
});
msg += this.guesses.join( ', ' ) + '\n';
msg += this.revealed;
bot.output( msg );
},
//win the game
win : function ( winrar ) {
this.gameEnd = true;
bot.output(
'Correct! The phrase is ' + this.word + '. Congrats to @' + winrar
);
},
winCheck : function () {
return this.word === this.revealed;
},
//lose the game. less bitter messages? maybe.
lose : function () {
this.gameEnd = true;
bot.output( 'You people suck. The phrase was ' + this.word );
},
loseCheck : function () {
return this.guessNum >= this.maxGuess;
},
buildOutput : function () {
if ( !this.gameEnd && this.guessMade ) {
this.preparePrint();
bot.codifyOutput = true;
this.guessMade = false;
}
}
};
bot.addCommand( 'new', game.new.bind(game) );
var IO = {
//event handling
events : {},
preventDefault : false,
//register for an event
register : function ( name, fun, thisArg ) {
if ( !this.events[name] ) {
this.events[ name ] = [];
}
this.events[ name ].push({
fun : fun,
thisArg : thisArg,
args : Array.prototype.slice.call( arguments, 3 )
});
return this;
},
//fire event!
fire : function ( name ) {
if ( !this.events[name] ) {
return;
}
var args = Array.prototype.slice.call( arguments, 1 );
this.events[ name ].forEach( fireEvent, this);
function fireEvent( evt ) {
var call = evt.fun.apply( evt.thisArg, evt.args.concat(args) );
if ( call === false ) {
this.preventDefault = true;
}
}
}
};
//build IO.in and IO.out
[ 'in', 'out' ].forEach(function ( dir ) {
var fullName = dir + 'put';
IO[ dir ] = {
buffer : [],
receive : function ( obj ) {
IO.fire( 'receive' + fullName, obj );
if ( IO.preventDefault ) {
console.log( obj, 'preventDefault' );
IO.preventDefault = false;
return this;
}
this.buffer.push( obj );
return this;
},
//unload the next item in the buffer
tick : function () {
if ( this.buffer.length ) {
IO.fire( fullName, this.buffer.shift() );
}
return this;
},
//unload everything in the buffer
flush : function () {
IO.fire( 'before' + fullName );
if ( !this.buffer.length ) {
return this;
}
var i = this.buffer.length;
while( i --> 0 ) {
this.tick();
}
IO.fire( 'after' + fullName );
this.buffer = [];
return this;
}
};
});
//hijack xhr to monitor all incoming requests
XMLHttpRequest.prototype.open = (function(){
//keep a reference to the old one (will be used to call it later)
var old = XMLHttpRequest.prototype.open;
return function(){
//we only care about the finished reuqests
this.addEventListener( "load", function(){
var parsed;
try {
parsed = JSON.parse( this.responseText );
}
//if there's a parsing error, just ignore the request
catch ( e ) {
return;
}
handleMessageObject( parsed );
//handle all messages that came,
IO.in.flush();
IO.out.flush();
});
//call the old version
return old.apply( this, arguments );
};
//handle a request object
function handleMessageObject( obj ) {
Object.keys( obj ).forEach(function ( key ) {
//I can't intelligently explain this part. you gotta sniff around
// how SO sends message data to get this
var msgObj = obj[ key ];
if ( msgObj.e && msgObj.e[0] ) {
msgObj.e.forEach( handleMessage );
}
});
}
//handle an individual message object
function handleMessage ( msg ) {
//event_type of 1 means new message
if ( msg.event_type !== 1 ) {
return;
}
//add the message to the input buffer and then handle it
IO.in.receive( msg );
}
}());
//small utility functions
String.prototype.indexesOf = function ( str ) {
var part = this.valueOf(),
//we use offset to determine the absolute distance from beginning
index, offset = 0,
len = str.length,
ret = [];
while ( (index = part.indexOf(str)) >= 0 ) {
ret.push( index + offset );
part = part.slice( index + len );
offset += index + len;
}
return ret;
};
String.prototype.startsWith = function ( str ) {
return this.indexOf( str ) === 0;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment