Compare commits

...

10 Commits

42 changed files with 1718 additions and 9573 deletions

View File

@ -1,12 +0,0 @@
[*]
indent_style = space
indent_size = 4
[*.sass]
indent_size = 2
[*.json]
indent_size = 2
[*.yaml]
indent_size = 2

27
.gitignore vendored
View File

@ -1,21 +1,26 @@
.DS_Store # Logs
node_modules logs
/dist *.log
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files # Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea .idea
.vscode
*.suo *.suo
*.ntvs* *.ntvs*
*.njsproj *.njsproj

1
.npmrc
View File

@ -1 +0,0 @@
shamefully-hoist=true

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}

24
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,24 @@
pipeline {
agent any
environment {
PATH = "/var/lib/jenkins/.nvm/versions/node/v20.9.0/bin:/var/lib/jenkins/bin:${env.PATH}"
}
stages {
stage('Install') {
steps {
sh 'pnpm i'
}
}
stage('Build') {
steps {
sh './node_modules/.bin/vite build'
}
}
stage('Deploy') {
steps {
sh 'rm -rf /var/www/rimajon-fe/*'
sh 'cp -r ./dist/* /var/www/rimajon-fe/'
}
}
}
}

View File

@ -1,19 +1,40 @@
# rimajon # rimajon-vue
## Project setup This template should help get you started developing with Vue 3 in Vite.
```
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
pnpm install pnpm install
``` ```
### Compiles and hot-reloads for development ### Compile and Hot-Reload for Development
```
pnpm run serve ```sh
pnpm dev
``` ```
### Compiles and minifies for production ### Type-Check, Compile and Minify for Production
```
pnpm run build
```
### Customize configuration ```sh
See [Configuration Reference](https://cli.vuejs.org/config/). pnpm build
```

View File

@ -1,5 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

1
env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

19
index.html Normal file
View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RiMaJon - Mahjong con cartas</title>
<link href="https://fonts.googleapis.com/css2?family=PT+Serif&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Secular+One&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/resources/phosphor.css">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -1,35 +1,30 @@
{ {
"name": "rimajon", "name": "rimajon-vue",
"version": "0.1.0", "version": "0.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve --port 3000", "dev": "vite",
"build": "vue-cli-service build --modern" "build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false"
}, },
"dependencies": { "dependencies": {
"core-js": "^3.6.5", "pug": "^3.0.2",
"vue": "3.0.0", "sass": "^1.69.5",
"vue-router": "4.0.2", "vue": "^3.3.4",
"vuex": "4.0.0-rc.2", "vue-router": "^4.2.5",
"vuex": "^4.1.0",
"vuex-persist": "^3.1.3" "vuex-persist": "^3.1.3"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0", "@tsconfig/node18": "^18.2.2",
"@vue/cli-plugin-router": "~4.5.0", "@types/node": "^18.18.5",
"@vue/cli-plugin-typescript": "~4.5.0", "@vitejs/plugin-vue": "^4.4.0",
"@vue/cli-plugin-vuex": "~4.5.0", "@vue/tsconfig": "^0.4.0",
"@vue/cli-service": "~4.5.0", "npm-run-all2": "^6.1.1",
"@vue/compiler-sfc": "^3.0.0-0", "typescript": "~5.2.0",
"phosphor-vue": "^1.0.0", "vite": "^4.4.11",
"pug": "2.0.4", "vue-tsc": "^1.8.19"
"pug-plain-loader": "1.0.0", }
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"typescript": "~3.9.3"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
} }

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
/* /index.html 200

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>RiMaJon - Mahjong con cartas</title>
<link href="https://fonts.googleapis.com/css2?family=PT+Serif&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Secular+One&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/resources/phosphor.css">
</head>
<body class="tema-automatico">
<noscript>
<strong>Para jugar RiMaJon necesitas activar JavaScript.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -1,51 +1,46 @@
<template> <script setup lang="ts">
<router-view/> import { RouterView } from 'vue-router'
<div style="display: none;">{{ modoColor }}</div> import { useStore } from 'vuex';
</template> import { computed, onMounted, watch } from 'vue';
<script lang="ts">
import { defineComponent, computed, watch } from "vue";
import { useStore } from "vuex";
export default defineComponent({ const store = useStore();
setup() { const modoColorUsuario = computed<string>(() => store.state.modoColorUsuario);
const store = useStore();
const modoColorUsuario = computed<string>(() => store.state.modoColorUsuario);
const query = window.matchMedia("(prefers-color-scheme: dark)"); const query = window.matchMedia("(prefers-color-scheme: dark)");
const funActualizarMediaQuery = (ev: MediaQueryListEvent | MediaQueryList) => { const funActualizarMediaQuery = (ev: MediaQueryListEvent | MediaQueryList) => {
store.commit( store.commit(
"setModoColorUsuario", "setModoColorUsuario",
ev.matches ? "oscuro" : "claro" ev.matches ? "oscuro" : "claro"
); );
}; };
query.addEventListener("change", funActualizarMediaQuery); query.addEventListener("change", funActualizarMediaQuery);
funActualizarMediaQuery(query); funActualizarMediaQuery(query);
watch(modoColorUsuario, (v) => { watch(modoColorUsuario, (v) => {
console.log("Modo actualizado"); console.log("Modo actualizado");
if (v === "oscuro") { if (v === "oscuro") {
document.body.className = "tema-oscuro"; document.body.className = "tema-oscuro";
} else if (v === "claro") { } else if (v === "claro") {
document.body.className = "tema-claro"; document.body.className = "tema-claro";
} else { } else {
document.body.className = "tema-automatico"; document.body.className = "tema-automatico";
} }
});
(() => {
const modo = localStorage.getItem("modoColorUsuario");
if (modo === "claro" || modo === "oscuro") {
store.commit("setModoColorUsuario", modo);
} else {
store.commit("setModoColorUsuario", "");
}
})();
return {
modoColor: modoColorUsuario
}
}
}); });
(() => {
const modo = localStorage.getItem("modoColorUsuario");
if (modo === "claro" || modo === "oscuro") {
store.commit("setModoColorUsuario", modo);
} else {
store.commit("setModoColorUsuario", "");
}
})();
</script> </script>
<template>
<RouterView />
<div style="display: none;">{{ modoColor }}</div>
</template>

View File

@ -4,8 +4,7 @@ body
color: var(--color-texto) color: var(--color-texto)
margin: 0 margin: 0
// Claro @mixin tema-claro
.tema-automatico
--color-fondo: #ffffff --color-fondo: #ffffff
--color-texto: #151515 --color-texto: #151515
--color-fondo-transparente: rgba(255, 255, 255, 0.8) --color-fondo-transparente: rgba(255, 255, 255, 0.8)
@ -18,26 +17,17 @@ body
--color-fondo-reyes: #ffffff --color-fondo-reyes: #ffffff
--color-texto-reyes: #2E7D32 --color-texto-reyes: #2E7D32
--color-mesa-1: #E3F2FD --color-fondo-resaltado-carta-roja: #64B5F6
--color-mesa-2: #90CAF9 --color-fondo-resaltado-carta-negra: #64B5F6
--color-fondo-resaltado-dragon-rojo: #64B5F6
.tema-claro --color-fondo-resaltado-dragon-verde: #64B5F6
--color-fondo: #ffffff --color-fondo-resaltado-dragon-azul: #64B5F6
--color-texto: #151515 --color-fondo-resaltado-reyes: #64B5F6
--color-fondo-transparente: rgba(255, 255, 255, 0.8)
--color-borde: gray
--color-texto-carta-roja: #b71c1c
--color-fondo-carta-roja: #ffffff
--color-fondo-dragon-rojo: #ffffff
--color-fondo-dragon-verde: #ffffff
--color-fondo-dragon-azul: #ffffff
--color-fondo-reyes: #ffffff
--color-texto-reyes: #2E7D32
--color-mesa-1: #E3F2FD --color-mesa-1: #E3F2FD
--color-mesa-2: #90CAF9 --color-mesa-2: #90CAF9
.tema-oscuro @mixin tema-oscuro
--color-fondo: #151515 --color-fondo: #151515
--color-texto: #dedede --color-texto: #dedede
--color-fondo-transparente: rgba(21, 21, 21, 0.85) --color-fondo-transparente: rgba(21, 21, 21, 0.85)
@ -50,22 +40,26 @@ body
--color-fondo-reyes: #2E7D32 --color-fondo-reyes: #2E7D32
--color-texto-reyes: #ffffff --color-texto-reyes: #ffffff
--color-fondo-resaltado-carta-roja: #e57373
--color-fondo-resaltado-carta-negra: #757575
--color-fondo-resaltado-dragon-rojo: #e57373
--color-fondo-resaltado-dragon-verde: #66BB6A
--color-fondo-resaltado-dragon-azul: #29B6F6
--color-fondo-resaltado-reyes: #66BB6A
--color-mesa-1: #004D40 --color-mesa-1: #004D40
--color-mesa-2: #003027 --color-mesa-2: #003027
// Claro
.tema-claro
@include tema-claro
.tema-oscuro
@include tema-oscuro
.tema-automatico
@include tema-claro
@media (prefers-color-scheme: dark) @media (prefers-color-scheme: dark)
.tema-automatico .tema-automatico
--color-fondo: #151515 @include tema-oscuro
--color-texto: #dedede
--color-fondo-transparente: rgba(21, 21, 21, 0.85)
--color-borde: #c1c1c1
--color-texto-carta-roja: #dedede
--color-fondo-carta-roja: #b71c1c
--color-fondo-dragon-rojo: #b71c1c
--color-fondo-dragon-verde: #2E7D32
--color-fondo-dragon-azul: #1565C0
--color-fondo-reyes: #2E7D32
--color-texto-reyes: #ffffff
--color-mesa-1: #004D40
--color-mesa-2: #003027

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -179,13 +179,8 @@ export default defineComponent({
.cont-carta .cont-carta
margin-left: 1px margin-left: 1px
.c-carta-resaltada
transform: translateY(calc(var(--phx) * -1))
filter: saturate(1.75) !important
opacity: 1 !important
.c-carta .c-carta
opacity: 0.85
position: relative position: relative
font: font:
size: calc(var(--phx) * 4 * var(--escala)) size: calc(var(--phx) * 4 * var(--escala))
@ -218,7 +213,7 @@ export default defineComponent({
top: -95% top: -95%
width: 100% width: 100%
height: 100% height: 100%
background-image: linear-gradient(135deg, rgba(210, 210, 210, 0.0) 0%, rgba(210, 210, 210, 0.0) 45%, rgba(210, 210, 210, 0.3) 55%, rgba(210, 210, 210, 0.9) 63%, rgba(210, 210, 210, 0.3) 67%, rgba(210, 210, 210, 0.0) 75%, rgba(210, 210, 210, 0.0) 100%) background-image: linear-gradient(135deg, rgba(169, 169, 169, 0.0) 0%, rgba(169, 169, 169, 0.0) 45%, rgba(169, 169, 169, 0.3) 55%, rgba(169, 169, 169, 0.9) 63%, rgba(169, 169, 169, 0.3) 67%, rgba(169, 169, 169, 0.0) 75%, rgba(169, 169, 169, 0.0) 100%)
transition: transform 1000ms transition: transform 1000ms
animation-duration: 4s animation-duration: 4s
animation-name: brillocarta animation-name: brillocarta
@ -274,26 +269,47 @@ export default defineComponent({
background-color: var(--color-fondo) background-color: var(--color-fondo)
color: var(--color-texto) color: var(--color-texto)
.carta-cNegro.c-carta-resaltada
background-color: var(--color-fondo-resaltado-carta-negra) !important
.carta-cRojo .carta-cRojo
background-color: var(--color-fondo-carta-roja) background-color: var(--color-fondo-carta-roja)
color: var(--color-texto-carta-roja) color: var(--color-texto-carta-roja)
.carta-cRojo.c-carta-resaltada
background-color: var(--color-fondo-resaltado-carta-roja) !important
.carta-cReyes .carta-cReyes
background-color: var(--color-fondo-reyes) background-color: var(--color-fondo-reyes)
color: var(--color-texto-reyes) color: var(--color-texto-reyes)
.carta-cReyes.c-carta-resaltada
background-color: var(--color-fondo-resaltado-reyes) !important
.carta-dNegro .carta-dNegro
background-color: var(--color-fondo) background-color: var(--color-fondo)
.carta-dNegro.c-carta-resaltada
background-color: var(--color-fondo-resaltado-carta-negra) !important
.carta-dRojo .carta-dRojo
background-color: var(--color-fondo-dragon-rojo) background-color: var(--color-fondo-dragon-rojo)
.carta-dRojo.c-carta-resaltada
background-color: var(--color-fondo-resaltado-dragon-rojo) !important
.carta-dVerde .carta-dVerde
background-color: var(--color-fondo-dragon-verde) background-color: var(--color-fondo-dragon-verde)
.carta-dVerde.c-carta-resaltada
background-color: var(--color-fondo-resaltado-dragon-verde) !important
.carta-dAzul .carta-dAzul
background-color: var(--color-fondo-dragon-azul) background-color: var(--color-fondo-dragon-azul)
.carta-dAzul.c-carta-resaltada
background-color: var(--color-fondo-resaltado-dragon-azul) !important
.carta- .carta-
opacity: 0 opacity: 0

View File

@ -1,5 +1,5 @@
import { computed } from "vue"; import { computed } from "vue";
import { RiMaJonState } from "@/store"; import type { RiMaJonState } from "../store/index";
import { Store } from "vuex"; import { Store } from "vuex";
export const getEsOscuro = (store: Store<RiMaJonState>) => { export const getEsOscuro = (store: Store<RiMaJonState>) => {

View File

@ -1,6 +1,7 @@
import { Store } from "vuex"; import { Store } from "vuex";
import { RiMaJonState } from "@/store"; import type { RiMaJonState } from "../store";
import { computed, ComputedRef } from "vue"; import { computed} from "vue";
import type { ComputedRef } from "vue";
export const getClaseDora = (valor: ComputedRef<number>, store: Store<RiMaJonState>) => computed<string>(() => { export const getClaseDora = (valor: ComputedRef<number>, store: Store<RiMaJonState>) => computed<string>(() => {
const [dora1] = store.state.dora; const [dora1] = store.state.dora;

View File

@ -1,11 +1,12 @@
import { createApp } from 'vue'; import { createApp } from 'vue'
import App from './App.vue'; import App from './App.vue'
import router from './router'; import router from './router'
import store from './store'; import store from './store'
import "./styles/global.sass"; import "./assets/global.sass"
// @ts-ignore const app = createApp(App)
createApp(App)
.use(store) app.use(router)
.use(router) app.use(store)
.mount('#app');
app.mount('#app')

View File

@ -1,77 +1,76 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; import { createRouter, createWebHistory } from 'vue-router'
import Inicio from "../views/Inicio/Inicio.vue"; import Inicio from "../views/Inicio/Inicio.vue";
import Sala from "@/views/Sala/Sala.vue"; import Sala from "../views/Sala/Sala.vue";
import Juego from "@/views/Juego/Juego.vue"; import Juego from "../views/Juego/Juego.vue";
const routes: Array<RouteRecordRaw> = [ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ {
path: '/', path: '/',
name: 'Home', name: 'Home',
component: Inicio component: Inicio
}, },
{ {
path: "/sala/:id/", path: "/sala/:id/",
name: "Sala", name: "Sala",
component: Sala component: Sala
}, },
{ {
path: "/juego/:id/", path: "/juego/:id/",
name: "Juego", name: "Juego",
component: Juego component: Juego
}, },
{ {
path: "/ayuda/", path: "/ayuda/",
name: "Ayuda", name: "Ayuda",
component: () => import(/* webpackChunkName: "ayuda" */ "../views/Ayuda/Ayuda.vue") component: () => import("../views/Ayuda/Ayuda.vue")
}, },
{ {
path: "/tutorial/", path: "/tutorial/",
name: "Tutorial", name: "Tutorial",
component: () => import(/* webpackChunkName: "tutorial" */ "../views/Tutorial/Tutorial.vue"), component: () => import("../views/Tutorial/Tutorial.vue"),
children: [ children: [
{ {
path: "", path: "",
component: () => import(/* webpackChunkName: "tutorial_index" */ "../views/Tutorial/views/Index.vue") component: () => import("../views/Tutorial/views/Index.vue")
}, },
{ {
path: "cartas/", path: "cartas/",
component: () => import(/* webpackChunkName: "tutorial_cartas" */ "../views/Tutorial/views/Cartas.vue") component: () => import( "../views/Tutorial/views/Cartas.vue")
}, },
{ {
path: "mano/", path: "mano/",
component: () => import(/* webpackChunkName: "tutorial_mano" */ "../views/Tutorial/views/Mano.vue") component: () => import("../views/Tutorial/views/Mano.vue")
}, },
{ {
path: "mano/par/", path: "mano/par/",
component: () => import(/* webpackChunkName: "tutorial_mano_par" */ "../views/Tutorial/views/Mano/Par.vue") component: () => import("../views/Tutorial/views/Mano/Par.vue")
}, },
{ {
path: "mano/secuencia/", path: "mano/secuencia/",
component: () => import(/* webpackChunkName: "tutorial_mano_secuencia" */ "../views/Tutorial/views/Mano/Secuencia.vue") component: () => import("../views/Tutorial/views/Mano/Secuencia.vue")
}, },
{ {
path: "mano/triple/", path: "mano/triple/",
component: () => import(/* webpackChunkName: "tutorial_mano_triple" */ "../views/Tutorial/views/Mano/Triple.vue") component: () => import("../views/Tutorial/views/Mano/Triple.vue")
}, },
{ {
path: "mano-lista/", path: "mano-lista/",
component: () => import(/* webpackChunkName: "tutorial_flujo-juego" */ "../views/Tutorial/views/ManoLista.vue") component: () => import( "../views/Tutorial/views/ManoLista.vue")
}, },
{ {
path: "bonus/", path: "bonus/",
component: () => import(/* webpackChunkName: "tutorial_bonus" */ "../views/Tutorial/views/Bonus.vue") component: () => import("../views/Tutorial/views/Bonus.vue")
}, },
{ {
path: "puntaje/", path: "puntaje/",
component: () => import(/* webpackChunkName: "tutorial_puntaje" */ "../views/Tutorial/views/Puntaje.vue") component: () => import("../views/Tutorial/views/Puntaje.vue")
} }
] ]
} }
]; ]
})
const router = createRouter({ export default router
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;

5
src/shims-vue.d.ts vendored
View File

@ -1,5 +0,0 @@
declare module '*.vue' {
import { defineComponent } from 'vue'
const component: ReturnType<typeof defineComponent>
export default component
}

View File

@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
div div(:style="'--phx: ' + phx + '; --escala: ' + escala + ';'")
h1 Sobre el juego h1 Sobre el juego
p Ri Ma Jon es un juego inspirado en Mahjong, pero ejecutado con cartas. p Ri Ma Jon es un juego inspirado en Mahjong, pero ejecutado con cartas.
@ -20,9 +20,9 @@ div
div.yaku div.yaku
h4 h4
i.ph-lock-bold.img-lock(title="Solo en mano cerrada") i.ph-lock-bold.img-lock(title="Solo en mano cerrada")
| Mano completamente cerrada | Mano cerrada
p Ganar en tu turno con una mano cerrada p Ganar sin robar ninguna carta
grupo-cartas(:cartas="[2, 4, 5, 7, 8, 42, 44, 46, 47, 48, 50]") grupo-cartas(:cartas="[2, 4, 4, 5, 6, 42, 44, 46, 47, 48, 50]")
div.yaku div.yaku
h4 h4
@ -31,11 +31,6 @@ div
p 2 secuencias iguales del mismo color en mano cerrada. p 2 secuencias iguales del mismo color en mano cerrada.
grupo-cartas(:cartas="[2, 2, 4, 5, 6, 7, 44, 45, 44, 128, 128]") grupo-cartas(:cartas="[2, 2, 4, 5, 6, 7, 44, 45, 44, 128, 128]")
div.yaku
h4 Variedad
p Al menos una carta de cada tipo
grupo-cartas(:cartas="[10, 11, 35, 36, 39, 160, 160, 160, 192, 192, 192]")
div.yaku div.yaku
h4 Realeza h4 Realeza
p 1 triple de J, K o Q. Acumulable. p 1 triple de J, K o Q. Acumulable.
@ -103,6 +98,7 @@ div
| Triple triples cerrados | Triple triples cerrados
p 3 triples en mano cerrada p 3 triples en mano cerrada
grupo-cartas(:cartas="[6, 6, 7, 48, 49, 49, 160, 160, 160, 192, 192]") grupo-cartas(:cartas="[6, 6, 7, 48, 49, 49, 160, 160, 160, 192, 192]")
p No se acumula con "Triple triples".
h3 5 puntos h3 5 puntos
@ -113,7 +109,7 @@ div
grupo-cartas(:cartas="[35, 37, 38, 40, 42, 45, 47, 48, 51, 52, 52]") grupo-cartas(:cartas="[35, 37, 38, 40, 42, 45, 47, 48, 51, 52, 52]")
p No se acumula con "escalera", "negro" o "rojo". p No se acumula con "escalera", "negro" o "rojo".
h3 7 puntos h3 8 puntos
div.pad div.pad
@ -249,13 +245,14 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{phx, escala}"> <style lang="sass">
.pad .pad
padding-left: 2rem padding-left: 2rem
.tabla-puntos .tabla-puntos
padding-left: 2rem padding-left: 2rem
h3 h3
text-decoration: underline text-decoration: underline
font-size: 1.45rem font-size: 1.45rem

View File

@ -35,7 +35,7 @@ import {useStore} from "vuex";
import crearUsuario from "./components/crear-usuario.vue"; import crearUsuario from "./components/crear-usuario.vue";
import crearSala from "./components/crear-sala.vue"; import crearSala from "./components/crear-sala.vue";
import entrarSala from "./components/entrar-sala.vue"; import entrarSala from "./components/entrar-sala.vue";
import { servidorF } from "@/variables"; import {servidorF} from "../../variables"
export default defineComponent({ export default defineComponent({
name: "Inicio", name: "Inicio",

View File

@ -1,6 +1,9 @@
<template lang="pug"> <template lang="pug">
div div(
:style="'--escala: ' + escala + '; --pH: ' + pH + '; --phx: ' + phx + '; --pW: ' + pW + '; --pwx:' + pwx + ';'"
)
pantalla-ganador(:datos="datosJuego") pantalla-ganador(:datos="datosJuego")
pantalla-empate(v-if="esEmpate")
contenedor-dora(:turnosRestantes="turnosDora") contenedor-dora(:turnosRestantes="turnosDora")
div.con-int-juego div.con-int-juego
div.cont-2-juego div.cont-2-juego
@ -21,15 +24,16 @@ div
</template> </template>
<script lang="ts"> <script lang="ts">
import {defineComponent, ref, onMounted, onUnmounted} from "vue"; import { defineComponent, ref, computed, onMounted, onUnmounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useDimensions } from "@/components/useDimensions"; import { useDimensions } from "@/components/useDimensions";
import { useStore } from "vuex"; import { useStore } from "vuex";
import { wsServidor } from "@/variables"; import { wsServidor } from "@/variables";
import contenedorDora from "./components/contenedor-dora.vue" import contenedorDora from "./components/contenedor-dora.vue";
import mano from "@/views/Juego/components/mano.vue"; import mano from "@/views/Juego/components/mano.vue";
import contenedorCartas from "./components/contenedor-cartas.vue" import contenedorCartas from "./components/contenedor-cartas.vue";
import pantallaGanador from "./components/pantalla-ganador.vue" import pantallaGanador from "./components/pantalla-ganador.vue";
import pantallaEmpate from "./components/pantalla-empate.vue";
import { EstadoJuego } from "@/views/Juego/types/EstadoJuego"; import { EstadoJuego } from "@/views/Juego/types/EstadoJuego";
import { DatosJuego } from "@/views/Juego/types/DatosJuego"; import { DatosJuego } from "@/views/Juego/types/DatosJuego";
import { Dragon, Mano } from "@/views/Juego/types/Mano"; import { Dragon, Mano } from "@/views/Juego/types/Mano";
@ -52,7 +56,7 @@ const obtClave = (obj: any, valor: string): string | undefined => {
export default defineComponent({ export default defineComponent({
name: "Juego", name: "Juego",
components: {contenedorDora, mano, contenedorCartas, pantallaGanador}, components: {contenedorDora, mano, contenedorCartas, pantallaGanador, pantallaEmpate},
setup() { setup() {
const route = useRoute(); const route = useRoute();
const store = useStore(); const store = useStore();
@ -200,6 +204,21 @@ export default defineComponent({
} }
}; };
const esEmpate = computed(() => {
const juegoTerminado = datosJuego.value?.estadoJuego === "Terminado"
const manos = datosJuego.value?.manos
if (juegoTerminado && manos) {
for (const k in manos) {
const m = manos[k];
if (m.esGanador) return false;
}
return true;
} else {
return false;
}
});
const obtClaveMap = (s: string) => obtClave(map, s); const obtClaveMap = (s: string) => obtClave(map, s);
return { return {
dora, dora,
@ -215,6 +234,7 @@ export default defineComponent({
turnoActual, turnoActual,
estadoJuego, estadoJuego,
datosJuego, datosJuego,
esEmpate,
obtClaveMap, obtClaveMap,
descartarCarta, descartarCarta,
pH, pH,
@ -228,7 +248,7 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{pH, phx, pW, pwx, escala}"> <style lang="sass">
.con-int-juego .con-int-juego
position: absolute position: absolute
@ -242,7 +262,8 @@ export default defineComponent({
.cont-2-juego .cont-2-juego
position: absolute position: absolute
border: solid 3px #795548 border: solid 5px #795548
border-radius: 5px
background: radial-gradient(var(--color-mesa-1), var(--color-mesa-2)) background: radial-gradient(var(--color-mesa-1), var(--color-mesa-2))
transform: rotateX(2deg) transform: rotateX(2deg)
width: 100% width: 100%

View File

@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
div.cont-cuadrante-descarte(:class="claseTurnoActual") div.cont-cuadrante-descarte(:class="claseTurnoActual" :style="'--escala: ' + escala + ';'")
div(v-for="cartas in grupoCartas") div(v-for="cartas in grupoCartas")
carta(v-for="(c, i) in cartas" :valor="c" :key="i") carta(v-for="(c, i) in cartas" :valor="c" :key="i")
@ -36,7 +36,7 @@ export default defineComponent({
}, },
escala: { escala: {
type: Number, type: Number,
default: 0.75 default: 0.7
}, },
esTurnoActual: { esTurnoActual: {
type: Boolean, type: Boolean,
@ -56,18 +56,19 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{escala}"> <style lang="sass">
.cont-cuadrante-descarte .cont-cuadrante-descarte
position: absolute position: absolute
width: 26% width: 23%
height: 20% height: 20%
bottom: 17% bottom: 17%
right: 37% right: 38.5%
text-align: left text-align: left
border-top-style: solid border-top-style: solid
border-top-width: calc(var(--phx) * 0.75 * var(--escala)) border-top-width: calc(var(--phx) / 2)
border-top-color: transparent border-top-color: transparent
transition: border-top-color 250ms
.cont-cuadrante-descarte-turno-actual .cont-cuadrante-descarte-turno-actual

View File

@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
div.contenedor-dora div.contenedor-dora(:style="'--escala: ' + escala + ';'")
carta(v-for="(c, i) in doraCerrado" :valor="c" :key="i") carta(v-for="(c, i) in doraCerrado" :valor="c" :key="i")
br br
carta(v-for="(c, i) in doraAbierto" :valor="c" :key="i") carta(v-for="(c, i) in doraAbierto" :valor="c" :key="i")
@ -47,7 +47,7 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{escala}"> <style lang="sass">
.contenedor-dora .contenedor-dora
position: fixed position: fixed

View File

@ -29,7 +29,7 @@ div.cont-cuadrante-2-mano(:style="'transform: rotate(' + posicionW + ')'")
carta(:valor="-1") carta(:valor="-1")
carta(:valor="mano.sigCarta" :fnDescartar="descartarCarta") carta(:valor="mano.sigCarta" :fnDescartar="descartarCarta")
carta(:valor="-1") carta(:valor="-1")
div(v-for="g in mano.cartasReveladas" :style="{display: 'inline-block'}") div(v-for="g in mano.cartasReveladas" :style="{display: 'inline-block', marginLeft: '5px'}")
carta(v-for="(c, i) in g" :valor="c" :key="i") carta(v-for="(c, i) in g" :valor="c" :key="i")
// //

View File

@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
div.opcion-mano(@click="enviarSolicitudIgnorarOportunidad" :style="{backgroundColor: '#9E9E9E'}") div.opcion-mano(@click="enviarSolicitudIgnorarOportunidad" :style="'background-color: #9E9E9E; --tamano: ' + tamano + ';'")
| Ignorar | Ignorar
// //
@ -51,7 +51,7 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{tamano}"> <style lang="sass">
.opcion-mano .opcion-mano
display: inline-block display: inline-block

View File

@ -1,5 +1,7 @@
<template lang="pug"> <template lang="pug">
div.opcion-mano(v-for="opcion in opciones" @click="enviarSolicitudSeq(opcion)" :style="{backgroundColor: '#009688'}") div.opcion-mano(v-for="opcion in opciones" @click="enviarSolicitudSeq(opcion)"
:style="'background-color: #009688; --tamano: ' + tamano + '; --escala: ' + escala + ';'"
)
div.contenedor-cartas-opcion-mano div.contenedor-cartas-opcion-mano
carta(v-for="(c, i) in obtCartasOrdenadas(opcion)" carta(v-for="(c, i) in obtCartasOrdenadas(opcion)"
:valor="c" :valor="c"
@ -76,7 +78,7 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{tamano, escala}"> <style lang="sass">
.contenedor-cartas-opcion-mano .contenedor-cartas-opcion-mano
position: absolute position: absolute

View File

@ -1,5 +1,7 @@
<template lang="pug"> <template lang="pug">
div.opcion-mano(@click="enviarSolicitudSeq()" :style="{backgroundColor: '#3F51B5'}") div.opcion-mano(@click="enviarSolicitudSeq()"
:style="'background-color: #3F51B5; --tamano: ' + tamano + '; --escala: ' + escala + ';'"
)
div.contenedor-cartas-opcion-mano div.contenedor-cartas-opcion-mano
carta(v-for="(c, i) in obtCartas()" carta(v-for="(c, i) in obtCartas()"
:valor="c" :valor="c"
@ -81,7 +83,7 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{tamano, escala}"> <style lang="sass">
.contenedor-cartas-opcion-mano .contenedor-cartas-opcion-mano
position: absolute position: absolute

View File

@ -1,5 +1,7 @@
<template lang="pug"> <template lang="pug">
div.opcion-mano(@click="enviarSolicitudWin()" :style="{backgroundColor: '#f44336'}") div.opcion-mano(@click="enviarSolicitudWin()"
:style="'background-color: #f44336; --tamano: ' + tamano + ';'"
)
span Win span Win
// //
@ -54,7 +56,7 @@ export default defineComponent({
</script> </script>
<style lang="sass" vars="{tamano}"> <style lang="sass">
.opcion-mano .opcion-mano
position: relative position: relative

View File

@ -0,0 +1,35 @@
<template lang="pug">
div.contenedor-pantalla-empate
h1 Empate
hr
router-link(to="/") Ir al inicio
//
</template>
<script lang="ts">
export default {
name: "pantalla-empate"
}
</script>
<style lang="sass" scoped>
.contenedor-pantalla-empate
position: fixed
top: 10%
left: 10%
width: 80%
height: 80%
z-index: 100
background-color: var(--color-fondo-transparente)
padding: 1rem
h1, h2, h3, h4, h5
margin: 0
padding: 1rem 0
</style>

View File

@ -33,6 +33,10 @@ const aumentarValorA = (ref: Ref<number>, valorDestino: number) => {
}; };
const formulaPuntos = (x: number) => 1000 * Math.floor(
3 * x + (x ** 3 * 125) / 1000
);
export default defineComponent({ export default defineComponent({
name: "pantalla-ganador", name: "pantalla-ganador",
components: {grupoCartas}, components: {grupoCartas},
@ -92,11 +96,7 @@ export default defineComponent({
for (const y of yaku.value) { for (const y of yaku.value) {
n += obtValorYaku(y) n += obtValorYaku(y)
} }
if (n === 0) return 100; return formulaPuntos(n);
const preValor = 1000 + (270 * n ** 2) - (18 * n ** 3);
// Eliminar los 2 ultimos números.
return Math.floor(preValor / 100) * 100;
}); });
const obtTextoYaku = (y: Yaku) => { const obtTextoYaku = (y: Yaku) => {

View File

@ -1,50 +1,74 @@
export type Yaku = export type Yaku =
// 10
| "DragonesFull" | "DragonesFull"
| "Verde" | "Verde"
// 8
| "RealezaDragones" | "RealezaDragones"
| "RealezaFull" | "RealezaFull"
| "TripleTriplesCerrados" | "EscaleraPerfecta"
| "A10"
// 5
| "EscaleraFull" | "EscaleraFull"
// 3
| "TripleTriplesCerrados"
| "Exterior" | "Exterior"
// 2
| "Escalera" | "Escalera"
| "TripleCuadruples"
| "Negro" | "Negro"
| "Rojo" | "Rojo"
| "SemiExterior" | "SemiExterior"
| "ParUnico" | "DobleSecuenciaPura"
| "DragonJugador" // 1
| "DragonPartida" | "Dragones"
| "Interior" | "Interior"
| "TripleTriples" | "TripleTriples"
| "TripleSecuenciaCerrada"
| "Realeza" | "Realeza"
| "DobleSecuenciaPura" | "DobleSecuencia"
| "Cerrado" | "ManoCerrada"
export const obtValorYaku = (y: Yaku): number => { export const obtValorYaku = (y: Yaku): number => {
switch (y) { switch (y) {
case "DragonesFull": return 10 case "DragonesFull":
case "Verde": return 10 return 10;
case "RealezaDragones": return 7 case "Verde":
case "RealezaFull": return 7 return 10;
case "TripleTriplesCerrados": return 3 case "RealezaDragones":
case "EscaleraFull": return 3 return 8;
case "Exterior": return 3 case "RealezaFull":
case "Escalera": return 2 return 8;
case "TripleCuadruples": return 2 case "EscaleraPerfecta":
case "Negro": return 2 return 8;
case "Rojo": return 2 case "A10":
case "SemiExterior": return 2 return 8;
case "ParUnico": return 1 case "EscaleraFull":
case "DragonJugador": return 1 return 5;
case "DragonPartida": return 1 case "TripleTriplesCerrados":
case "Interior": return 1 return 3;
case "TripleTriples": return 1 case "Exterior":
case "TripleSecuenciaCerrada": return 1 return 3;
case "Realeza": return 1 case "Escalera":
case "DobleSecuenciaPura": return 1 return 2;
case "Cerrado": return 0 case "Negro":
return 2;
case "Rojo":
return 2;
case "SemiExterior":
return 2;
case "DobleSecuenciaPura":
return 2;
case "Dragones":
return 1;
case "Interior":
return 1;
case "TripleTriples":
return 1;
case "Realeza":
return 1;
case "DobleSecuencia":
return 1;
case "ManoCerrada":
return 1;
} }
} }

View File

@ -50,12 +50,12 @@ div
td= (valorBonus * 3) / 10 + ' puntos' td= (valorBonus * 3) / 10 + ' puntos'
tr tr
td 2 indicadores td 2 indicadores
td= (valorBonus * 3) / 10 + ' puntos' td= (valorBonus * 2) / 10 + ' puntos'
td= (valorBonus * 6) / 10 + ' puntos' td= (valorBonus * 4) / 10 + ' puntos'
td - td -
tr tr
td 3 indicadores td 3 indicadores
td= (valorBonus * 9) / 10 + ' puntos' td= (valorBonus * 4) / 10 + ' puntos'
td - td -
td - td -
tr tr

View File

@ -4,7 +4,11 @@ div
p Primero se obtienen los puntos otorgados por los yaku. p Primero se obtienen los puntos otorgados por los yaku.
p Luego se obtienen los puntos otorgados por los bonus. p Luego se obtienen los puntos otorgados por los bonus.
p La suma de estos dos es la cantidad de puntos total. Luego se busca esa cantidad en la tabla: p La suma de estos dos es la cantidad de puntos total. Para obtener las monedas se usa la formula:
img(:src="'/img/formula-puntaje.png'" style="height: 100px; width: auto;")
p En la siguiente tabla se muestran los valores comunes:
table.tabla-puntaje table.tabla-puntaje
thead thead
@ -12,9 +16,12 @@ div
td Puntos td Puntos
td Monedas td Monedas
tbody tbody
tr(v-for="(p, i) in puntos") tr(v-for="i in puntos")
td {{ i * 0.5 }} td {{ i }}
td {{ p }} td {{ formulaPuntos(i) }}
p La cantidad maxima de puntos es 10
p Cada jugador inicia con 100,000 monedas
// //
</template> </template>
@ -22,35 +29,38 @@ div
<script lang="ts"> <script lang="ts">
import { defineComponent } from "vue"; import { defineComponent } from "vue";
const formulaPuntos = (x: number) => 1000 * Math.floor(
3 * x + (x ** 3 * 125) / 1000
);
const puntos = [ const puntos = [
0, 1,
0, 1.5,
1000, 2,
2000, 2.5,
3000, 3,
4000, 3.5,
6000, 4,
8000, 4.5,
10000, 5,
13000, 5.5,
17000, 6,
21000, 6.5,
25000, 7,
30000, 7.5,
35000, 8,
37000, 8.5,
39000, 9,
41000, 9.5,
43000, 10
45000,
50000
]; ];
export default defineComponent({ export default defineComponent({
name: "Puntaje", name: "Puntaje",
setup() { setup() {
return { return {
puntos puntos,
formulaPuntos
} }
} }
}); });

12
tsconfig.app.json Normal file
View File

@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

View File

@ -1,39 +1,11 @@
{ {
"compilerOptions": { "files": [],
"target": "esnext", "references": [
"module": "esnext", {
"strict": true, "path": "./tsconfig.node.json"
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
}, },
"lib": [ {
"esnext", "path": "./tsconfig.app.json"
"dom", }
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
] ]
} }

16
tsconfig.node.json Normal file
View File

@ -0,0 +1,16 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

16
vite.config.ts Normal file
View File

@ -0,0 +1,16 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})