From e833e403f77b10ff4c849025387a0edb676e1b97 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 | 78 ++++++++++- frontend/src/router/index.js | 31 +++++ frontend/src/stores/bisca.js | 127 ++++++++++++++++++ frontend/src/stores/game.js | 8 -- 6 files changed, 283 insertions(+), 12 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 @@ + + + diff --git a/frontend/src/pages/home/HomePage.vue b/frontend/src/pages/home/HomePage.vue index 42f95c7..8f120c0 100644 --- a/frontend/src/pages/home/HomePage.vue +++ b/frontend/src/pages/home/HomePage.vue @@ -1,11 +1,85 @@ -` \ No newline at end of file + diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index b75364d..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), @@ -19,6 +21,20 @@ const router = createRouter({ path: '/login', component: LoginPage, }, + { + 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', children: [ @@ -51,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', () => { - -})