Skip to content

Instantly share code, notes, and snippets.

@wemakeweb
Last active August 29, 2015 14:04
Show Gist options
  • Save wemakeweb/31ad14217eda854548d2 to your computer and use it in GitHub Desktop.
Save wemakeweb/31ad14217eda854548d2 to your computer and use it in GitHub Desktop.
/**
* (c) 2014 Hodor Inc.
*/
function $(id) { // einfach nur eine funktion, damit man nicht jedesmal document.getElementById(id); schreiben muss
return document.getElementById(id);
}
var DEBUGLEVEL = {// wie unten, einfach nur, damits schöner aussieht)
DEBUG: 0,
NOTICE: 1,
ERROR: 2
};
var currentDebugLevel = DEBUGLEVEL.NOTICE;
function debug(message, level) { // kram auf der console ausgeben
if (level === undefined) {
level = DEBUGLEVEL.DEBUG;
}
if (level < currentDebugLevel) {
return;
}
// und wenn es ein objekt oder array ist, den inhalt anzeigen; sonst steht da einfach nur [object Array], wenn du das mit console.log(obj) machst
if (Object.prototype.toString.call(message) === '[object Array]' || Object.prototype.toString.call(message) === '[object Object]') {
console.log(new Date().getTime() + ':');
dump(message);
} else {
var e = document.createElement('p');
e.innerHTML = new Date().getTime() + ': ' + message;
$('debug').insertBefore(e, $('debug').childNodes[0]);
}
}
function dump(obj) {
console.debug(obj);
}
// das hier ist auch noch nicht sauber, die werde ich größtenteils noch in die game-klasse verschieben
var ablagestapelDiv = $('ablagestapel');
var computerHandDiv = $('computerHand');
var menschHandDiv = $('menschHand');
var ziehstapelDiv = $('ziehstapel');
var karten = [];
var zeichen = ["Herz", "Pik", "Kreuz", "Karo"];
var zahlen = ["7", "8", "9", "10", "J", "Q", "K", "A"];
var computerKarten = [];
var menschKarten = [];
var ziehStapelKarten = [];
var ablageStapelKarten = [];
function init() { // joa, wie der name schon sagt
debug('init');
karten = kartenGenerieren();
kartenMischen(karten);
menschKarten = kartenZiehen(5); // fünf für den menschen
computerKarten = kartenZiehen(5); // comp
ziehStapelKarten = kartenZiehen(21); // der rest
ablageStapelKarten.push(kartenZiehen(1)); // die eine für den anfang
GAME.init(); // die spiel-klasse initialisieren
mainLoop(); // und die schleife starten
}
function mainLoop() { // diese funktion wird im produktiv-betrieb dann halt alle ~30ms ausgeführt
GAME.step(); // und dann wird einfach nur diese funktion ausgeführt, die auf den aktuellen zustand reagiert (oder auch nicht -> GAME.STATUS.WAITING, wenn nichts passiert ist in der zwischenzeit)
// TODO: auch wirklich nur ausführen, wenn etwas geändert wurde, sonst verschenken wir total viel rechenleistung
render(); // wenn beim ausführen von game.step() änderungen passiert sind, werden diese ausgegeben ("gerendert")
if (GAME.CURRENTSTATUS === GAME.STATUS.ENDE) {
alert('ES IST VORBEI; BEI BEI JULIMOND');
GAME.saveScore();
return;
} else if( GAME.CURRENTSTATUS === GAME.STATUS.DRAW){
alert('Das Spiel endet unentschieden');
return;
}
// das sorgt dafür, dass sich die funktion nach x Millisekunden wieder selbst aufruft
setTimeout(function() {
mainLoop();
}, 1000 / GAME.TICKRATE);
}
function kartenGenerieren() { // der code ist ja schon alt
var neueKarten = [];
for (var j = 0; j < zeichen.length; j++) {
for (var k = 0; k < zahlen.length; k++) {
neueKarten.push({
zeichen: zeichen[j],
zahl: zahlen[k],
title: zeichen[j] + ' ' + zahlen[k]
});
}
}
return neueKarten;
}
function kartenMischen(o) { // google, copy&paste -> keine ahnung, was da genau passiert. funkioniert aber
for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x)
;
return o;
}
function kartenZiehen(anzahl) {
// weniger als 1 karte ziehen? -> HODOR!
if (anzahl < 1) {
debug('wrong usage', DEBUGLEVEL.ERROR);
}
if (anzahl === 1) {
return karten.pop(); // wenns eine sein soll, geben wir einfach eine direkte zurück (Erinnerung pop() gibt einfach das oberster element aus und löscht es direkt aus dem array)
} else {
// bei mehreren karten wird einfach ne schleife ausgeführt
var returnKarten = []; // und die gezogenen karten erstmal zwischengespeichert
for (var i = 0; i < anzahl; i++) {
returnKarten.push(karten.pop()); //hier wird gespeichert
}
return returnKarten; // und dann das array zurückgeben
}
// dadurch muss man halt net fünfmal kartenZiehen(1) aufrufen, wenn man fünf karten haben will
}
function render() { // einfach nur den kram ausgeben, der in den arrays steht
if (!GAME.PLEASERENDER) { // wenn nichts gerendert werden muss, nichts tun
return; // wenn hier nicht "return"t wird, dann wird das alles ausgeführt, obwohl es nicht ausgeführt werden muss
}
debug('render start');
// computerhand
computerHandDiv.innerHTML = '';
for (var i = 0; i < computerKarten.length; i++) {
var e = document.createElement('div');
e.className = 'karte';
computerHandDiv.appendChild(e);
}
//menschenhand
menschHandDiv.innerHTML = '';
for (var j = 0; j < menschKarten.length; j++) {
var e = document.createElement('div');
e.className = 'karte';
e.innerHTML = menschKarten[j].title; // hier geben wir im unterschied zum computer die beschreibung aus
e.onclick = function() { // und die menschenkarten kann man anklicken
GAME.playCard(this.innerHTML, GAME.LOCATION.MENSCHHAND);
};
menschHandDiv.appendChild(e);
}
// der ablagestapel (mega uninteressant)
ablagestapelDiv.innerHTML = '<div class="karte">' + ablageStapelKarten[ablageStapelKarten.length - 1].title + '</div>';
// der ziehstapel ist schon besser
ziehstapelDiv.innerHTML = '';
var e = document.createElement('div');
e.className = 'karte';
e.onclick = function() { // und mit onclick-funktionalität
if(ziehStapelKarten.length != 0){
GAME.playCard('N A', GAME.LOCATION.ZIEHSTAPEL);
} else {
alert('Ziehstapel ist leer.');
}
};
ziehstapelDiv.appendChild(e);
GAME.PLEASERENDER = false;
}
var GAME = {
TICKRATE: 2, // wie oft soll nachgefragt werden (Formel: 1000 / Tickrate = ms Wartezeit zwischen zwei Nachfragen)
STATUS: {// die status, die möglich sind (der plural von status ist übrigens status mit langem u ;))
START: 0,
COMPUTER: 1,
COMPUTERPLAYED: 2,
MENSCH: 3,
MENSCHPLAYED: 4,
ENDE: 5,
WAITING: 6,
DRAW: 7
},
LOCATION: {// das ist eigentlich auch nur syntaktischer zucker. ist es halt schöner GAME.LOCATION.MENSCHHAND zu schreiben und zu lesen also z.B. eine 0
MENSCHHAND: 0,
COMPUTERHAND: 1,
ABLAGESTAPEL: 2,
ZIEHSTAPEL: 3
},
PLEASERENDER: true,
CURRENTSTATUS: undefined, // der aktuelle status (ist am anfang einfach undefiniert und wird in der init-methode gesetzt
LASTPLAYEDCARD: undefined, // s.o.
LASTCARDWASFROMSTAPLE: false,
PLAYER: undefined, // s.o.
PLAYERS: {// die spieler
MENSCH: 0,
COMPUTER: 1
},
init: function() {
this.CURRENTSTATUS = this.STATUS.START; // am start ist der status "start" -> OMG; WTF; HODOR!
this.LASTPLAYEDCARD = ablageStapelKarten[ablageStapelKarten.length - 1]; //und die letzte Karte muss gesetzt werden, damit die gültigkeitsüberprüfung funkioniert (ist halt einfach die karte, die da schon liegt)
},
playCard: function(whichOne, from) {
var card = this.determineCardTypeByString(whichOne); //welche karte wurde gespielt
this.LASTCARDWASFROMSTAPLE = true;
if (from === this.LOCATION.MENSCHHAND || from === this.LOCATION.COMPUTERHAND) { // wenn sie von einer der hände kam, muss sie spielbar gewesen sein
if (!this.isCardPlayable(card)) {
alert('Das war ein ungültiger Zug!');
return false;
}
this.LASTPLAYEDCARD = card; // wir müssen uns merken, welche karte zuletzt gespielt wurde, damit wir wissen, ob der aktuelle zug gültig war
this.LASTCARDWASFROMSTAPLE = false;
}
this.removeCardFromStaple(card, from); // die karte von der hand oder vom stapel entfernen
if( this.CURRENTSTATUS != this.STATUS.DRAW ){
if (this.PLAYER === this.PLAYERS.MENSCH) { // ansonsten einfach nur den spielstatus ändern, damit die mainloop reagieren kann
this.CURRENTSTATUS = this.STATUS.MENSCHPLAYED;
}
if (this.PLAYER === this.PLAYERS.COMPUTER) {
this.CURRENTSTATUS = this.STATUS.COMPUTERPLAYED;
}
this.PLEASERENDER = true;
}
return true;
},
step: function() {
debug('CURRENTSTATUS: ' + this.CURRENTSTATUS);
switch (this.CURRENTSTATUS) {
case this.STATUS.START:
debug('Das Spiel beginnt', DEBUGLEVEL.NOTICE);
this.PLAYER = this.PLAYERS.MENSCH;
this.CURRENTSTATUS = this.STATUS.MENSCH;
break;
case this.STATUS.MENSCH: // macht wirklich nichts anderes als zu sagen, dass du dran bist
debug('Du bist am Zug', DEBUGLEVEL.NOTICE);
this.PLAYER = this.PLAYERS.MENSCH;
this.CURRENTSTATUS = this.STATUS.WAITING;
break;
case this.STATUS.MENSCHPLAYED: // der mensch hat gespielt
this.CURRENTSTATUS = this.STATUS.COMPUTER; // das heißt jetzt ist der computer dran
if (menschKarten.length === 0) {
this.CURRENTSTATUS = this.STATUS.ENDE;
return;
}
/**
* Überprüfe ob es noch spielbare Züge gibt
*/
var playAbleCard = this.findAny(menschKarten, this.isCardPlayable, this);
if(this.LASTPLAYEDCARD && !playAbleCard && ziehStapelKarten.length == 0){
this.CURRENTSTATUS = this.STATUS.DRAW;
return;
}
if (this.checkForCardBube()) { // war die karte ein bube, dann darfst du dir was wünschen
// var c = prompt('Wünsch dir was (z.B.: Herz 7; Schreibweise beachten!)');
// debug('Gewünscht wurde: ' + c, DEBUGLEVEL.NOTICE);
// TODO
this.PLEASERENDER = true; // es hat sich was an den karten verändert, deswegen muss neu gerendert werden
}
if (this.checkForCard7()) { // klar
debug('Computer musste 2 Karten ziehen!', DEBUGLEVEL.NOTICE);
this.card7Handler();
this.PLEASERENDER = true; // es hat sich was an den karten verändert, deswegen muss neu gerendert werden
}
if (this.checkForCard8()) { // auch klar
debug('Computer muss aussetzen', DEBUGLEVEL.NOTICE);
this.CURRENTSTATUS = this.STATUS.MENSCH; // hier ändern wir den status wieder zurück auf mensch -> sonst wäre ja der computer dran
}
break;
case this.STATUS.COMPUTER: // gibt aus wer dran ist
debug('Der Computer ist am Zug', DEBUGLEVEL.NOTICE);
this.PLAYER = this.PLAYERS.COMPUTER;
// aber hier brauchen wir einen "BOT", der das macht, was sonst der mensch machen würde
for (var i = 0; i < computerKarten.length; i++) { //einfach durch die karten durchgehen
var c = this.determineCardTypeByString(computerKarten[i].title);
if (c.zeichen === this.LASTPLAYEDCARD.zeichen || c.zahl === this.LASTPLAYEDCARD.zahl) { // und wenn eine spielbare dabei ist, spielen
debug('Der computer spielt folgende Karte:');
debug(c);
GAME.playCard(computerKarten[i].title, this.LOCATION.COMPUTERHAND);
return;
}
}
GAME.playCard('N A', GAME.LOCATION.ZIEHSTAPEL); // der computer konnte keine karte spielen -> eine karte vom stapel nehmen
break;
case this.STATUS.COMPUTERPLAYED: //gleich wie oben beim menschen
this.CURRENTSTATUS = this.STATUS.MENSCH;
if (computerKarten.length === 0) {
this.CURRENTSTATUS = this.STATUS.ENDE;
return;
}
/**
* Überprüfe ob es noch spielbare Züge gibt
*/
var playAbleCard = this.findAny(computerKarten, this.isCardPlayable, this);
if(this.LASTPLAYEDCARD && !playAbleCard && ziehStapelKarten.length == 0){
this.CURRENTSTATUS = this.STATUS.DRAW;
return;
}
/* if (this.checkForCardBube()) {
// das wünschen muss der computer dann auch generieren ("BOT"-Funktionalität)
var c = prompt('Wünsch dir was (z.B.: Herz 7; Schreibweise beachten!)');
debug('Gewünscht wurde: ' + c);
// TODO
this.PLEASERENDER = true; // es hat sich was an den karten verändert, deswegen muss neu gerendert werden
}*/
if (this.checkForCard7()) {
debug('Du musstest 2 Karten ziehen!', DEBUGLEVEL.NOTICE);
this.card7Handler();
this.PLEASERENDER = true; // es hat sich was an den karten verändert, deswegen muss neu gerendert werden
}
if (this.checkForCard8()) {
debug('Du musst aussetzen', DEBUGLEVEL.NOTICE);
this.CURRENTSTATUS = this.STATUS.COMPUTER;
}
break;
case this.STATUS.ENDE: // blub
this.calculateScore();
alert('Das Spiel ist vorbei.');
break;
case this.STATUS.WAITING: // einfach nichts tun und warten bis etwas passiert
debug('waiting for an action');
break;
}
},
card7Handler: function() {
var toPushFrom;
/**
* spieler kann keine karten mehr ziehen -> unentschieden
*/
if(ziehStapelKarten.length < 1){
this.CURRENTSTATUS = this.STATUS.DRAW;
return;
}
if (this.PLAYER === this.PLAYERS.COMPUTER) {
toPushFrom = menschKarten;
} else {
toPushFrom = computerKarten;
}
toPushFrom.push(ziehStapelKarten.pop());
toPushFrom.push(ziehStapelKarten.pop());
},
checkForCard7: function() { // easy
if (this.LASTPLAYEDCARD.zahl != 7) {
return false;
}
return true;
},
checkForCard8: function() { // verständlich
if (this.LASTPLAYEDCARD.zahl != 8) {
return false;
}
return true;
},
checkForCardBube: function() { // bla
if (this.LASTPLAYEDCARD.zahl != "J") {
return false;
}
return true;
},
determineCardTypeByString: function(str) { // erwartet einen string wie er oben generiert wird (z.B. "Herz 8")
var arr = str.split(" "); // den String aufbrechen (am Leerzeichen) und in ein array speichern
return {// und einfach zur schönen programmierung ein objekt zurückgeben mit den werten
zeichen: arr[0], // z.B. "Herz"
zahl: arr[1] // z.B: "8"
};
},
isCardPlayable: function(whichOne) {
/**
* Spezial Fall Bube
* 1. Buben sind auf allses legbar
* 2. Auf einen Buben darf nur eine Karte mit dem selben Zeichen des Bubens gelegt werden
*/
if( whichOne.zahl === "J" || this.LASTPLAYEDCARD.zahl == "J" && whichOne.zeichen === this.LASTPLAYEDCARD.zeichen ){
return true;
}
if (this.LASTPLAYEDCARD.zahl === whichOne.zahl || this.LASTPLAYEDCARD.zeichen === whichOne.zeichen) { // gültig ist der zug, wenn die zahl oder das zeichen gleich ist; || = ODER
return true;
}
return false;
},
removeCardFromStaple: function(card, from) { // ganz langweilige array-operationen
if (from === this.LOCATION.MENSCHHAND) { // wenn die karte von der menschenhand entfernt werden soll
var newCards = []; // wir speichern einfach die karten, die erhalten bleiben sollen zwischen
for (var i = 0; i < menschKarten.length; i++) {
var c = this.determineCardTypeByString(menschKarten[i].title);
if (c.zeichen === card.zeichen && c.zahl === card.zahl) { // das hier ist eigentlich unsauber programmiert. die funktion soll eine karte entfernen, legt aber eine gültige karte auf den ablagestapel, aber das passt erst mal so, weil das programm ja noch sehr übersichtlich ist ;)
ablageStapelKarten.push(menschKarten[i]); // wenn die karte gültig war (also gespielt werden durfte), kopiere sie in den ablagestapel
continue; //und kopieren sie in das neue array
}
newCards.push(menschKarten[i]); // hier wird gespeichert
}
menschKarten = newCards; // das neue array wieder in der "Hand" speichern
return;
}
if (from === this.LOCATION.COMPUTERHAND) { // das gleiche wie oben nur für den computer
var newCards = [];
for (var i = 0; i < computerKarten.length; i++) {
var c = this.determineCardTypeByString(computerKarten[i].title);
if (c.zeichen === card.zeichen && c.zahl === card.zahl) {
ablageStapelKarten.push(computerKarten[i]);
continue;
}
newCards.push(computerKarten[i]);
}
computerKarten = newCards;
return;
}
if (from === this.LOCATION.ZIEHSTAPEL) { // wenn eine karte vom ziehstapel gezogen wurde, dann packe sie dem spiel auf die hand
var cardFromStack = ziehStapelKarten.pop();
console.log("ziehStapelKarten %s", ziehStapelKarten.length);
if (this.PLAYER === this.PLAYERS.MENSCH) {
menschKarten.push(cardFromStack);
} else {
computerKarten.push(cardFromStack);
}
return;
}
debug('no cards removed?!'); // das hier ist nur der fehler fall, wenn man irgendwas falsch gemacht hat (sollte also nie erscheinen optimalerweise)
},
/**
* calculates the store
*/
saveScore : function(){
var score = 0;
/**
* computer wins, do nothing
*/
if( computerKarten.length == 0 ){
return;
}
computerKarten.forEach(function( karte ){
if(['7', '8', '9', '10'].indexOf(karte) >= 0){
score += parseInt(karte);
} else {
score += 10;
}
});
// var name = document.getElementById('#name').innerHTML;
this.ajaxPost('Highscore.php', {
score : score,
name : 'jan'
}, function( text ){
console.log(text);
})
},
ajaxPost : function( url, data, cb){
var formData = new FormData();
for(var key in data){
formData.append(key, data[key]);
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
cb(xhr.responseText);
}
};
xhr.open("post", url, true);
xhr.send(formData);
},
findAny : function(arr, cb, ctx){
for(var i =0, len= arr.length; len > i; i++){
if( cb.call(ctx || this, arr[i]) === true ){
return true;
}
}
return false;
}
};
init();
/*
übrigens ist der ablauf im prinzip ziemlich simpel:
1. generieren und mischen der karten
2. danach wird nur initialisiert (also die karten verteilt, notwendige objekte erstellt und der kram dargestellt blabliblub)
3. die hauptschleife wird ausgeführt und da passiert die eigentliche magie
3.1. das spiel hat immer einen zustand, der sagt, was als nächstes passieren muss (zum beispiel this.STATUS.MENSCH sagt aus, dass jetzt der mensch ziehen muss)
3.2. besonders ist hier, dass es einen zustand this.STATUS.WAITING gibt. das hängt damit zusammen, dass wir hier warten muss, aber das programm weiterläuft. so
funktioniert eigentlich jetzt spiel und sogar dein betriebssystem. sobald irgendein neuer status eintritt, wird dann einfach darauf reagiert. weil wir nicht
wissen, wann das ist, fragen wir einfach alle paar millisekunden nach:
function mainLoop() {
GAME.step(); // nachfragen
render(); // den aktuellen stand auf der html-seite ausgeben
if (GAME.CURRENTSTATUS === GAME.STATUS.ENDE) { // wenn das spiel zuende ist, brauchen wir nichts mehr nachfragen
return;
}
setTimeout(function() { //hiermit warten wir einfach x millisekunden
mainLoop();
}, 1000 / GAME.TICKRATE); //1000ms durch tickrate ergibt die anzahl ms, die gewartet wird. momentan ist die tickrate 1, deswegen wird immer 1000ms gewartet
//ich werde nachher 33 wieder einstellen, dass heißt alle ~30ms wird der status überprüft und änderungen gerendert
}
3.3. die funktion render() zeigt den kram an, der in den karten-arrays steht:
computerHandDiv.innerHTML = ''; //erstmal leer machen
for (var i = 0; i < computerKarten.length; i++) { //für jede karte auf der computer hand
var e = document.createElement('div'); //element erstellen
e.className = 'karte';
computerHandDiv.appendChild(e); // und einfügen im dom
}
menschHandDiv.innerHTML = ''; //so
for (var j = 0; j < menschKarten.length; j++) {//so
var e = document.createElement('div');
e.className = 'karte';
e.innerHTML = menschKarten[j].title;
e.onclick = function() { //hier kommt noch der onclick-handler dazu, damit man auf etwas klicken kann und was passiert
GAME.playCard(this.innerHTML, GAME.LOCATION.MENSCHHAND); //nämlich ein spielzug ausführen -> GAME.playcard
};
menschHandDiv.appendChild(e);
}
ablagestapelDiv.innerHTML = '<div class="karte">' + ablageStapelKarten[ablageStapelKarten.length - 1].title + '</div>';
ziehstapelDiv.innerHTML = '';
var e = document.createElement('div');
e.className = 'karte';
e.innerHTML = 'Zieh mich';
e.onclick = function() {
GAME.playCard(this.innerHTML, GAME.LOCATION.ZIEHSTAPEL);
};
ziehstapelDiv.appendChild(e);
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment