Forum: PC-Programmierung [Javascript] Monopoly


von Paul S. (flughafen2)


Lesenswert?

Hallo,
hier eine Idee die ich mal umsetzen wollte:
Javascript Monopoly

Der Ablaufplan für 2 Spieler sieht etwa so aus:
1
- Spieler1 ist dran
2
- Nachricht: Würfel wurden auf n und p gerollt (n und p sind zufällig 0<n<7)
3
- bewege Spieler1 n+p Felder vorwärts
4
- Der Spieler ladet auf einer Straße:
5
-- Nachricht wenn Straße nicht verkauft ist: Möchte Spieler1 die Straße mit der Nummer n für v € kaufen?
6
-- ja
7
--- Geld v wird abgezogen
8
--- Spieler erhält Karte
9
-- nein
10
---
11
-- Nachricht wenn Straße verkauft ist (Miete): Spieler1 hat Besitzer q Miete gezahlt
12
-- Geld wird verschoben
13
- Der Spieler muss ins Gefängnis:
14
-- Die Spielfigur wird auf das Gefängnisfeld geschoben.
15
- LOS:
16
-- Der Spieler erhält das Geld
17
- Nachricht: Spieler2 ist dran
Das Spielfeld sieht (von Javascript aus betrachtet) so aus:
1
|--------------------------------|
2
|<div id='feld3'></div>Parkstraße|
3
|--------------------------------|
4
|<div id='feld2'></div>Turmstraße|
5
|--------------------------------|
6
|<div id='feld1'></div>Badstraße |
7
|--------------------------------|
Jedes Feld hat eine eindeutige Nummer und ist so aufgebaut:
1
<div class='feld'>
2
<!--im Beispiel der Rahmen-->
3
<div id='feldN'>
4
<!--hier schreibt Javascript die Spielernamen rein-->
5
</div>
6
Straßenname
7
</div>
Hier ist eine Javascript Funktion dazu:
1
var spieler1position=1;//Spieler ist auf Feld 1
2
function move (spieler,nach){
3
  document.getElementById('feld'+nach).innerHTML="";
4
  document.getElementById('feld'+nach).innerHTML=spieler;
5
}
6
move ('spieler1',3);//Spieler ist danach auf Feld 3
Damit die Spieler die Informationen erhalten, sind 2 Dinge definiert:
1
<!--1. Info-Box-->
2
<div id="spieler1-info-box"></div>
3
<!--2. Daten-->
4
<div id="spieler1-geld"></div>
5
<div id="spieler1-strassen"></div>
zum Aufruf sind Javascript-Funktionen nötig:
1
function addmoney (spieler,howmuch){
2
3
}
4
function removemoney (spieler,howmuch){
5
6
}
7
function info (spieler,msg){
8
9
}

Kann man daraus was sinnvolles bauen?

von anonym (Gast)


Lesenswert?

Paul Schmitz schrieb:
> Kann man daraus was sinnvolles bauen?

rein mit javascript nicht wirklich - man kann zwar das spielprinzip 
nachbauen, als verteilte anwendung jedoch relativ witzlos, da man sich 
mit einfachsten mitteln einfach selbst bereichern kann.
als ajax-anwendung (evtl. mit KI) könnte man da schon ein bisschen mehr 
daraus machen, erfordert aber ein bisschen hirnschmalz um den datenstand 
aller mitspieler synchron zu halten und auch manipulationen 
auszuschließen

von Paul S. (flughafen2)


Lesenswert?

anonym schrieb:
> rein mit javascript nicht wirklich - man kann zwar das spielprinzip
> nachbauen, als verteilte anwendung jedoch relativ witzlos, da man sich
> mit einfachsten mitteln einfach selbst bereichern kann.

Wenn man nicht gerade einen Knopf einfügt 'sich selbst Geld geben' und 
Tastenkombinationen blockiert, ist das eigentlich ganz gut (keine 
Konsole). Man spielt dann statt mit einem Brett virtuell.

Man könnte sogar von verschiedenen Rechnern aus spielen, wenn man auf 
dem Server den Spielstatus in eine Datei schreibt und diese immer wieder 
ausliest.

von Daniel A. (daniel-a)


Lesenswert?

Jedem feld eine eigene id zu geben ist nicht ideal. Ich empfehle auf 
html zu verzichten und statdessen oop zu verwenden:
1
function Feld(){
2
  var e = document.createElement("div");
3
  this.getElement=function(){
4
    return e;
5
  };
6
}
7
var feld = new Feld();

Und dann für feld,spielfeld, etc sinnvolle klassen schreiben.

von Paul S. (flughafen2)


Lesenswert?

Daniel A. schrieb:
> function Feld(){
>   var e = document.createElement("div");
>   this.getElement=function(){
>     return e;
>   };
> }
> var feld = new Feld();

