mirror of
https://github.com/Aviortheking/Puissance4.git
synced 2025-04-22 10:52:15 +00:00
add the 2nd day of work
This commit is contained in:
parent
1ec96163ab
commit
6db66906da
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"id":"../node_modules/@dzeio/dom-manager/dist/index.js","dependencies":[{"name":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/package.json","includedInParent":true,"mtime":1608219815779},{"name":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/package.json","includedInParent":true,"mtime":1608219815443},{"name":"./DOMElement","loc":{"line":7,"column":45},"parent":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/index.js","resolved":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/DOMElement.js"},{"name":"./DOMFleetManager","loc":{"line":9,"column":50},"parent":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/index.js","resolved":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/DOMFleetManager.js"}],"generated":{"js":"\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.DOMFleetManager = exports.DOMElement = void 0;\r\nconst DOMElement_1 = __importDefault(require(\"./DOMElement\"));\r\nexports.DOMElement = DOMElement_1.default;\r\nconst DOMFleetManager_1 = __importDefault(require(\"./DOMFleetManager\"));\r\nexports.DOMFleetManager = DOMFleetManager_1.default;\r\n"},"sourceMaps":{"js":{"mappings":[{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":1,"column":0},"generated":{"line":1,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":2,"column":0},"generated":{"line":2,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":3,"column":0},"generated":{"line":3,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":4,"column":0},"generated":{"line":4,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":5,"column":0},"generated":{"line":5,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":6,"column":0},"generated":{"line":6,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":7,"column":0},"generated":{"line":7,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":8,"column":0},"generated":{"line":8,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":9,"column":0},"generated":{"line":9,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":10,"column":0},"generated":{"line":10,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":11,"column":0},"generated":{"line":11,"column":0}}],"sources":{"../node_modules/@dzeio/dom-manager/dist/index.js":"\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.DOMFleetManager = exports.DOMElement = void 0;\r\nconst DOMElement_1 = __importDefault(require(\"./DOMElement\"));\r\nexports.DOMElement = DOMElement_1.default;\r\nconst DOMFleetManager_1 = __importDefault(require(\"./DOMFleetManager\"));\r\nexports.DOMFleetManager = DOMFleetManager_1.default;\r\n"},"lineCount":11}},"error":null,"hash":"d24788d11e56655232f1dc2b69591de9","cacheData":{"env":{}}}
|
||||
{"id":"../node_modules/@dzeio/dom-manager/dist/index.js","dependencies":[{"name":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/package.json","includedInParent":true,"mtime":1608220555886},{"name":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/package.json","includedInParent":true,"mtime":1608219815443},{"name":"./DOMElement","loc":{"line":7,"column":45},"parent":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/index.js","resolved":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/DOMElement.js"},{"name":"./DOMFleetManager","loc":{"line":9,"column":50},"parent":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/index.js","resolved":"/home/ubuntu/Bureau/cours/2eme année/contest/Puissance4/node_modules/@dzeio/dom-manager/dist/DOMFleetManager.js"}],"generated":{"js":"\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.DOMFleetManager = exports.DOMElement = void 0;\r\nconst DOMElement_1 = __importDefault(require(\"./DOMElement\"));\r\nexports.DOMElement = DOMElement_1.default;\r\nconst DOMFleetManager_1 = __importDefault(require(\"./DOMFleetManager\"));\r\nexports.DOMFleetManager = DOMFleetManager_1.default;\r\n"},"sourceMaps":{"js":{"mappings":[{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":1,"column":0},"generated":{"line":1,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":2,"column":0},"generated":{"line":2,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":3,"column":0},"generated":{"line":3,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":4,"column":0},"generated":{"line":4,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":5,"column":0},"generated":{"line":5,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":6,"column":0},"generated":{"line":6,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":7,"column":0},"generated":{"line":7,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":8,"column":0},"generated":{"line":8,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":9,"column":0},"generated":{"line":9,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":10,"column":0},"generated":{"line":10,"column":0}},{"source":"../node_modules/@dzeio/dom-manager/dist/index.js","original":{"line":11,"column":0},"generated":{"line":11,"column":0}}],"sources":{"../node_modules/@dzeio/dom-manager/dist/index.js":"\"use strict\";\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.DOMFleetManager = exports.DOMElement = void 0;\r\nconst DOMElement_1 = __importDefault(require(\"./DOMElement\"));\r\nexports.DOMElement = DOMElement_1.default;\r\nconst DOMFleetManager_1 = __importDefault(require(\"./DOMFleetManager\"));\r\nexports.DOMFleetManager = DOMFleetManager_1.default;\r\n"},"lineCount":11}},"error":null,"hash":"d24788d11e56655232f1dc2b69591de9","cacheData":{"env":{}}}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
.cache
|
||||
dist/
|
||||
public/
|
||||
|
@ -1,9 +1,16 @@
|
||||
import WebSocket from "ws";
|
||||
import Listener from "./Listener";
|
||||
|
||||
/**
|
||||
* Creation et Export de la classe Connection hérité de Listener
|
||||
*/
|
||||
export default class Connection extends Listener<{
|
||||
message: (message: string | Record<string, any>) => void
|
||||
close: () => void
|
||||
}> {
|
||||
/**
|
||||
* Creation du constructeur, qui reçoit des messages de type string et qui les transforme en Json si possible
|
||||
*
|
||||
*/
|
||||
public constructor(
|
||||
private ws: WebSocket
|
||||
) {
|
||||
@ -15,8 +22,14 @@ export default class Connection extends Listener<{
|
||||
this.emit('message', message.toString())
|
||||
}
|
||||
})
|
||||
ws.once('close', () => {
|
||||
this.emit('close')
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Envoie du message reçu et modifié vers le serveur
|
||||
*/
|
||||
public send(message: string | Record<string, any>) {
|
||||
if (typeof message === 'string') {
|
||||
return this.ws.send(message)
|
||||
|
21
Websocket.ts
21
Websocket.ts
@ -2,27 +2,36 @@ import WebSocket from "ws";
|
||||
import Connection from "./Connection";
|
||||
import Listener from "./Listener";
|
||||
|
||||
/**
|
||||
* Creation et export de la class Server hérité de Listener
|
||||
*
|
||||
*/
|
||||
export default class Server extends Listener<{
|
||||
connection: (connection: Connection) => void
|
||||
open: () => void
|
||||
}> {
|
||||
|
||||
private clients: Array<Connection> = []
|
||||
private server: WebSocket.Server
|
||||
|
||||
/**
|
||||
* Créer un serveur WebSocket
|
||||
* Ecoute les emissions lors de l'ouverture d'une connection
|
||||
* émet l'information de nouvelle connection lors d'une nouvelle connection
|
||||
*/
|
||||
public constructor(options: WebSocket.ServerOptions) {
|
||||
super()
|
||||
const server = new WebSocket.Server(options, () => this.emit('open'))
|
||||
server.on('connection', (ws) => {
|
||||
const connection = new Connection(ws)
|
||||
connection.on('close', () => {
|
||||
const index = this.clients.indexOf(connection)
|
||||
this.clients.splice(index, 1)
|
||||
})
|
||||
this.emit('connection', connection)
|
||||
})
|
||||
this.server = server
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'envoyer un message à tout les serveurs reliés
|
||||
*/
|
||||
public broadcast(message: string) {
|
||||
this.clients.forEach((ws) => ws.send(message))
|
||||
this.server.clients.forEach((ws) => ws.send(message))
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,48 @@
|
||||
import { DOMElement, DOMFleetManager } from '@dzeio/dom-manager'
|
||||
import { textChangeRangeIsUnchanged } from 'typescript'
|
||||
|
||||
/**
|
||||
* Création et export de la classe game
|
||||
*/
|
||||
export default class Game {
|
||||
|
||||
private pointsJ1 = 0
|
||||
private pointsJ2 = 0
|
||||
public onReset?: () => void
|
||||
public onMultiStart?: () => void
|
||||
public multiplayerSessionId?: number
|
||||
public isWaitingForPlayerMove = false
|
||||
public playerColor: 'red' | 'yellow' = 'red'
|
||||
public gameType: 'single' | 'multi' = 'single'
|
||||
public onWin?: (color?: 'red' | 'yellow') => void
|
||||
|
||||
private table: DOMElement<HTMLTableElement>
|
||||
private columns: Array<Array<DOMElement>> = []
|
||||
|
||||
private gameStarted = false
|
||||
private ws?: WebSocket
|
||||
|
||||
/**
|
||||
* Création du constructeur permettant de créer le tableau de jeu
|
||||
*/
|
||||
public constructor(
|
||||
table: HTMLTableElement
|
||||
table: HTMLTableElement,
|
||||
rows: number = 6,
|
||||
cols: number = 7
|
||||
) {
|
||||
this.table = new DOMElement(table)
|
||||
for (let i = 0; i < rows; i++) {
|
||||
const row = new DOMElement('tr')
|
||||
for (let j = 0; j < cols; j++) {
|
||||
row.item.appendChild(new DOMElement('td').item)
|
||||
}
|
||||
row.place('asChildOf', this.table)
|
||||
}
|
||||
this.setupGeneral()
|
||||
}
|
||||
|
||||
/**
|
||||
* Mise en place du tableau, et de différents attributs nécessaires
|
||||
*/
|
||||
public setupGeneral() {
|
||||
// Clear la table
|
||||
this.columns = []
|
||||
@ -50,29 +78,138 @@ export default class Game {
|
||||
|
||||
// Setup la base du jeux
|
||||
}
|
||||
/**
|
||||
* Remise a zéro du jeu lors d'un redemarrage de partie
|
||||
*/
|
||||
public resetGame() {
|
||||
this.cleanMultiplayer()
|
||||
if (this.onReset) {
|
||||
this.onReset()
|
||||
}
|
||||
|
||||
public setRestartButton(btn: DOMElement) {
|
||||
btn.on('click', () => {
|
||||
this.setupGeneral()
|
||||
this.startSinglePlayer()
|
||||
this.pointsJ1 = 0
|
||||
this.pointsJ2 = 0
|
||||
this.updatePoints()
|
||||
|
||||
this.gameStarted = false
|
||||
this.clearTable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Remise a zéro du plateau de jeu lors d'un redemarrage de partie
|
||||
*/
|
||||
public clearTable() {
|
||||
const rows = new DOMFleetManager('tr', this.table)
|
||||
rows.each((item, rowIndex) => {
|
||||
const cells = new DOMFleetManager('td', item)
|
||||
// cellIndex = 0-6
|
||||
cells.each((cell, cellIndex) => {
|
||||
cell
|
||||
.text(' ')
|
||||
.data('color', null)
|
||||
.data('winner', null)
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Lancement d'une partie en joueur vs ia
|
||||
*/
|
||||
public startSinglePlayer() {
|
||||
this.gameStarted = true
|
||||
this.gameType = 'single'
|
||||
this.setPlayerTurn(true)
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Gestion des différentes requetes en fonction des actions de l'utilisateur
|
||||
*/
|
||||
public onWebSocket = (event: MessageEvent) => {
|
||||
const json = JSON.parse(event.data)
|
||||
if ('joined' in json && json.joined === true) {
|
||||
this.multiplayerSessionId = json.sessionId
|
||||
}
|
||||
if ('xPos' in json && !this.isWaitingForPlayerMove) {
|
||||
this.makeMove(json.xPos, this.getEnnemyColor())
|
||||
this.setPlayerTurn(true)
|
||||
}
|
||||
if ('gameStarted' in json) {
|
||||
console.log('Game Started in multiplayer')
|
||||
if (this.onMultiStart) {
|
||||
this.onMultiStart()
|
||||
}
|
||||
this.gameType = 'multi'
|
||||
this.gameStarted = true
|
||||
this.isWaitingForPlayerMove = json.startGame
|
||||
}
|
||||
if ('gameStopped' in json) {
|
||||
console.log('The other player has left the session')
|
||||
this.resetGame()
|
||||
}
|
||||
if ('continue' in json) {
|
||||
this.continueGame()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fermeture d'une session multijoueur
|
||||
*/
|
||||
public cleanMultiplayer() {
|
||||
this.ws?.close()
|
||||
}
|
||||
/**
|
||||
* Création d'une session multijoueur
|
||||
*/
|
||||
|
||||
public setupMultiplayer() {
|
||||
this.ws = new WebSocket(`ws://${window.location.hostname}:8080`)
|
||||
this.ws.onmessage = this.onWebSocket
|
||||
}
|
||||
|
||||
/**
|
||||
* Création d'une partie multijoueur
|
||||
*/
|
||||
public createMultiplayerGame() {
|
||||
if (!this.ws) {
|
||||
throw new Error('WebSocket Error')
|
||||
}
|
||||
this.ws.send(JSON.stringify({ type: 'request' }))
|
||||
return new Promise<number>((res, rej) => {
|
||||
setTimeout(() => {
|
||||
if (!this.multiplayerSessionId) {
|
||||
return
|
||||
}
|
||||
res(this.multiplayerSessionId)
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
|
||||
public isWaitingForPlayerMove = false
|
||||
public playerColor: 'red' | 'yellow' = 'red'
|
||||
public gameType: 'single' | 'multi' = 'single'
|
||||
/**
|
||||
*
|
||||
* Cette fonction permet de rejoindre la partie créer par un utilisateur
|
||||
*/
|
||||
|
||||
public startSinglePlayer() {
|
||||
this.gameStarted = true
|
||||
this.isWaitingForPlayerMove = true
|
||||
public joinMultiplayerGame(sessionId: number) {
|
||||
if (!this.ws) {
|
||||
throw new Error('WebSocket Error')
|
||||
}
|
||||
this.ws.send(JSON.stringify({ type: 'join', id: sessionId }))
|
||||
}
|
||||
/**
|
||||
* Attribution des couleurs
|
||||
*/
|
||||
private getEnnemyColor() {
|
||||
return this.playerColor === 'red' ? 'yellow' : 'red'
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestion du tour du joueur
|
||||
*/
|
||||
public setPlayerTurn(player: boolean) {
|
||||
const playerShower = DOMElement.get('.playerColor')
|
||||
if (!playerShower) {
|
||||
return
|
||||
}
|
||||
playerShower.text(player ? this.playerColor : this.playerColor === 'red' ? 'yellow' : 'red')
|
||||
playerShower.text(player ? this.playerColor : this.getEnnemyColor())
|
||||
if (player) {
|
||||
this.isWaitingForPlayerMove = true
|
||||
} else {
|
||||
@ -84,26 +221,32 @@ export default class Game {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public setupMultiplayer() { }
|
||||
|
||||
/**
|
||||
* Gestion de l'état des actions du joueur
|
||||
*/
|
||||
public onPlayerMove(cell: DOMElement, xPos: number) {
|
||||
console.log(this.playerColor)
|
||||
if (this.isWaitingForPlayerMove) {
|
||||
this.isWaitingForPlayerMove = !this.makeMove(xPos, this.playerColor)
|
||||
if (this.isWaitingForPlayerMove) {
|
||||
return
|
||||
}
|
||||
if (this.gameType === 'single' && this.gameStarted) {
|
||||
if (this.gameStarted) {
|
||||
this.setPlayerTurn(false)
|
||||
}
|
||||
if (this.ws && this.multiplayerSessionId) {
|
||||
this.ws.send(JSON.stringify({ type: 'proxy', id: this.multiplayerSessionId, xPos }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Make a move and return and true if the move was done and false if the move was not done
|
||||
* Action de placement de jeton dans le jeu
|
||||
*/
|
||||
public makeMove(xPos: number, color: 'red' | 'yellow'): boolean {
|
||||
|
||||
console.log(color)
|
||||
let cellToFill: DOMElement | undefined
|
||||
let yPos = 0
|
||||
for (let i = 0; i < this.columns[xPos].length; i++) {
|
||||
@ -118,7 +261,6 @@ export default class Game {
|
||||
}
|
||||
|
||||
}
|
||||
console.log('cellToFill', cellToFill)
|
||||
if (!cellToFill) {
|
||||
return false
|
||||
}
|
||||
@ -127,19 +269,84 @@ export default class Game {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gestion des conditions de victoire
|
||||
*
|
||||
*/
|
||||
public checkWinner(x: number, y: number) {
|
||||
const win = this.checkDirection(x, y, 'horizontal') || this.checkDirection(x, y, 'vertical') || this.checkDirection(x, y, 'diagonal-left') || this.checkDirection(x, y, 'diagonal-right')
|
||||
const isFull = this.isFull()
|
||||
if (win === false) {
|
||||
console.log('FALSE')
|
||||
if (isFull) {
|
||||
if (this.onWin) {
|
||||
this.onWin(undefined)
|
||||
}
|
||||
this.gameStarted = false
|
||||
console.log('Egalité')
|
||||
return
|
||||
}
|
||||
console.log('no winner currently')
|
||||
return false
|
||||
}
|
||||
|
||||
this.gameStarted = false
|
||||
|
||||
console.log(win)
|
||||
const clr = win[0].data('color') as 'red'
|
||||
if (this.onWin) {
|
||||
this.onWin(clr || undefined)
|
||||
}
|
||||
if (clr === this.getEnnemyColor()) {
|
||||
this.pointsJ2++
|
||||
} else {
|
||||
this.pointsJ1++
|
||||
}
|
||||
this.updatePoints()
|
||||
win.forEach((item) => {
|
||||
console.log(item.data('winner', 'true'))
|
||||
})
|
||||
this.gameStarted = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestion de colonne remplie
|
||||
*/
|
||||
public isFull() {
|
||||
for (const col of this.columns) {
|
||||
for (const cell of col) {
|
||||
const clr = cell.data('color')
|
||||
if (!clr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestion du tableau de jeu lors de relance de partie
|
||||
*/
|
||||
public continueGame() {
|
||||
this.clearTable()
|
||||
if (this.ws && this.gameType === 'multi' && !this.gameStarted) {
|
||||
this.ws.send(JSON.stringify({ type: 'proxy', id: this.multiplayerSessionId, continue: true }))
|
||||
}
|
||||
this.gameStarted = true
|
||||
if (this.gameType === 'single' && !this.isWaitingForPlayerMove) {
|
||||
this.makeIATakeTurn()
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Attribution des points
|
||||
*/
|
||||
private updatePoints() {
|
||||
DOMElement.get('.j1p')?.text(this.pointsJ1 + '')
|
||||
DOMElement.get('.j2p')?.text(this.pointsJ2 + '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification des conditions de victoires
|
||||
*/
|
||||
public checkDirection(x: number, y: number, direction: 'horizontal' | 'vertical' | 'diagonal-left' | 'diagonal-right'): Array<DOMElement> | false {
|
||||
console.log('Starting Check', direction)
|
||||
const color = this.columns[x][y].data('color')
|
||||
@ -161,8 +368,7 @@ export default class Game {
|
||||
newY = typeof wentReverse !== 'undefined' ? y + i - wentReverse : y - i
|
||||
}
|
||||
|
||||
console.log('index', i, 'y', newY, 'Y exist', this.isYCorrect(newY))
|
||||
console.log('index', i, 'x', newX, 'X exist', this.isXCorrect(newX))
|
||||
|
||||
|
||||
if (!this.isYCorrect(newY) || !this.isXCorrect(newX)) {
|
||||
if (typeof wentReverse === 'undefined') {
|
||||
@ -173,7 +379,6 @@ export default class Game {
|
||||
}
|
||||
const element = this.columns[newX][newY]
|
||||
|
||||
console.log('element color', element.data('color'), 'color wanted', color)
|
||||
|
||||
if (element.data('color') !== color) {
|
||||
if (typeof wentReverse === 'undefined') {
|
||||
@ -186,14 +391,22 @@ export default class Game {
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification des placement de jetons verticaux
|
||||
*/
|
||||
private isXCorrect(x: number) {
|
||||
return x >= 0 && x < this.columns.length
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification des placement de jetons horizontaux
|
||||
*/
|
||||
private isYCorrect(y: number) {
|
||||
return y >= 0 && y < this.columns[0].length
|
||||
}
|
||||
/**
|
||||
* Gestion de l'IA
|
||||
*/
|
||||
|
||||
public makeIATakeTurn() {
|
||||
let turnDone = false
|
||||
@ -201,16 +414,17 @@ export default class Game {
|
||||
const pos = getRandomInt(0, this.columns.length - 1)
|
||||
turnDone = this.makeMove(pos, 'red')
|
||||
}
|
||||
this.setPlayerTurn(true)
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Création de number Aléatoire
|
||||
*/
|
||||
function getRandomInt(min: number, max: number) {
|
||||
return Math.floor(Math.random() * ((max + 1) - min)) + min
|
||||
}
|
||||
|
||||
|
||||
|
||||
// const cell = new DOMElement('tr')
|
||||
|
||||
// cell.data('color') // return 'red | 'yello' pour get
|
||||
// cell.data('color', 'red') //return void pour set
|
||||
|
@ -2,71 +2,42 @@
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Puissance 4</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Tour du joueur <span class="playerColor"></span></div>
|
||||
<button class="restartBtn">Recommencer</button>
|
||||
<h1>Puissance 4</h1>
|
||||
|
||||
<div class="chooseSetup">
|
||||
<button class="vsAI">Jouer contre une IA</button>
|
||||
<button class="vsPlayer">Jouer contre un joueur en ligne</button>
|
||||
</div>
|
||||
<div id="usermessage" style="display: none">Donnez ce code au deuxieme joueur</div>
|
||||
|
||||
<div class="playerOption" style="display: none">
|
||||
|
||||
<button class="createSession">Créer une Session</button>
|
||||
<input type="number" id="sessionID" required min="100" max="999" />
|
||||
<button class="joinSession">Rejoindre une Session</button>
|
||||
<button id="backInMenu">retour au menu</button>
|
||||
</div>
|
||||
<div class="giveUp" style="display: none">
|
||||
<button class="restartBtn">Arrêter</button>
|
||||
<button class="continueBtn" style="display:none">Nouvelle Manche</button>
|
||||
</div>
|
||||
<div class="tableContainer">
|
||||
<table>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>3</td>
|
||||
<td>3</td>
|
||||
<td>3</td>
|
||||
<td>3</td>
|
||||
<td>3</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td>5</td>
|
||||
<td>5</td>
|
||||
<td>5</td>
|
||||
<td>5</td>
|
||||
<td>5</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>6</td>
|
||||
<td>6</td>
|
||||
<td>6</td>
|
||||
<td>6</td>
|
||||
<td>6</td>
|
||||
<td>6</td>
|
||||
<td>6</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="stateOfGame">
|
||||
<div class="victoire"></div>
|
||||
<div>Tour du joueur <span class="playerColor"></span></div>
|
||||
<div>Vos points <span class="j1p">0</span></div>
|
||||
<div>Points Adversaire <span class="j2p">0</span></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<script src="./main.ts"></script>
|
||||
|
@ -3,6 +3,9 @@ import './style.css'
|
||||
import Game from './Game'
|
||||
import { DOMElement } from '@dzeio/dom-manager'
|
||||
|
||||
/**
|
||||
* Mise en place de l'environnement de jeu
|
||||
*/
|
||||
const table = document.querySelector('table')
|
||||
|
||||
if (!table) {
|
||||
@ -10,16 +13,134 @@ if (!table) {
|
||||
}
|
||||
|
||||
const game = new Game(table)
|
||||
const restartBtn = DOMElement.get('.restartBtn')
|
||||
if (restartBtn) {
|
||||
game.setRestartButton(restartBtn)
|
||||
}
|
||||
|
||||
game.playerColor = 'yellow'
|
||||
game.startSinglePlayer()
|
||||
|
||||
/**
|
||||
* Récupération des éléments nécéssaires
|
||||
*/
|
||||
|
||||
const btnWrapper = DOMElement.get('.chooseSetup')
|
||||
const multiplayerOptions = DOMElement.get('.playerOption')
|
||||
const input = DOMElement.get<HTMLInputElement>('#sessionID')
|
||||
const giveUpWrapper = DOMElement.get('.giveUp')
|
||||
const btnJoinGame = DOMElement.get('.joinSession')
|
||||
const btnCreateGame = DOMElement.get('.createSession')
|
||||
const btnBackInMenu = DOMElement.get('#backInMenu')
|
||||
const userMessage = DOMElement.get('#usermessage')
|
||||
const messageVictoire = DOMElement.get('.victoire')
|
||||
const continueBtn = DOMElement.get('.continueBtn')
|
||||
|
||||
|
||||
const ws = new WebSocket('ws://localhost:8080')
|
||||
ws.onmessage = (event) => {
|
||||
console.log(event.data)
|
||||
/**
|
||||
* Comportement du DOM lors du reset de la partie
|
||||
*/
|
||||
game.onReset = () => {
|
||||
btnWrapper?.style('display', '')
|
||||
multiplayerOptions?.style('display', 'none')
|
||||
giveUpWrapper?.style('display', 'none')
|
||||
messageVictoire?.text('')
|
||||
continueBtn?.style('display', 'none')
|
||||
}
|
||||
|
||||
/**
|
||||
* Comportement du DOM lors d'une victoire
|
||||
*/
|
||||
game.onWin = (winner) => {
|
||||
console.log(winner)
|
||||
if (!winner) {
|
||||
messageVictoire?.text('Égalité !')
|
||||
} else {
|
||||
messageVictoire?.text(`Le Joueur ${winner} à gagné !`)
|
||||
}
|
||||
continueBtn?.style('display', '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Comportement du DOM lors du lancement d'une partie
|
||||
*/
|
||||
game.onMultiStart = () => {
|
||||
giveUpWrapper?.style('display', '')
|
||||
multiplayerOptions?.style('display', 'none')
|
||||
userMessage?.style('display', 'none')
|
||||
}
|
||||
/**
|
||||
* Comportement du DOM et du jeu lorsqu'un utilisateur rejoins une partie
|
||||
*/
|
||||
btnJoinGame?.on('click', () => {
|
||||
const numberSession = input?.item.valueAsNumber || 0
|
||||
game.joinMultiplayerGame(numberSession)
|
||||
})
|
||||
|
||||
/**
|
||||
* Comportement du DOM et du jeu lorsqu'un utilisateur créer une partie
|
||||
*/
|
||||
|
||||
btnCreateGame?.on('click', async () => {
|
||||
const id = await game.createMultiplayerGame()
|
||||
if (!input) {
|
||||
return
|
||||
}
|
||||
input.item.valueAsNumber = id
|
||||
input.attr('readOnly', true)
|
||||
userMessage?.style('display', '')
|
||||
btnCreateGame?.style('display', 'none')
|
||||
btnJoinGame?.style('display', 'none')
|
||||
|
||||
})
|
||||
/**
|
||||
* Comportement du DOM et du jeu lorsqu'un utilisateur relance une partie
|
||||
*/
|
||||
|
||||
continueBtn?.on('click', () => {
|
||||
game.continueGame()
|
||||
messageVictoire?.text('')
|
||||
continueBtn?.style('display', 'none')
|
||||
})
|
||||
|
||||
/**
|
||||
* Comportement du DOMlorsqu'un utilisateur retourne sur le menu
|
||||
*/
|
||||
DOMElement.get('#backInMenu', multiplayerOptions)?.on('click', () => {
|
||||
btnWrapper?.style('display', 'flex')
|
||||
btnBackInMenu?.style('display', 'none')
|
||||
btnCreateGame?.style('display', 'flex')
|
||||
userMessage?.style('display', 'none')
|
||||
|
||||
multiplayerOptions?.style('display', 'none')
|
||||
game.cleanMultiplayer()
|
||||
})
|
||||
/**
|
||||
* Comportement du DOM et du jeu lorsqu'un utilisateur lance une partie contre l'IA
|
||||
*/
|
||||
|
||||
DOMElement.get('.vsAI', btnWrapper)?.on('click', () => {
|
||||
game.startSinglePlayer()
|
||||
btnWrapper?.style('display', 'none')
|
||||
giveUpWrapper?.style('display', '')
|
||||
userMessage?.style('display', 'none')
|
||||
})
|
||||
|
||||
/**
|
||||
* Comportement du DOM et du jeu lorsqu'un utilisateur souhaite lancer une partie en multijoueur
|
||||
*/
|
||||
DOMElement.get('.vsPlayer', btnWrapper)?.on('click', () => {
|
||||
multiplayerOptions?.style('display', 'flex')
|
||||
btnJoinGame?.style('display', 'flex')
|
||||
|
||||
game.setupMultiplayer()
|
||||
btnWrapper?.style('display', 'none')
|
||||
multiplayerOptions?.style('display', '')
|
||||
if (input?.item) {
|
||||
input.item.value = ''
|
||||
}
|
||||
btnBackInMenu?.style('display', 'flex')
|
||||
|
||||
})
|
||||
/**
|
||||
* Comportement du DOM et du jeu lorsqu'un utilisateur recommence une partie
|
||||
*/
|
||||
const restartBtn = DOMElement.get('.restartBtn')?.on('click', () => {
|
||||
game.resetGame()
|
||||
})
|
||||
|
||||
window.game = game
|
||||
|
@ -8,12 +8,25 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40rem;
|
||||
}
|
||||
|
||||
table {
|
||||
height: 45rem;
|
||||
border: 2px solid;
|
||||
margin-top: 10rem;
|
||||
}
|
||||
|
||||
.chooseSetup,
|
||||
.playerOption,
|
||||
.giveUp {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr {
|
||||
@ -21,10 +34,19 @@ tr {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
#usermessage {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#backInMenu {
|
||||
display: none
|
||||
}
|
||||
|
||||
td {
|
||||
border-radius: 100%;
|
||||
border: 1px solid;
|
||||
height: 10px;
|
||||
width: 20px;
|
||||
height: 7rem;
|
||||
width: 7rem;
|
||||
}
|
||||
|
||||
td[data-color="red"] {
|
||||
@ -38,3 +60,11 @@ td[data-color="yellow"] {
|
||||
td[data-winner="true"] {
|
||||
background: gold
|
||||
}
|
||||
|
||||
.stateOfGame {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 10rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
1
launch.bat
Normal file
1
launch.bat
Normal file
@ -0,0 +1 @@
|
||||
npm run start
|
103
main.ts
103
main.ts
@ -2,20 +2,30 @@ import express from 'express'
|
||||
import WebSocket from './Websocket'
|
||||
import Connection from './Connection'
|
||||
|
||||
/**
|
||||
* Création de l'interface Comm
|
||||
*/
|
||||
interface Comm {
|
||||
type?: 'request' | 'join' | 'proxy'
|
||||
id?: number
|
||||
xPos?: number
|
||||
continue?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Mise en place du framework express
|
||||
*/
|
||||
const app = express();
|
||||
|
||||
app.use(express.static('public'))
|
||||
|
||||
/**
|
||||
* Création du serveur
|
||||
*/
|
||||
var server = app.listen(3000, function () {
|
||||
|
||||
const wsServer = new WebSocket({ port: 8080 })
|
||||
|
||||
/**
|
||||
*Lecture des différents messages reçu en fonctions de leurs types
|
||||
*/
|
||||
wsServer.on('connection', (conn) => {
|
||||
conn.send({ ok: true })
|
||||
conn.on('message', (message: Comm | string) => {
|
||||
@ -31,30 +41,103 @@ var server = app.listen(3000, function () {
|
||||
joinSession(conn, message.id)
|
||||
}
|
||||
|
||||
if (message?.type === 'proxy' && message?.xPos) {
|
||||
proxyRequest(conn, message.xPos)
|
||||
if (message?.type === 'proxy' && typeof message.xPos === 'number' && message?.id) {
|
||||
proxyRequest(conn, message.id, message.xPos)
|
||||
}
|
||||
|
||||
if (message?.type === 'proxy' && typeof message.xPos === 'number' && message?.id) {
|
||||
proxyRequest(conn, message.id, message.xPos)
|
||||
}
|
||||
|
||||
if (message?.type === 'proxy' && message.continue && message?.id) {
|
||||
proxyContinue(conn, message.id)
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
console.log(`Example app listening at http://localhost:3000`);
|
||||
});
|
||||
|
||||
const currentSessions: Array<Array<Connection>> = []
|
||||
|
||||
/**
|
||||
*
|
||||
* Création de session de jeu et identification de celle ci par un code
|
||||
*/
|
||||
function handleRequest(conn: Connection) {
|
||||
// Générer un nombre aléatoire entre 100 et 999 et on vérifie qu'il n'y a pas déja de parti avec cette ID
|
||||
let n: number
|
||||
do {
|
||||
n = getRandomInt(100, 999)
|
||||
} while (currentSessions[n] !== undefined);
|
||||
|
||||
// Rajouter la connection a cette partie
|
||||
|
||||
// renvoie au client l'ID
|
||||
joinSession(conn, n)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Cette fonction permet de joindre une session créer par handleRequest
|
||||
*
|
||||
*
|
||||
*/
|
||||
function joinSession(conn: Connection, session: number) {
|
||||
// Rajouter la connection a cette partie
|
||||
|
||||
if (!currentSessions[session]) {
|
||||
currentSessions[session] = []
|
||||
}
|
||||
if (currentSessions[session].length >= 2) {
|
||||
return conn.send({ joined: false, reason: 'lobby full' })
|
||||
}
|
||||
currentSessions[session].push(conn)
|
||||
conn.once('close', () => {
|
||||
console.log('closing session')
|
||||
const index = currentSessions[session].indexOf(conn)
|
||||
currentSessions[session].splice(index, 1)
|
||||
currentSessions[session].forEach((c) => c.send(JSON.stringify({ gameStopped: true })))
|
||||
if (currentSessions[session].length === 0) {
|
||||
delete currentSessions[session]
|
||||
}
|
||||
})
|
||||
// renvoie au client l'ID
|
||||
conn.send({ sessionId: session, joined: true })
|
||||
|
||||
if (currentSessions[session].length === 2) {
|
||||
for (const connection of currentSessions[session]) {
|
||||
connection.send({ gameStarted: true, startGame: connection !== conn })
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Permet d'envoyer le mouvement fait par le joueur actif
|
||||
*/
|
||||
function proxyRequest(conn: Connection, session: number, xPos: number) {
|
||||
// Renvoyer a tout les clients du meme ID le xPos
|
||||
for (const connection of currentSessions[session]) {
|
||||
if (conn === connection) {
|
||||
continue
|
||||
}
|
||||
connection.send({ xPos })
|
||||
}
|
||||
}
|
||||
|
||||
function proxyRequest(conn: Connection, xPos: number) {
|
||||
// renvoyer a tout les clients du meme ID le xPos
|
||||
/**
|
||||
* Création de la nouvelle manche, sans redémarrer la partie
|
||||
*
|
||||
*/
|
||||
function proxyContinue(conn: Connection, session: number) {
|
||||
// Renvoyer a tout les clients du meme ID le xPos
|
||||
for (const connection of currentSessions[session]) {
|
||||
if (conn === connection) {
|
||||
continue
|
||||
}
|
||||
connection.send({ continue: true })
|
||||
}
|
||||
}
|
||||
/**
|
||||
*Création d'un chiffre aléatoire
|
||||
*/
|
||||
function getRandomInt(min: number, max: number) {
|
||||
return Math.floor(Math.random() * ((max + 1) - min)) + min
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Puissance 4</title><link rel="stylesheet" href="/main.491056a1.css"></head><body> <div>Tour du joueur <span class="playerColor"></span></div> <button class="restartBtn">Recommencer</button> <div class="tableContainer"> <table> <tr> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> </tr> <tr> <td>2</td> <td>2</td> <td>2</td> <td>2</td> <td>2</td> <td>2</td> <td>2</td> </tr> <tr> <td>3</td> <td>3</td> <td>3</td> <td>3</td> <td>3</td> <td>3</td> <td>3</td> </tr> <tr> <td>4</td> <td>4</td> <td>4</td> <td>4</td> <td>4</td> <td>4</td> <td>4</td> </tr> <tr> <td>5</td> <td>5</td> <td>5</td> <td>5</td> <td>5</td> <td>5</td> <td>5</td> </tr> <tr> <td>6</td> <td>6</td> <td>6</td> <td>6</td> <td>6</td> <td>6</td> <td>6</td> </tr> </table> </div> </body><script src="/main.6ae8f54c.js"></script></html>
|
||||
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Puissance 4</title><link rel="stylesheet" href="/main.0dd87d91.css"></head><body> <h1>Puissance 4</h1> <div class="chooseSetup"> <button class="vsAI">contre ia</button> <button class="vsPlayer">multijoueur</button> </div> <div id="usermessage"></div> <div class="playerOption" style="display:none"> <button class="createSession">Create Session</button> <input type="number" id="sessionID" required="" min="100" max="999"> <button class="joinSession">Join Session</button> <button id="backInMenu">retour au menu</button> </div> <div class="giveUp" style="display:none"> <button class="restartBtn">Abandonner</button> <button class="continueBtn">Nouvelle Manche</button> </div> <div class="tableContainer"> <table> </table> </div> <div class="stateOfGame"> <div>Tour du joueur <span class="playerColor"></span></div> <div>Vos points <span class="j1p">0</span></div> <div>Points Adversaire <span class="j2p">0</span></div> </div> </body><script src="/main.41fb9c97.js"></script></html>
|
Loading…
x
Reference in New Issue
Block a user