You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
triangles.fun/src/App.svelte

361 lines
6.8 KiB

3 years ago
<script>
import Graph from "./Graph.js"
import { onMount } from "svelte"
import { crossfade, scale } from "svelte/transition"
const [send, receive] = crossfade({
duration: 400,
fallback: scale,
})
const pole = 0
const hole = 1
const pick = 2
const dest = 3
let circles = []
let playing
let bold
let adjcs
let jumps
const restart = () => {
adjcs = new Graph()
jumps = new Graph()
circles = []
playing = true
bold = false
3 years ago
const numCircles = 15
for (let i = 0; i < numCircles; i++) {
circles[i] = pole
adjcs.addVertex(i)
jumps.addVertex(i)
if (i > 0) {
adjcs.addEdge(i, i - 1)
}
3 years ago
}
3 years ago
circles[0] = hole
adjcs.addEdge(0, 8)
adjcs.addEdge(1, 7)
adjcs.addEdge(1, 8)
adjcs.addEdge(2, 6)
adjcs.addEdge(2, 7)
adjcs.addEdge(3, 5)
adjcs.addEdge(3, 6)
adjcs.addEdge(5, 11)
adjcs.addEdge(6, 10)
adjcs.addEdge(6, 11)
adjcs.addEdge(7, 9)
adjcs.addEdge(7, 10)
adjcs.addEdge(9, 13)
adjcs.addEdge(10, 12)
adjcs.addEdge(10, 13)
adjcs.addEdge(12, 14)
jumps.addEdge(0, 2)
jumps.addEdge(0, 9)
jumps.addEdge(1, 3)
jumps.addEdge(1, 10)
jumps.addEdge(2, 4)
jumps.addEdge(2, 9)
jumps.addEdge(2, 11)
jumps.addEdge(3, 10)
jumps.addEdge(4, 11)
jumps.addEdge(5, 7)
jumps.addEdge(5, 12)
jumps.addEdge(6, 8)
jumps.addEdge(6, 13)
jumps.addEdge(7, 12)
jumps.addEdge(8, 13)
jumps.addEdge(9, 11)
jumps.addEdge(9, 14)
jumps.addEdge(11, 14)
}
3 years ago
const commonBetween = (source, destination) => {
const common = adjcs.adjacencyList[source].filter(common =>
adjcs.adjacencyList[destination].includes(common)
)
if (common.length != 1) {
throw new Error(
`Jump from ${source} to ${destination} cannot be performed`
)
}
return common
}
const clearDests = () =>
circles.forEach(
(_, i) => (circles[i] = circles[i] == dest ? hole : circles[i])
)
const getDests = (circles, curr) => {
let dests = []
jumps.adjacencyList[curr].forEach(jump => {
const jumpedOver = commonBetween(curr, jump)
if (circles[jump] == hole && circles[jumpedOver] == pole) {
dests.push(jump)
}
})
return dests
}
const getHints = circles => {
let hints = []
circles.forEach((circle, i) => {
if (circle == pole) {
const dests = getDests(circles, i)
if (dests.length > 0) {
hints.push(i)
}
}
})
return hints
}
const jumpReverse = (circles, source, destination) => {
const jumpedOver = commonBetween(source, destination)
circles[source] = pole
circles[jumpedOver] = pole
circles[destination] = hole
}
const jumpOver = (circles, source, destination) => {
const jumpedOver = commonBetween(source, destination)
circles[source] = hole
circles[jumpedOver] = hole
circles[destination] = pole
}
const change = curr => {
const prev = circles.indexOf(pick)
if (circles[curr] == pole && prev == -1) {
let dests = getDests(circles, curr)
dests.forEach(d => (circles[d] = dest))
if (dests.length > 0) {
circles[curr] = pick
}
return
}
if (circles[curr] == dest) {
jumpOver(circles, prev, curr)
clearDests()
const hints = getHints(circles)
if (hints.length == 0) {
playing = false
bold = true
}
return
}
if (circles[curr] == pick) {
circles[curr] = pole
clearDests()
}
3 years ago
}
class TT {
constructor(src, des) {
this.SRC = src
this.DES = des
this.xx = []
}
}
onMount(() => {
restart()
let shadow = [...circles]
const start = 0
const moves = new TT(start, undefined)
const recurse = move => {
const hints = getHints(shadow)
if (hints.length == 0) {
return
}
hints.forEach(hint => {
getDests(shadow, hint).forEach(des => {
const last = move.xx.push(new TT(hint, des)) - 1
jumpOver(shadow, hint, des)
recurse(move.xx[last], last)
jumpReverse(shadow, hint, des)
})
})
}
recurse(moves)
console.log(moves)
})
3 years ago
</script>
<style>
.div0 {
grid-area: 5 / 1 / 6 / 2;
}
.div1 {
grid-area: 5 / 3 / 6 / 4;
}
.div2 {
grid-area: 5 / 5 / 6 / 6;
}
.div3 {
grid-area: 5 / 7 / 6 / 8;
}
.div4 {
grid-area: 5 / 9 / 6 / 10;
}
.div5 {
grid-area: 4 / 8 / 5 / 9;
}
.div6 {
grid-area: 4 / 6 / 5 / 7;
}
.div7 {
grid-area: 4 / 4 / 5 / 5;
}
.div8 {
grid-area: 4 / 2 / 5 / 3;
}
.div9 {
grid-area: 3 / 3 / 4 / 4;
}
.div10 {
grid-area: 3 / 5 / 4 / 6;
}
.div11 {
grid-area: 3 / 7 / 4 / 8;
}
.div12 {
grid-area: 2 / 6 / 3 / 7;
}
.div13 {
grid-area: 2 / 4 / 3 / 5;
}
.div14 {
grid-area: 1 / 5 / 2 / 6;
}
.triangle {
width: 600px;
height: 520px;
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-template-rows: repeat(5, 1fr);
grid-column-gap: 0px;
grid-row-gap: 0px;
}
3 years ago
.circle {
width: 50px;
height: 50px;
3 years ago
clip-path: circle();
3 years ago
text-align: center;
color: white;
3 years ago
}
.pole {
cursor: pointer;
background-color: #8fbcbb;
}
.hole {
cursor: default;
background-color: #d8dee9;
3 years ago
}
.pick {
cursor: pointer;
background-color: #a3be8c;
}
.dest {
cursor: pointer;
background-color: #81a1c1;
}
:global(body) {
background-color: #eceff4;
margin: 0;
padding: 15px;
}
.restart {
cursor: pointer;
}
.playing {
visibility: hidden;
}
.bold {
font-weight: bold;
}
3 years ago
</style>
<main>
<div>
<span class="restart" class:bold on:click={restart}>RESTART GAME</span>
<span data-cy="game-over" class:playing> | GAME OVER</span>
</div>
3 years ago
<div class="triangle">
{#each circles as _, i}
{#if circles[i] == hole}
<div
in:receive={{ key: i }}
out:send={{ key: i }}
class="circle div{i} hole"
on:click={() => change(i)}>
{i}
</div>
{/if}
{#if circles[i] == pole}
<div
in:receive={{ key: i }}
out:send={{ key: i }}
class="circle div{i} pole"
on:click={() => change(i)}>
{i}
</div>
{/if}
{#if circles[i] == pick}
<div
in:receive={{ key: i }}
out:send={{ key: i }}
class="circle div{i} pick"
on:click={() => change(i)}>
{i}
</div>
{/if}
{#if circles[i] == dest}
<div
in:receive={{ key: i }}
out:send={{ key: i }}
class="circle div{i} dest"
on:click={() => change(i)}>
{i}
</div>
{/if}
3 years ago
{/each}
3 years ago
</div>
</main>