Ich habe den Code mal getestet, die Erzeugungsfunktion tut jedoch in 
Firefox und Chrome nichts. Eigentlich sollte doch ein div erzeugt 
werden, oder?

von Daniel A. (daniel-a)


Lesenswert?

Das wird es auch! Aber das div wurde zu keinem element im document tree 
hinzugefügt. Dafür gibt es die methode:
1
parentNode.appendChild(newNode)

Dann kann man im document ein element mit der id spielfeldContainer 
erstellen, erstellt eine instanz seiner Spielfeld klasse und ruft 
getElement und appendChild auf um es dem dokument hinzuzufügen. Die 
spielfeld klasse erstellt wiederum instanzen der Feld klassen, 
registriert deren root element an der richtigen stelle, und baut so das 
Spielfeld zusammen. Vorteil: Du musst den Elementen keine ID geben, und 
kanst deren referenzen z.B. in einem Array speichern. Die instanzierun 
der Felder und das setzen derer eigenschaften, etc. kann danach in einer 
einfachen schleife gelöst werden, und eine Änderung für alle Felder wird 
zu einer einzigen in der Feld klasse.

von Paul S. (flughafen2)


Lesenswert?

Okay, damit funktionierts.
1
div#spielfeld div {border:1px solid black;width:100px;height:50px;}
2
</style>
3
<div id="spielfeld"></div>
4
<script> 
5
function Feld(){
6
  var e = document.createElement("div");
7
  document.getElementById('spielfeld').appendChild(e);
8
  this.getElement=function(){
9
    return e;
10
  };
11
  this.addText=function(text){
12
    e.innerHTML=text;
13
  }
14
  this.clear=function(){
15
    e.innerHTML="";
16
  }
17
}
18
var feld1 = new Feld();
19
var feld2 = new Feld();
20
feld2.addText ("Feldtext");
21
 </script>

: Bearbeitet durch User
von Paul S. (flughafen2)


Angehängte Dateien:

Lesenswert?

So, im Anhang befinden sich einige Funktionen:
Feld: addText fügt einen Text zum Feld hinzu, clear löscht diesen
msg: show zeigt einen Text, hide versteckt diesen
player: Geldverwaltung: addmoney fügt Geld hinzu, removemoney zieht 
welches ab, ein Player hat normal 0€
Straße: name,miete,kaufpreis,houses sind gesetzt, changeplayer ändert 
den Spieler, die Variable this.player ist normal undefined, buy(player) 
kauft die Straße, buyhouse(player) kauft ein Haus und multipliziert die 
Miete mit dem Wert (EDIT: hat noch einen kleinen Fehler), addFeld macht 
diese Straße als Feld sichtbar

Definiert muss nur noch das folgende werden:
1
var strasse1 = new strasse ("Schlossstraße",50,400);
2
//...
3
4
var player1 = new player ("Spieler1");
5
var player2 = new player ("Spieler2");
6
//...
7
8
var msg = new msg;
9
msg.show ('Willkommen bei Monopoly.');

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

OK, der Ansatz ist gut, aber es gibt einige störende Details, z.B. die 
Funktion buy in der classe Strasse, nicht die Strasse kauft den Player, 
es ist umgekehrt! Du könntest die Funktion setOwner nennen, und die buy 
funktion im player, diese ruft dort die setOwner funktion der Strasse 
und seine eigene removemoney funktion auf, welche optional private sein 
könnte.
Ausserdem: Verwende NIEMALS eval, denn eval ist böse!
1
// Schlechte lösung
2
var geldabziehen=this.player+".removemoney ("+this.kaufpreis+");";
3
eval (geldabziehen);
4
5
// korrekte lösung 1
6
this.player.removemoney(this.kaufpreis);
7
8
// korrekte lösung 2
9
var geldabziehen=this.player.removemoney.bind(this.player,this.kaufpreis);
10
geldabziehen();
11
12
// korrekte lösung 3
13
var geldabziehen=this.player.removemoney.bind(this.player);
14
geldabziehen(this.kaufpreis);

von Paul S. (flughafen2)


Lesenswert?

Okay.

Daniel A. schrieb:
> Ausserdem: Verwende NIEMALS eval, denn eval ist böse!

Wieso gibt es das dann? Und was ist äquivalent zu diesem, aber nicht 
böse?
Mit deinem Code (anstatt von eval,
1
var geldabziehen=this.player.removemoney.bind(this.player);geldabziehen(this.kaufpreis);
) erhalte ich nur "TypeError: this.player.removemoney is undefined".

