Skip to content

Instantly share code, notes, and snippets.

@fermelli
Last active October 20, 2024 06:37
Show Gist options
  • Save fermelli/6a11a0029349d40cc0b58c92943e6f56 to your computer and use it in GitHub Desktop.
Save fermelli/6a11a0029349d40cc0b58c92943e6f56 to your computer and use it in GitHub Desktop.
Este es un juego de tic-tac-toe simple implementado en Vue 3. Basado en la version de React de la documentacion oficial (https://react.dev/learn/tutorial-tic-tac-toe)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tic Tac Toe: Implementacion en Vue 3</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
margin: 20px;
padding: 0;
}
h1 {
margin-top: 0;
font-size: 22px;
}
h2 {
margin-top: 0;
font-size: 20px;
}
h3 {
margin-top: 0;
font-size: 18px;
}
h4 {
margin-top: 0;
font-size: 16px;
}
h5 {
margin-top: 0;
font-size: 14px;
}
h6 {
margin-top: 0;
font-size: 12px;
}
code {
font-size: 1.2em;
}
ul {
padding-inline-start: 20px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}
.board-row:after {
clear: both;
content: '';
display: table;
}
.status {
margin-bottom: 10px;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
</style>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
/* Tic Tac Toe: Vue 3 */
/*
Este es un juego de tic-tac-toe simple implementado en Vue 3.
Basado en la version de React de la documentacion oficial (https://react.dev/learn/tutorial-tic-tac-toe)
Extensiones recomendadas para VSCode:
- Prettier - Code formatter
- es6-string-html
*/
const { computed, createApp, ref } = Vue;
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (
squares[a] &&
squares[a] === squares[b] &&
squares[a] === squares[c]
) {
return squares[a];
}
}
return null;
}
const Square = {
props: {
value: {
type: [String, null],
required: true,
},
},
emits: ['onSquareClick'],
template: /*html*/ `
<button class="square" @click="$emit('onSquareClick')">
{{ value }}
</button>
`,
};
const Board = {
props: {
xIsNext: {
type: Boolean,
required: true,
},
squares: {
type: Array,
required: true,
},
},
emits: ['onPlay'],
components: {
Square,
},
setup(props) {
const winner = computed(() => calculateWinner(props.squares));
function handleClick(i) {
if (calculateWinner(props.squares) || props.squares[i]) {
return;
}
const nextSquares = props.squares.slice();
if (props.xIsNext) {
nextSquares[i] = 'X';
} else {
nextSquares[i] = 'O';
}
this.$emit('onPlay', nextSquares);
}
return { winner, handleClick };
},
template: /*html*/ `
<div class="status">
{{ winner ? 'Ganador: ' + winner : 'Siguiente jugador: ' + (xIsNext ? 'X' : 'O') }}
</div>
<div class="board-row">
<Square :value="squares[0]" @onSquareClick="handleClick(0)" />
<Square :value="squares[1]" @onSquareClick="handleClick(1)" />
<Square :value="squares[2]" @onSquareClick="handleClick(2)" />
</div>
<div class="board-row">
<Square :value="squares[3]" @onSquareClick="handleClick(3)" />
<Square :value="squares[4]" @onSquareClick="handleClick(4)" />
<Square :value="squares[5]" @onSquareClick="handleClick(5)" />
</div>
<div class="board-row">
<Square :value="squares[6]" @onSquareClick="handleClick(6)" />
<Square :value="squares[7]" @onSquareClick="handleClick(7)" />
<Square :value="squares[8]" @onSquareClick="handleClick(8)" />
</div>
`,
};
const Game = {
setup() {
const history = ref([Array(9).fill(null)]);
const currentMove = ref(0);
const xIsNext = computed(() => currentMove.value % 2 === 0);
const currentSquares = computed(
() => history.value[currentMove.value],
);
function handlePlay(nextSquares) {
const nextHistory = [
...history.value.slice(0, currentMove.value + 1),
nextSquares,
];
history.value = nextHistory;
currentMove.value = nextHistory.length - 1;
}
function jumpTo(nextMove) {
currentMove.value = nextMove;
}
return {
history,
currentMove,
xIsNext,
currentSquares,
handlePlay,
jumpTo,
};
},
components: {
Board,
},
template: /*html*/ `
<div className="game">
<div className="game-board">
<Board :xIsNext="xIsNext" :squares="currentSquares" @onPlay="handlePlay" />
</div>
<div className="game-info">
<ol>
<li v-for="(squares, move) in history.slice(0, currentMove + 1)" :key="move">
<button @click="jumpTo(move)">
{{
move > 0 ? 'Ir al movimiento #' + move : 'Ir al inicio del juego'
}}
</button>
</li>
</ol>
</div>
</div>
`,
};
const app = createApp({
components: {
Game,
},
template: /*html*/ `
<Game />
`,
});
app.mount('#app');
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment