Renommage assets > /public + Refonte logique et interface de jeu
|
Before Width: | Height: | Size: 169 B After Width: | Height: | Size: 169 B |
|
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 179 B |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 163 B After Width: | Height: | Size: 163 B |
|
Before Width: | Height: | Size: 162 B After Width: | Height: | Size: 162 B |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 160 B After Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 117 B After Width: | Height: | Size: 117 B |
BIN
public/sEmpty.png
Normal file
|
After Width: | Height: | Size: 117 B |
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 184 B |
|
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 221 B |
|
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 232 B |
|
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 195 B |
|
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 131 B |
|
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 702 B |
|
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 141 B |
@@ -6,27 +6,27 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'home',
|
||||||
component: () => import('../views/HomeView.vue')
|
component: () => import('@/views/HomeView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
name: 'about',
|
name: 'about',
|
||||||
component: () => import('../views/AboutView.vue')
|
component: () => import('@/views/AboutView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/game',
|
path: '/game',
|
||||||
name: 'game',
|
name: 'game',
|
||||||
component: () => import('../views/GameView.vue'),
|
component: () => import('@/views/GameView.vue'),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'solo',
|
path: 'solo',
|
||||||
name: 'solo',
|
name: 'solo',
|
||||||
component: () => import('../views/Game/SoloView.vue')
|
component: () => import('@/views/Game/SoloView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'party',
|
path: 'party',
|
||||||
name: 'party',
|
name: 'party',
|
||||||
component: () => import('../views/Game/PartyView.vue')
|
component: () => import('@/views/Game/PartyView.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,46 @@
|
|||||||
|
type CellGrid = string[][] // type CellGrid (grille de jeu)
|
||||||
|
type MineGrid = number[][] // type MineGrid (grille de bombes)
|
||||||
|
|
||||||
|
function genCellGrid(width: number, length: number): CellGrid { // fonction genCellGrid (génération de la grille de jeu)
|
||||||
|
return Array.from({ length: width }, () => Array.from({ length: length }, () => "/sUnknown.png"))
|
||||||
|
}
|
||||||
|
|
||||||
|
function genMineGrid(width: number, length: number, nbMines: number): MineGrid { // fonction genMineGrid (génération des bombes)
|
||||||
|
const mineGrid: MineGrid = [] // initialisation de la grille de bombes
|
||||||
|
while (mineGrid.length < nbMines) { // boucle pour placer les bombes
|
||||||
|
const x = Math.floor(Math.random() * length) // position x de la bombe
|
||||||
|
const y = Math.floor(Math.random() * width) // position y de la bombe
|
||||||
|
const indice = [y, x] // id de la bombe
|
||||||
|
if (!mineGrid.includes(indice)) mineGrid.push(indice) // si la bombe n'est pas déjà placée, on la place
|
||||||
|
}
|
||||||
|
return mineGrid; // retour de la grille de bombes
|
||||||
|
}
|
||||||
|
|
||||||
|
function cliqueGauche(cellGrid: CellGrid, mineGrid: MineGrid, x: number, y: number) { // fonction main (début du jeu)
|
||||||
|
//const indice = [y, x] // id de la case cliquée
|
||||||
|
//if (mineGrid.includes(indice)) bombe() // si la case cliquée est une bombe, on va dans la fonction bombe
|
||||||
|
//else if (champDeMines[indice] === 0) {caseVide(indice);} // si la case cliquée est vide, on va dans la fonction caseVide
|
||||||
|
//else if (champDeMines[indice] !== 0) {decouvreCase(indice);} // si la case cliquée est un numéro, on va dans la fonction decouvreCase
|
||||||
|
//decouvreCase(indice);
|
||||||
|
if (cellGrid[y][x] === '/sClick.png') return cellGrid[y][x] = '/sEmpty.png' // modification de l'image de la case
|
||||||
|
}
|
||||||
|
|
||||||
|
function cliqueDroit(cellGrid: string[][], x: number, y: number): void { // fonction cliqueDroit (flag d'une case) // modification de l'image de la case
|
||||||
|
switch (cellGrid[y][x]) {
|
||||||
|
case '/sUnknown.png':
|
||||||
|
cellGrid[y][x] = "/sFlag.png"
|
||||||
|
break
|
||||||
|
case '/sFlag.png':
|
||||||
|
cellGrid[y][x] = "/sQuestion.png"
|
||||||
|
break
|
||||||
|
case '/sQuestion.png':
|
||||||
|
cellGrid[y][x] = "/sUnknown.png"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
const directions: number[] = [-11, -10, -9, -1, 1, 9, 10, 11]; // directions possibles pour découvrir les cases
|
const directions: number[] = [-11, -10, -9, -1, 1, 9, 10, 11]; // directions possibles pour découvrir les cases
|
||||||
const champDeMines: number[] = []; // champ de mines (0 = case vide, 10 = bombe, 1 à 8 = nombre de bombes adjacentes)
|
const champDeMines: number[] = []; // champ de mines (0 = case vide, 10 = bombe, 1 à 8 = nombre de bombes adjacentes)
|
||||||
for (let i = 0; i < 100; i++) {champDeMines.push(0);} // initialisation des cases à 0
|
for (let i = 0; i < 100; i++) {champDeMines.push(0);} // initialisation des cases à 0
|
||||||
@@ -19,18 +62,7 @@ function caseVide(indice: number): void {
|
|||||||
function decouvreCase(indice: number): void { // fonction decouvreCase (découverte d'une case)
|
function decouvreCase(indice: number): void { // fonction decouvreCase (découverte d'une case)
|
||||||
casesDecouvertes[indice] = 1; // modification dans le tableau des cases découvertes
|
casesDecouvertes[indice] = 1; // modification dans le tableau des cases découvertes
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
function flagCase(indice: number): void { // fonction flagCase (flag d'une case)
|
export { genCellGrid, genMineGrid, cliqueGauche, cliqueDroit } // export des variables et fonctions
|
||||||
casesDecouvertes[indice] = 2; // modification dans le tableau des cases découvertes
|
export type { CellGrid, MineGrid } // export des types
|
||||||
}
|
|
||||||
|
|
||||||
function cliqueGauche(indice: number): void { // fonction main (début du jeu)
|
|
||||||
if (champDeMines[indice] === 10) {bombe();} // si la case cliquée est une bombe, on va dans la fonction bombe
|
|
||||||
else if (champDeMines[indice] === 0) {caseVide(indice);} // si la case cliquée est vide, on va dans la fonction caseVide
|
|
||||||
else if (champDeMines[indice] !== 0) {decouvreCase(indice);} // si la case cliquée est un numéro, on va dans la fonction decouvreCase
|
|
||||||
decouvreCase(indice);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cliqueDroite(indice: number): void { // fonction cliqueDroite (flag d'une case)
|
|
||||||
flagCase(indice);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,101 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { genCellGrid, genMineGrid, cliqueGauche, cliqueDroit } from '@/utils/game'
|
||||||
|
import type { CellGrid, MineGrid } from '@/utils/game'
|
||||||
|
|
||||||
|
const width = 10
|
||||||
|
const length = 15
|
||||||
|
const nbMines = 25
|
||||||
|
|
||||||
|
// Création grille des cases
|
||||||
|
const cellGrid = ref<CellGrid>([])
|
||||||
|
cellGrid.value = genCellGrid(width, length)
|
||||||
|
|
||||||
|
// Création grille des mines
|
||||||
|
let mineGrid: MineGrid = []
|
||||||
|
mineGrid = genMineGrid(width, length, nbMines)
|
||||||
|
|
||||||
|
// État pour gérer le clic et la position de la cellule
|
||||||
|
const isMouseDown = ref(false)
|
||||||
|
const currentCell = ref<{ rowIndex: number, cellIndex: number } | null>(null)
|
||||||
|
|
||||||
|
const handleMouseDown = (rowIndex: number, cellIndex: number) => {
|
||||||
|
isMouseDown.value = true
|
||||||
|
currentCell.value = { rowIndex, cellIndex }
|
||||||
|
if (cellGrid.value[rowIndex][cellIndex] === '/sUnknown.png') cellGrid.value[rowIndex][cellIndex] = '/sClick.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseUp = (rowIndex: number, cellIndex: number) => {
|
||||||
|
isMouseDown.value = false
|
||||||
|
cliqueGauche(cellGrid.value, mineGrid, cellIndex, rowIndex)
|
||||||
|
currentCell.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseMove = (rowIndex: number, cellIndex: number) => {
|
||||||
|
if (isMouseDown.value && currentCell.value) {
|
||||||
|
const { rowIndex: prevRowIndex, cellIndex: prevCellIndex } = currentCell.value
|
||||||
|
if (prevRowIndex !== rowIndex || prevCellIndex !== cellIndex) {
|
||||||
|
if (cellGrid.value[prevRowIndex][prevCellIndex] === '/sClick.png') cellGrid.value[prevRowIndex][prevCellIndex] = '/sUnknown.png' // Réinitialiser l'image précédente
|
||||||
|
if (cellGrid.value[rowIndex][cellIndex] === '/sUnknown.png') cellGrid.value[rowIndex][cellIndex] = '/sClick.png' // Changer l'image actuelle
|
||||||
|
currentCell.value = { rowIndex, cellIndex }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGlobalMouseMove = (event: MouseEvent) => {
|
||||||
|
if (isMouseDown.value && currentCell.value) {
|
||||||
|
const target = event.target as HTMLElement
|
||||||
|
if (!target.classList.contains('cell')) {
|
||||||
|
const { rowIndex, cellIndex } = currentCell.value
|
||||||
|
if (cellGrid.value[rowIndex][cellIndex] === '/sClick.png') {
|
||||||
|
cellGrid.value[rowIndex][cellIndex] = '/sUnknown.png'
|
||||||
|
}
|
||||||
|
currentCell.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener('mousemove', handleGlobalMouseMove))
|
||||||
|
onUnmounted(() => document.removeEventListener('mousemove', handleGlobalMouseMove))
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<h1>Solo</h1>
|
<h1>Solo</h1>
|
||||||
|
<div class="grid">
|
||||||
|
<div v-for="(row, rowIndex) in cellGrid" :key="rowIndex" class="row">
|
||||||
|
<div v-for="(cell, cellIndex) in row" :key="cellIndex">
|
||||||
|
<img class="cell" :src="cell"
|
||||||
|
@mousedown.right="cliqueDroit(cellGrid, cellIndex, rowIndex)"
|
||||||
|
@mousedown.left="handleMouseDown(rowIndex, cellIndex)"
|
||||||
|
@mouseup.left="handleMouseUp(rowIndex, cellIndex)"
|
||||||
|
@mousemove="handleMouseMove(rowIndex, cellIndex)"
|
||||||
|
@contextmenu.prevent
|
||||||
|
@select.prevent
|
||||||
|
draggable="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
border: 10px solid black;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
.cell {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<h1>MultiMinesweeper</h1>
|
<h1>MultiMinesweeper</h1>
|
||||||
<p>
|
<p>
|
||||||
Bienvenue sur notre jeu !
|
Bienvenue sur notre jeu de démineur en ligne !
|
||||||
<br>
|
<br>
|
||||||
Pour jouer, il vous suffit de sélectionner le mode de jeu que vous souhaitez dans le menu ci-dessous.
|
Pour jouer, il vous suffit de sélectionner le mode de jeu que vous souhaitez dans le menu ci-dessous.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||