Der Player kann nun verschoben und angezeigt werden.
1
function player (name){
2
  this.name=name;
3
  //Geld
4
  this.money=0;
5
  this.position=0;//Strasse0
6
  this.addmoney=function(howmuch){
7
    this.money+=howmuch;
8
  };
9
  this.removemoney=function(howmuch){
10
    this.money-=howmuch;
11
    if(this.money<0){
12
      alert (this.name+' hat verloren!');
13
    }
14
  };
15
  this.moveAbsolute=function(newfield){
16
    this.position=newfield;
17
    return this.position;
18
  };
19
  this.moveRelative=function(stepforward){
20
    this.position+=stepforward;
21
    return this.position;
22
  };
23
  this.showPlayerDiv=function(pos){
24
    eval ("strasse"+pos+".feld.addText ('<div id=\'"+this.name"\'></div>');");
25
  };
26
}
Ebenso habe ich erste Ablauffunktionenideen umgesetzt (hier nur die 
Würfelfunktion mit 2 Würfeln):
1
function control (){
2
  this.wuerfle=function(){
3
    var cube1 = Math.floor((Math.random() * 6) + 1);
4
    var cube2 = Math.floor((Math.random() * 6) + 1);
5
    var cubes = cube1 + cube2;
6
    return cubes;
7
  }
8
}

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Paul Schmitz schrieb:
> Wieso gibt es das dann? Und was ist äquivalent zu diesem, aber nicht
> böse?

Eval kann alles, deshalb ist es böse. Es gibt kein gutartiges equivalent 
zu eval, obwohl sandboxing mit workern schon sehr nah dran ist.

> Mit deinem Code (anstatt von eval, var
> erhalte ich nur "TypeError: this.player.removemoney is undefined".

Ups, ich dachte this.player wäre eine referenz auf einen player, ist 
aber ein string mit dem Namen der playervariable, das ist ein 
Designfehler und sollte korrigiert werden.

Das "sicherere" equivalent zur Zeile:
1
var geldabziehen=this.player+".removemoney ("+this.kaufpreis+");";
2
eval (geldabziehen);
3
// besser, aber nicht gut, weil window globaler scope ist
4
window[this.player].removemoney (this.kaufpreis);

Die player sollten bei dieser zugriffsmethode aber in einem objekt oder 
array gespeichert und window durch den identifier einer referenz auf das 
objekt/array ersetzt werden.

: Bearbeitet durch User
von Paul S. (flughafen2)


Angehängte Dateien:

Lesenswert?

Nun habe ich eine per Javascripteingabe funktionierende Version gebaut.
Befehle:
- player1.addmoney(1000)
- player1.removemoney(1000)
- player1.moveAbsolute(1)
- player1.moveRelative(2)
- player1.showPlayerDiv()
- strasse1.setOwner("player1")
- strasse1.changeplayer("player2")
- strasse1.buyhouse()
- msg.show("Nachricht")
- msg.hide()
- controls.wuerfle()

Mit der Control-Funktion werden später diese Funktionen aufgerufen.

EDIT: Habe in Wikipedia ein schönes Spielfeld gesehen, das mit 
HTML-Tabellen erzeugt ist. Vielleicht kann man daraus ja noch was 
machen. http://de.wikipedia.org/wiki/Monopoly#Das_Spielfeld

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Nur um dass mit dem eval nochmal gesagt zu haben:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Don.27t_use_eval.21

Dashier stört mich immernoch:
  strasse1.setOwner("player1")
besser wäre:
  strasse1.setOwner(player1)

und dann statt
window[this.player].removemoney (this.kaufpreis);
folgendes:
this.player.removemoney(this.kaufpreis);

Es macht einfach keinen sinn den namen einer globalen variablen zu 
übergeben, nur um später einen lookup im globalen scope manuell 
durchzuführen, um eine referenz dieser variable zu erhalten. Wenn du die 
Variable direkt übergiebst, übergibst du nur dessen Referenz (ausser bei 
primitiven datentypen).

von Paul S. (flughafen2)


Angehängte Dateien:

Lesenswert?

Jetzt eine Neuerung:
Die Controls werden mit controls.run (playerN) aufgerufen. Nach einem 
Zug wird der Spieler automatisch gesetzt und Miete (wenn nötig) 
automatisch gezahlt. Die Spielerposition wird immer dargestellt.

Eine Funktion um Straßen zu belasten (umdrehen) ist noch nicht 
eingeführt, da dies etwas komplexer ist:
- Der Spieler muss die Straße auswählen können
- Der Spieler bekommt einmalig das Geld für den Straßenwert aber keine 
Miete mehr
- Der Spieler muss auswählen können, wann er das Geld wieder 
zurückzahlen muss (mit 10% Zinsen)

Die Tabelle von Wikipedia wurde teilweise schon eingebaut (untere Felder 
für die ganze Tabelle sehe ich aber noch keine Möglichkeit), um die alte 
Version zu nutzen muss nur der Name von FeldCp() und Feld() vertauscht 
werden und die Tabelle gelöscht werden.

: Bearbeitet durch User
von Paul S. (flughafen2)


Angehängte Dateien:

Lesenswert?

Nun habe ich mal die Controlfunktion geupdated, der playerdiv 
funktioniert aber nicht mehr :(
Nach Reparatur kommt dann:
- Gemeinschaftsfeld und ?-Feld
- Gefängnis
1
... der Code wurde in den Anhang verschoben ...

EDIT: Hat jemand ne Idee mit dem Spielfeld?

: Bearbeitet durch User
von Paul S. (flughafen2)


Angehängte Dateien:

Lesenswert?

Nun gibt es einige Knöpfe.
Nach Eingabe von controls.run(player1) oder controls.run(player2) und 
drücken von 'Kaufen' erscheint ein Knopf mit der action 
'strasse2.setOwner ([object Object]);'. erzeugt wird das mit 
blablabla.innerHTML+="<button 
onclick='strasse"+this.player.position+".setOwner 
("+this.player+");'>Kaufen</button><br>";. Was ist da falsch (ich meine 
das natürlich im Erzeugungscode, nicht die Tatsache, dass da [object 
Object] steht)?

von Daniel A. (daniel-a)


Lesenswert?

Paul S. schrieb:
> blablabla.innerHTML+="<button
> onclick='strasse"+this.player.position+".setOwner
> ("+this.player+");'>Kaufen</button><br>";. Was ist da falsch (ich meine
> das natürlich im Erzeugungscode, nicht die Tatsache, dass da [object
> Object] steht)?

