Refactoring: BaseGame, Game, ComputerGame (ProblemGame?)
[vchess.git] / client / src / views / Game.vue
CommitLineData
a6bddfc6
BA
1<!-- TODO: component Game, + handle players + observers connect/disconnect
2 event = "gameconnect" ...etc
3 connect/disconnect with sid+name (ID not required); name slightly redundant but easier
4ce15fd9
BA
4
5quand on arrive dans la partie, on poll les sids pour savoir qui est en ligne (ping)
6(éventuel échange lastate avec les connectés, pong ...etc)
7ensuite quand qqun se deco il suffit d'écouter "disconnect"
8pareil quand quelqu'un reco.
9(c'est assez rudimentaire et écoute trop de messages, mais dans un premier temps...)
7b626bdd 10 // TODO: [in game] send move + elapsed time (in milliseconds); in case of "lastate" message too
a6bddfc6 11-->
a6088c90
BA
12<template lang="pug">
13.row
14 .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
15 BaseGame(:variant="variant.name" @game-over=".....TODO")
16
17
18
19localStorage["score"] = score;
20
21
22 .button-group(v-if="mode!='analyze'")
23 button(@click="offerDraw") Draw
24 button(@click="abortGame") Abort
25 button(@click="resign") Resign
26 div(v-if="mode=='corr'")
27 textarea(v-show="score=='*' && vr.turn==mycolor" v-model="corrMsg")
28 div(v-show="cursor>=0") {{ moves[cursor].message }}
29</template>
30
31<script>
32// TODO: if I'm an observer and player(s) disconnect/reconnect, how to find me ?
33// onClick :: ask full game to remote player, and register as an observer in game
34// (use gameId to communicate)
35// on landing on game :: if gameId not found locally, check remotely
36// ==> il manque un param dans game : "remoteId"
37import Board from "@/components/Board.vue";
38//import Chat from "@/components/Chat.vue";
39//import MoveList from "@/components/MoveList.vue";
40import { store } from "@/store";
41
42export default {
43 name: 'my-game',
44 components: {
45 BaseGame,
46 },
47 // gameId: to find the game in storage (assumption: it exists)
48 // mode: "live" or "corr" (correspondance game), or "analyze"
49 // gameRef in URL hash (listen for changes)
50 props: ["gid","mode","variant"],
51 data: function() {
52 return {
53 st: store.state,
54 myname: store.state.user.name, //may be anonymous (thus no name)
55 opponents: {}, //filled later (potentially 2 or 3 opponents)
56 drawOfferSent: false, //did I just ask for draw?
57 people: [], //observers
58 };
59 },
60 watch: {
61 gid: function() {
62 this.launchGame();
63 },
64 },
65 // Modal end of game, and then sub-components
66 created: function() {
67 if (!!this.gid)
68 this.launchGame();
69 // TODO: if I'm one of the players in game, then:
70 // Send ping to server (answer pong if opponent[s] is connected)
71 if (true && !!this.conn && !!this.gameRef)
72 {
73 this.conn.onopen = () => {
74 this.conn.send(JSON.stringify({
75 code:"ping",oppid:this.oppid,gameId:this.gameRef.id}));
76 };
77 }
78 // TODO: also handle "draw accepted" (use opponents array?)
79 // --> must give this info also when sending lastState...
80 // and, if all players agree then OK draw (end game ...etc)
81 const socketMessageListener = msg => {
82 const data = JSON.parse(msg.data);
83 let L = undefined;
84 switch (data.code)
85 {
86 case "newmove": //..he played!
87 this.play(data.move, this.variant.name!="Dark" ? "animate" : null);
88 break;
89 case "pong": //received if we sent a ping (game still alive on our side)
90 if (this.gameRef.id != data.gameId)
91 break; //games IDs don't match: definitely over...
92 this.oppConnected = true;
93 // Send our "last state" informations to opponent(s)
94 L = this.vr.moves.length;
95 Object.keys(this.opponents).forEach(oid => {
96 this.conn.send(JSON.stringify({
97 code: "lastate",
98 oppid: oid,
99 gameId: this.gameRef.id,
100 lastMove: (L>0?this.vr.moves[L-1]:undefined),
101 movesCount: L,
102 }));
103 });
104 break;
105 // TODO: refactor this, because at 3 or 4 players we may have missed 2 or 3 moves (not just one)
106 case "lastate": //got opponent infos about last move
107 L = this.vr.moves.length;
108 if (this.gameRef.id != data.gameId)
109 break; //games IDs don't match: nothing we can do...
110 // OK, opponent still in game (which might be over)
111 if (this.score != "*")
112 {
113 // We finished the game (any result possible)
114 this.conn.send(JSON.stringify({
115 code: "lastate",
116 oppid: data.oppid,
117 gameId: this.gameRef.id,
118 score: this.score,
119 }));
120 }
121 else if (!!data.score) //opponent finished the game
122 this.endGame(data.score);
123 else if (data.movesCount < L)
124 {
125 // We must tell last move to opponent
126 this.conn.send(JSON.stringify({
127 code: "lastate",
128 oppid: this.opponent.id,
129 gameId: this.gameRef.id,
130 lastMove: this.vr.moves[L-1],
131 movesCount: L,
132 }));
133 }
134 else if (data.movesCount > L) //just got last move from him
135 this.play(data.lastMove, "animate");
136 break;
137 case "resign": //..you won!
138 this.endGame(this.mycolor=="w"?"1-0":"0-1");
139 break;
140 // TODO: also use (dis)connect info to count online players?
141 case "gameconnect":
142 case "gamedisconnect":
143 if (this.mode=="human")
144 {
145 const online = (data.code == "connect");
146 // If this is an opponent ?
147 if (!!this.opponents[data.id])
148 this.opponents[data.id].online = online;
149 else
150 {
151 // Or an observer ?
152 if (!online)
153 delete this.people[data.id];
154 else
155 this.people[data.id] = data.name;
156 }
157 }
158 break;
159 }
160 };
161 const socketCloseListener = () => {
162 this.conn.addEventListener('message', socketMessageListener);
163 this.conn.addEventListener('close', socketCloseListener);
164 };
165 if (!!this.conn)
166 {
167 this.conn.onmessage = socketMessageListener;
168 this.conn.onclose = socketCloseListener;
169 }
170 },
171 // dans variant.js (plutôt room.js) conn gère aussi les challenges
172 // et les chats dans chat.js. Puis en webRTC, repenser tout ça.
173 methods: {
174 offerDraw: function() {
175 if (!confirm("Offer draw?"))
176 return;
177 // Stay in "draw offer sent" state until next move is played
178 this.drawOfferSent = true;
179 if (this.subMode == "corr")
180 {
181 // TODO: set drawOffer on in game (how ?)
182 }
183 else //live game
184 {
185 this.opponents.forEach(o => {
186 if (!!o.online)
187 {
188 try {
189 this.conn.send(JSON.stringify({code: "draw", oppid: o.id}));
190 } catch (INVALID_STATE_ERR) {
191 return;
192 }
193 }
194 });
195 }
196 },
197 // + conn handling: "draw" message ==> agree for draw (if we have "drawOffered" at true)
198 receiveDrawOffer: function() {
199 //if (...)
200 // TODO: ignore if preventDrawOffer is set; otherwise show modal box with option "prevent future offers"
201 // if accept: send message "draw"
202 },
203 abortGame: function() {
204 if (!confirm("Abort the game?"))
205 return;
206 //+ bouton "abort" avec score == "?" + demander confirmation pour toutes ces actions,
207 //send message: "gameOver" avec score "?"
208 },
209 resign: function(e) {
210 if (!confirm("Resign the game?"))
211 return;
212 if (this.mode == "human" && this.oppConnected(this.oppid))
213 {
214 try {
215 this.conn.send(JSON.stringify({code: "resign", oppid: this.oppid}));
216 } catch (INVALID_STATE_ERR) {
217 return;
218 }
219 }
220 this.endGame(this.mycolor=="w"?"0-1":"1-0");
221 },
222 launchGame: async function() {
223 const vModule = await import("@/variants/" + this.variant.name + ".js");
224 window.V = vModule.VariantRules;
225 this.loadGame(this.gid);
226 },
227 loadGame: function(gid) {
228 // TODO: ask game to remote peer if this.remoteId is set
229 // (or just if game not found locally)
230 // NOTE: if it's a corr game, ask it from server
231 const game = getGameFromStorage(gid); //, this.gameRef.uid); //uid may be blank
232 this.opponent.id = game.oppid; //opponent ID in case of running HH game
233 this.opponent.name = game.oppname; //maye be blank (if anonymous)
234 this.score = game.score;
235 this.mycolor = game.mycolor;
236 this.fenStart = game.fenStart;
237 this.moves = game.moves;
238 this.cursor = game.moves.length-1;
239 this.lastMove = (game.moves.length > 0 ? game.moves[this.cursor] : null);
240 },
241 oppConnected: function(uid) {
242 return this.opponents.any(o => o.id == uidi && o.online);
243 },
244 },
245};
246</script>