From e68f1357ccf82bd26395428c78c0276a4e2cd465 Mon Sep 17 00:00:00 2001 From: Tiago Ramos <2222055@my.ipleiria.pt> Date: Tue, 23 Dec 2025 00:18:34 +0000 Subject: [PATCH] Added game start for single player, 3 and 9 card game types and protected the pages for only logged in players --- frontend/src/components/game/GameBoard.vue | 8 +- .../src/pages/game/SinglePlayerGamePage.vue | 43 +++++ frontend/src/pages/home/HomePage.vue | 182 ++++++++---------- frontend/src/router/index.js | 31 ++- frontend/src/stores/bisca.js | 127 ++++++++++++ frontend/src/stores/game.js | 8 - 6 files changed, 285 insertions(+), 114 deletions(-) create mode 100644 frontend/src/pages/game/SinglePlayerGamePage.vue create mode 100644 frontend/src/stores/bisca.js delete mode 100644 frontend/src/stores/game.js diff --git a/frontend/src/components/game/GameBoard.vue b/frontend/src/components/game/GameBoard.vue index 361fe8c..418f7fc 100644 --- a/frontend/src/components/game/GameBoard.vue +++ b/frontend/src/components/game/GameBoard.vue @@ -95,11 +95,11 @@ const props = defineProps({ }, playerScore: { type: Number, - default: 45, + default: 0, }, opponentScore: { type: Number, - default: 23, + default: 0, }, currentTurn: { type: String, @@ -113,4 +113,8 @@ const emit = defineEmits(['card-clicked']) const handleCardClick = (payload) => { emit('card-clicked', payload) } + +const handlePlayCard = (card) => { + store.playerPlayCard(card) +} diff --git a/frontend/src/pages/game/SinglePlayerGamePage.vue b/frontend/src/pages/game/SinglePlayerGamePage.vue new file mode 100644 index 0000000..ec6a4d6 --- /dev/null +++ b/frontend/src/pages/game/SinglePlayerGamePage.vue @@ -0,0 +1,43 @@ + + + + + + A baralhar cartas... + + + + diff --git a/frontend/src/pages/home/HomePage.vue b/frontend/src/pages/home/HomePage.vue index 5c93924..8f120c0 100644 --- a/frontend/src/pages/home/HomePage.vue +++ b/frontend/src/pages/home/HomePage.vue @@ -1,107 +1,85 @@ + + + Bisca Game + + + + Single Player + + + + Multiplayer + + + + + Escolhe o Modo + + + + Bisca de 3 + Clássico + + + + Bisca de 9 + Épico + + + + + Voltar atrás + + + + + - - - - - - Single Player - - - Test your memory by finding matching pairs! - - - - - High Scores (local) - - - - No high scores yet. Be the first! - - - - - - {{ index + 1 }} - - - {{ score.player1_points }} Moves -- {{ - score.username }} - {{ score.time }} /s - - - - - - - - - - - Start Game - - - - - - - - MultiPlayer - - - Comming Soon!! - - - - - - - - + diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 8869581..983f8fd 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -6,7 +6,9 @@ import TestAnimations from '@/pages/TestAnimations.vue' import TestDealing from '@/pages/TestDealing.vue' import TestAllAnimations from '@/pages/TestAllAnimations.vue' import TestGameBoard from '@/pages/TestGameBoard.vue' +import SinglePlayerGamePage from '@/pages/game/SinglePlayerGamePage.vue' import { createRouter, createWebHistory } from 'vue-router' +import { toast } from 'vue-sonner' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -20,8 +22,18 @@ const router = createRouter({ component: LoginPage, }, { - path: '/user', - component: UserPage, + path: '/game/3', + name: 'bisca3', + component: SinglePlayerGamePage, + props: { gameType: 3 }, + meta: { requiresAuth: true }, + }, + { + path: '/game/9', + name: 'bisca9', + component: SinglePlayerGamePage, + props: { gameType: 9 }, + meta: { requiresAuth: true }, }, { path: '/testing', @@ -55,4 +67,19 @@ const router = createRouter({ ], }) +router.beforeEach((to, from, next) => { + if (to.meta.requiresAuth) { + const token = localStorage.getItem('token') // Ou useAuthStore().token + + if (!token) { + toast.error('Acesso Negado', { + description: 'Precisas de fazer login para aceder ao jogo.', + duration: 4000, + }) + return next({ name: 'home' }) + } + } + next() +}) + export default router diff --git a/frontend/src/stores/bisca.js b/frontend/src/stores/bisca.js new file mode 100644 index 0000000..49a7c79 --- /dev/null +++ b/frontend/src/stores/bisca.js @@ -0,0 +1,127 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useBiscaStore = defineStore('bisca', () => { + const isDealing = ref(false) + const isGameRunning = ref(false) + const gameType = ref(3) + + const deck = ref([]) + const playerHand = ref([]) + const opponentHand = ref([]) + const trumpCard = ref(null) + const playerScore = ref(0) + const opponentScore = ref(0) + + const currentTurn = ref('player') + + const table = ref({ + playerCard: null, + opponentCard: null, + firstToPlay: null, + }) + + const startGame = async (type = 3) => { + if (isDealing.value) return + + isDealing.value = true + isGameRunning.value = true + gameType.value = type + + playerScore.value = 0 + opponentScore.value = 0 + + deck.value = [] + playerHand.value = [] + opponentHand.value = [] + trumpCard.value = null + + currentTurn.value = 'player' + + table.value = { + playerCard: null, + opponentCard: null, + firstToPlay: null, + } + + deck.value = createDeck() + + trumpCard.value = deck.value[0] + + await wait(500) + + await dealInitialCards() + + isDealing.value = false + } + + const dealInitialCards = async () => { + const cardsToDeal = gameType.value === 9 ? 9 : 3 + + const dealSpeed = gameType.value === 9 ? 200 : 500 + + for (let i = 0; i < cardsToDeal; i++) { + if (deck.value.length > 0) { + const card = deck.value.pop() + playerHand.value.push(card) + await wait(dealSpeed) + } + + if (deck.value.length > 0) { + const card = deck.value.pop() + opponentHand.value.push(card) + await wait(dealSpeed) + } + } + } + + const createDeck = () => { + const suits = ['c', 'e', 'o', 'p'] + const ranks = [1, 2, 3, 4, 5, 6, 7, 11, 12, 13] + let newDeck = [] + + for (const suit of suits) { + for (const rank of ranks) { + newDeck.push({ + id: `${suit}-${rank}`, + suit, + rank, + points: getPoints(rank), + strength: getStrength(rank), + }) + } + } + return newDeck.sort(() => Math.random() - 0.5) + } + + const getPoints = (rank) => { + if (rank === 1) return 11 + if (rank === 7) return 10 + if (rank === 13) return 4 + if (rank === 11) return 3 + if (rank === 12) return 2 + return 0 + } + + const getStrength = (rank) => { + const strengthMap = { 1: 10, 7: 9, 13: 8, 11: 7, 12: 6, 6: 5, 5: 4, 4: 3, 3: 2, 2: 1 } + return strengthMap[rank] || 0 + } + + const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + + return { + isDealing, + isGameRunning, + gameType, + deck, + playerHand, + opponentHand, + trumpCard, + playerScore, + opponentScore, + currentTurn, + table, + startGame, + } +}) diff --git a/frontend/src/stores/game.js b/frontend/src/stores/game.js deleted file mode 100644 index f979538..0000000 --- a/frontend/src/stores/game.js +++ /dev/null @@ -1,8 +0,0 @@ -import { defineStore } from 'pinia' -import { ref, computed } from 'vue' -import { toast } from 'vue-sonner' -import { useApiStore } from './api' - -export const useGameStore = defineStore('game', () => { - -})