innerHTML würde ich immer vermeiden (ausser wenn ich den inhalt von divs 
Löschen muss.

Hinweis: this.player+"" ist equivallent zu this.layer.toString() was zu 
"[Object object]" evaluiert.

Ungetestet:
1
  var button = document.createElement("button");
2
  button.appendChild(document.createTextNode("Kaufen"));
3
  button.addEventListener("click",function(event){
4
    window['strasse'+this.player.position].setOwner(this.player);
5
  }.bind(this));
6
  blablabla.appendChild(button);

Hierbei ist anzumerken, dass man this.player.position durch eine 
Referenz auf die Strasse ersezen könnte. Dadurch würde die verwendung 
von window[...] überflüssig. Oder die Strassen in ein Array packen, dann 
wird aus window['strasse'+this.player.position] folgendes: 
strassen[this.player.position]
Am besten beides kombinieren.

von Paul S. (flughafen2)


Lesenswert?

Die Funktion Zug sieht funktioniert so nicht (ungetesteter Code ist 
drin, gekennzeichnet durch Kommentare). Der Knopf erscheint, beim 
klicken auf diesen passiert jedoch nichts (und nichts ist zu wenig).
1
this.zug=function(player){  
2
    this.player=player;
3
    var w=this.wuerfle();
4
    document.getElementById("msg").innerHTML+=this.player.name+" ist dran<br>Die Würfel sind addiert "+w+".<br/>Der Spieler wurde gesetzt.<br>";
5
    this.player.removePlayerDiv ();
6
    this.player.moveRelative(w);
7
    this.player.showPlayerDiv();
8
    var plpos = this.player.position;
9
    if(typeof window["strasse"+plpos].player === "undefined"&&window["strasse"+plpos].kaufpreis!==0){
10
      document.getElementById("msg").innerHTML+="Die Straße ist noch zu kaufen.<br>Möchten sie diese nun kaufen?<br>";
11
//AB HIER IST DER CODE
12
      var button = document.createElement("button");
13
      button.appendChild(document.createTextNode("Kaufen"));
14
      button.addEventListener("click",function(event){
15
        window["strasse"+plpos].setOwner(this.player);
16
      }.bind(this));]
17
      document.getElementById("msg").appendChild(button);
18
//ENDE CODE
19
    }else{
20
      document.getElementById("msg").innerHTML+="Die Straße ist schon an "+window["strasse"+plpos].player.name+" verkauft, die Miete beträgt "+window["strasse"+plpos].miete+". Die Miete wurde gezahlt.<br>";
21
      this.player.removemoney (window["strasse"+plpos].miete);
22
      window["strasse"+plpos].player.addmoney (window["strasse"+plpos].miete);
23
    }
24
  };

Das mit dem Straßenarray so (macht so zumindest Sinn):
1
var strassen = new Array();
2
strassen[0] = new strasse ("LOS",0,0);
3
strassen[1] = new strasse ("name",50,50);
4
//u.s.w.
?

von Paul S. (flughafen2)


Angehängte Dateien:

Lesenswert?

Das ist jetzt behoben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.