From 6b08c641e9ad1f3b1c7ecc626efc0ee34d3d6925 Mon Sep 17 00:00:00 2001 From: Maksymilian Jopek Date: Sun, 27 Mar 2022 23:06:05 +0200 Subject: v0.1.0 - Game without ending --- src/Ball.ts | 38 ++++++++++++++++++++++++++++++++--- src/consts.ts | 1 + src/main.ts | 11 ++++------- src/map.ts | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/style.css | 4 ++-- src/ui.ts | 57 ++++++++++++++++++++++++++++++++++++++--------------- src/utils.ts | 4 ++++ 7 files changed, 149 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/Ball.ts b/src/Ball.ts index a8dc912..e2c04f1 100644 --- a/src/Ball.ts +++ b/src/Ball.ts @@ -1,5 +1,6 @@ import { START_NO_OF_BALLS, MAP_WIDTH, MAP_HEIGHT, COLORS } from "./consts"; import { getRandomInt, getRandomEl } from "./utils"; +import { getTd } from "./ui"; export default class Ball { x: number; @@ -11,15 +12,46 @@ export default class Ball { this.y = y; this.color = color; } - static generateNewBalls(): Array { + + get td() { + return getTd(this.x, this.y); + } + isEqual(b: Ball) { + if (!b) throw Error("b is undeifneds") + if (!this) throw Error("this is undeifneds") + return this.x === b.x && this.y === b.y; + } + + static generateNewBalls(currentBalls: Ball[]): Array { const out = []; for (let i = 0; i < START_NO_OF_BALLS; i++) { let x: number, y: number, color: string; do { - [x, y, color] = [getRandomInt(0, MAP_HEIGHT), getRandomInt(0, MAP_WIDTH), getRandomEl(COLORS)]; - } while (out.filter(b => b.x === x && b.y === y).length !== 0) + [x, y, color] = [getRandomInt(0, MAP_HEIGHT), getRandomInt(0, MAP_WIDTH), Nexts.pop()]; + } while ( + out.find(b => b.x === x && b.y === y) || + currentBalls.find(b => b.x === x && b.y === y) + ) out.push(new Ball(x, y, color)); } return out; } } + +export class Nexts { + static els = Array.from(document.querySelectorAll("#next div")) as HTMLDivElement[] + static setEls() { + for (const el of this.els) { + if (el.style.backgroundColor === "") { + el.style.backgroundColor = getRandomEl(COLORS); + } + } + } + static pop() { + const out = this.els[0].style.backgroundColor; + this.els[0].style.backgroundColor = this.els[1].style.backgroundColor; + this.els[1].style.backgroundColor = this.els[2].style.backgroundColor + this.els[2].style.backgroundColor = getRandomEl(COLORS) + return out; + } +} diff --git a/src/consts.ts b/src/consts.ts index 1798a45..f97cbd1 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -4,3 +4,4 @@ export const MAP_HEIGHT = 9; export const MAP_WIDTH = 9; export const TD_SIZE = "50px"; export const CIRCLE_SIZE = "35px"; +export const DELETE_FROM_BALLS = 3; diff --git a/src/main.ts b/src/main.ts index 23355bf..50d41e6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,16 +1,13 @@ import './style.css' -import Ball from "./Ball" +import Ball, { Nexts } from "./Ball" import { genGameTable, render } from "./ui"; declare global { interface Window { balls: Ball[]; } } -const balls = Ball.generateNewBalls(); -window.balls = balls; -// Ball.generateStartBalls(); -// const map = <(Ball | null)[][]>[]; +Nexts.setEls(); +window.balls = Ball.generateNewBalls([]); genGameTable(); - -render(balls); +render(); diff --git a/src/map.ts b/src/map.ts index 44a970c..9fa85ef 100644 --- a/src/map.ts +++ b/src/map.ts @@ -1,7 +1,68 @@ import Ball from "./Ball"; -import { MAP_HEIGHT, MAP_WIDTH } from "./consts"; +import { DELETE_FROM_BALLS, MAP_HEIGHT, MAP_WIDTH } from "./consts"; import { Graph } from "./pathfinder/Graph"; +export function findToRemove(balls: Ball[]): Ball[] { + const out = new Set() + for (const ball of balls) { + const xNeighbours = new Set(); + for (let x = ball.x; x < MAP_HEIGHT; x++) { + const b = balls.find(b => b.y === ball.y && b.x === x && b.color === ball.color); + if (!b) break; + xNeighbours.add(b) + } + for (let x = ball.x - 1; x >= 0; x--) { + const b = balls.find(b => b.y === ball.y && b.x === x && b.color === ball.color) + if (!b) break; + xNeighbours.add(b) + } + + const yNeighbours = new Set(); + for (let y = ball.y; y < MAP_WIDTH; y++) { + const b = balls.find(b => b.x === ball.x && b.y === y && b.color === ball.color); + if (!b) break; + yNeighbours.add(b) + } + for (let y = ball.y - 1; y >= 0; y--) { + const b = balls.find(b => b.x === ball.x && b.y === y && b.color === ball.color) + if (!b) break; + yNeighbours.add(b) + } + + // same(Sign)XYNeigbours + const sxyNeighbours = new Set(); + for (let x = ball.x, y = ball.y; x >= 0 && y >= 0; x--, y--) { + const b = balls.find(b => b.x === x && b.y === y && b.color === ball.color) + if (!b) break; + sxyNeighbours.add(b) + } + for (let x = ball.x + 1, y = ball.y + 1; x < MAP_HEIGHT && y < MAP_WIDTH; x--, y--) { + const b = balls.find(b => b.x === x && b.y === y && b.color === ball.color) + if (!b) break; + sxyNeighbours.add(b) + } + + // diffrent(Sign)XYNeigbours + const dxyNeighbours = new Set(); + for (let x = ball.x, y = ball.y; x >= 0 && y < MAP_WIDTH; x--, y++) { + const b = balls.find(b => b.x === x && b.y === y && b.color === ball.color) + if (!b) break; + dxyNeighbours.add(b) + } + for (let x = ball.x + 1, y = ball.y - 1; x >= 0 && y >= 0; x++, y--) { + const b = balls.find(b => b.x === x && b.y === y && b.color === ball.color) + if (!b) break; + dxyNeighbours.add(b) + } + + const sets = [xNeighbours, yNeighbours, sxyNeighbours, dxyNeighbours] + for (const s of sets) { + if (s.size >= DELETE_FROM_BALLS) s.forEach(b => out.add(b)) + } + } + return [...out]; +} + export type Map = (Ball | null)[][]; export function genMap(balls: Array): Map { const map = []; diff --git a/src/style.css b/src/style.css index 6f617ad..8803e96 100644 --- a/src/style.css +++ b/src/style.css @@ -2,7 +2,7 @@ font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - color: #2c3e50; + color: white; background-color: black; } @@ -15,7 +15,7 @@ td { width: 50px; height: 50px; } -td div { +td div, #next div { width: 35px; height: 35px; margin: auto auto; diff --git a/src/ui.ts b/src/ui.ts index 40e65c6..95ceb5c 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,6 +1,7 @@ import Ball from "./Ball"; import { MAP_WIDTH, MAP_HEIGHT, TD_SIZE } from "./consts"; -import { genGraph, genMap } from "./map"; +import { sleep } from "./utils"; +import { findToRemove, genGraph, genMap } from "./map"; import findPath, { Path } from "./pathfinder"; let selectedBall: Ball | null = null; @@ -19,25 +20,30 @@ export async function nextTurn() { getTd(v.x!, v.y!).style.backgroundColor = "rgba(50, 50, 50, 0.8)"; } - await sleep(2000); + await sleep(1000); + + const toRemove = findToRemove(window.balls); + + + window.balls = window.balls.filter(ba => !toRemove.find(b => ba.isEqual(b))) + for (const b of toRemove) { + clearTd(b.td) + } + pointsEl.innerText = (parseInt(pointsEl.innerText) + toRemove.length).toString() setCurrentPath([]); - window.balls.push(...Ball.generateNewBalls()); + window.balls.push(...Ball.generateNewBalls(window.balls)); render(); turnIsChanging = false; } -async function sleep(time: number) { - return new Promise(resolve => setTimeout(resolve, time)); -} + export function tdOnClick(_e: PointerEvent) { if (!currentPath.length || turnIsChanging) return; const std = getTd(currentPath[0].x!, currentPath[0].y!); - (std.firstChild as HTMLDivElement).style.width = ""; - (std.firstChild as HTMLDivElement).style.height = ""; + clearTd(std) const ib = window.balls.findIndex(b => b.x === currentPath[0].x && b.y === currentPath[0].y)! window.balls[ib].x = currentPath[currentPath.length - 1].x! window.balls[ib].y = currentPath[currentPath.length - 1].y! - std.innerHTML = ""; selectedBall = null; render(window.balls); nextTurn(); @@ -57,15 +63,22 @@ export function render(balls?: Ball[]) { for (const ball of balls) { const { x, y, color } = ball; const td = getTd(x, y); - (td.firstChild as HTMLDivElement).style.backgroundColor = color; + td.firstChild.style.backgroundColor = color; - td.onclick = () => { + td.onmousedown = () => { if (turnIsChanging) return; const circle = td.firstChild as HTMLDivElement; setCurrentPath([]); const smallerCircle = () => { - circle.style.width = ""; - circle.style.height = ""; + if (!selectedBall) return; + selectedBall.td.firstChild.style.width = "" + selectedBall.td.firstChild.style.height = "" + } + getGameMapEl().onmouseleave = () => { + if (turnIsChanging) return; + setCurrentPath([]); + smallerCircle(); + selectedBall = null; } if (circle.style.width === TD_SIZE) { @@ -81,6 +94,15 @@ export function render(balls?: Ball[]) { }; } } +export function clearTd(td: Td) { + if (td.localName !== "td") { + console.log(td) + throw new Error("Not td passed to clearTd()"); + } + td.innerHTML = "" + td.onmousedown = null; + td.appendChild(document.createElement("div")) +} export function genGameTable() { const table = getGameMapEl(); for (let i = 0; i < MAP_HEIGHT; i++) { @@ -96,11 +118,14 @@ export function genGameTable() { } table.appendChild(tr) } - } export function getGameMapEl(): HTMLTableElement { return document.querySelector('table')! } -export function getTd(x: number, y: number): HTMLTableDataCellElement { - return getGameMapEl().children[x].children[y] as HTMLTableDataCellElement; +export interface Td extends HTMLTableCellElement { + firstChild: HTMLDivElement; +} +export function getTd(x: number, y: number): Td { + return getGameMapEl().children[x].children[y] as Td; } +export const pointsEl = document.querySelector("h3 span") as HTMLSpanElement diff --git a/src/utils.ts b/src/utils.ts index 0dc0bb1..a767896 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -7,3 +7,7 @@ export function getRandomInt(min: number, max: number): number { export function getRandomEl(arr: Array): T { return arr[getRandomInt(0, arr.length)]; } +export async function sleep(time: number) { + return new Promise(resolve => setTimeout(resolve, time)); +} + -- cgit v1.3.1