Commit 9b79e4a4 authored by Sebastian Speitel's avatar Sebastian Speitel
Browse files

seperate Grid from App

add fem-bootstrap
parent 1e80e27a
......@@ -331,6 +331,11 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
"bootstrap": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
"integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
......@@ -1018,6 +1023,15 @@
"reusify": "^1.0.4"
}
},
"fem-bootstrap": {
"version": "git+https://bitbucket.fem.tu-ilmenau.de/scm/~clerie/fem-bootstrap.git#63e7998bcfa1539c304faee71f6eec514041f6e3",
"from": "git+https://bitbucket.fem.tu-ilmenau.de/scm/~clerie/fem-bootstrap.git",
"requires": {
"bootstrap": "4.3.1",
"jquery": "1.9.1",
"popper.js": "1.14.7"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
......@@ -1424,6 +1438,11 @@
}
}
},
"jquery": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-1.9.1.tgz",
"integrity": "sha1-5M1INfqu+63lNYV2E8D8P/KtrzQ="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
......@@ -1781,6 +1800,11 @@
"find-up": "^4.0.0"
}
},
"popper.js": {
"version": "1.14.7",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz",
"integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ=="
},
"postcss": {
"version": "7.0.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
......
......@@ -17,6 +17,7 @@
"typescript": "^4.0.2"
},
"dependencies": {
"fem-bootstrap": "git+https://bitbucket.fem.tu-ilmenau.de/scm/~clerie/fem-bootstrap.git",
"vue": "^3.0.0-rc.8"
}
}
<template>
<div>
<table>
<tr v-for="y in height" :key="y">
<td
v-for="x in width"
:key="x"
@click="click(x, y)"
:class="getCell(x, y)"
></td>
</tr>
</table>
<!-- <ul>
<li v-for="(ship, i) of ships" :key="i">
{{ Math.max(ship.sizeX, ship.sizeY) }}
</li>
</ul> -->
<template v-if="phase === 'setup'">
<v-grid v-model:grid="grid" @clicked="click" />
<button @click="grid.reset()">Reset</button>
<button :disabled="!valid" @click="phase = 'running'">Abschicken</button>
</template>
<div v-else>
<v-grid />
<v-grid />
</div>
<ul>
<template v-for="l in Math.max(width, height)">
<template v-for="l in Math.max(grid.width, grid.height)">
<li
v-if="required[l] || lengths[l]"
v-if="required[l] || grid.shipCount(l)"
:key="l"
:style="`color:${
(required[l] || 0) === (lengths[l] || 0) ? 'green' : 'red'
(required[l] || 0) === grid.shipCount(l) ? 'green' : 'red'
}`"
>
{{ l }}er: {{ lengths[l] || 0 }} von {{ required[l] || 0 }}
{{ l }}er: {{ grid.shipCount(l) }} von {{ required[l] || 0 }}
</li>
</template>
</ul>
<button @click="reset">Reset</button>
<button :disabled="!valid">Abschicken</button>
<br />
<textarea readonly v-text="json" />
</div>
</template>
<script lang="ts">
import { reactive, ref, computed } from "vue";
enum Cell {
UNKNOWN = "unknown",
WATER = "water",
SHIP = "ship",
DESTROYED = "destroyed"
}
interface Ship {
x: number;
y: number;
sizeX: number;
sizeY: number;
}
import { reactive, ref, computed, onMounted } from "vue";
import { Cell, getCell, setCell, Grid } from "./gameLogic";
import VGrid from "./components/Grid.vue";
export default {
components: { VGrid },
setup() {
const grid = reactive(new Map<string, Cell>());
const grid = reactive(new Grid(12, 6));
const phase = ref("setup");
//@ts-ignore
window.grid = grid;
const width = ref(13);
const height = ref(6);
const required = {
1: 0,
2: 3,
......@@ -68,127 +51,37 @@ export default {
5: 1
};
function getCell(x: number, y: number) {
let cell = grid.get(`${x | 0},${y | 0}`);
if (cell === undefined) cell = Cell.UNKNOWN;
return cell;
}
function setCell(x: number, y: number, cell: Cell) {
if (getCell(x - 1, y - 1) === Cell.SHIP) return;
if (getCell(x + 1, y - 1) === Cell.SHIP) return;
if (getCell(x + 1, y + 1) === Cell.SHIP) return;
if (getCell(x - 1, y + 1) === Cell.SHIP) return;
grid.set(`${x | 0},${y | 0}`, cell);
return true;
}
function reset() {
for (let x = 1, X = width.value; x <= X; x++)
for (let y = 1, Y = height.value; y <= Y; y++) {
setCell(x, y, Cell.WATER);
}
}
function click(x: number, y: number) {
const old = getCell(x, y);
const old = getCell(grid, x, y);
if (old === Cell.UNKNOWN || old === Cell.WATER) {
setCell(x, y, Cell.SHIP);
setCell(grid, x, y, Cell.SHIP);
return;
}
if (old === Cell.SHIP) {
setCell(x, y, Cell.WATER);
setCell(grid, x, y, Cell.WATER);
return;
}
}
const ships = computed(() => {
const found = new Set<Ship>();
const visited = new Set<string>();
function visit(x: number, y: number, lookup = true): Cell {
const coords = `${x | 0},${y | 0}`;
if (visited.has(coords)) return;
visited.add(coords);
const cell = getCell(x, y);
if (lookup) return cell;
if (cell !== Cell.SHIP) return;
let sizeX: number = 1;
while (visit(x + sizeX, y) === Cell.SHIP) sizeX++;
const ships = computed(() => grid.ships);
let sizeY: number = 1;
while (visit(x, y + sizeY) === Cell.SHIP) sizeY++;
if (sizeX > 1 && sizeY > 1) {
alert("Invalid ships");
}
found.add({ x, y, sizeX, sizeY });
}
for (let x = 1, X = width.value; x <= X; x++)
for (let y = 1, Y = height.value; y <= Y; y++) {
visit(x, y, false);
}
return found;
});
const lengths = computed(() => {
const lengths = {};
for (let s of ships.value) {
const l = Math.max(s.sizeX, s.sizeY);
lengths[l] = (lengths[l] ? lengths[l] : 0) + 1;
}
return lengths;
});
const valid = computed(() => {
for (let l = 0; l < Math.max(width.value, height.value); l++) {
const r = required[l] || 0;
const s = lengths.value[l] || 0;
if (r !== s) return false;
}
return true;
});
const valid = computed(() => grid.valid(required));
const json = computed(() => {
return JSON.stringify([...ships.value.values()]);
});
return {
width,
height,
phase,
grid,
getCell,
click,
ships,
lengths,
required,
valid,
reset,
json
};
}
};
</script>
<style>
td {
width: 3em;
height: 3em;
}
.water,
.unknown {
background: blue;
}
.ship {
background: gray;
}
</style>
<template>
<table>
<tr v-for="y in grid.height" :key="y">
<td
v-for="x in grid.width"
:key="x"
@click="click(x, y)"
:class="getCell(grid, x, y)"
></td>
</tr>
</table>
</template>
<script lang="ts">
import { toRefs, computed } from "vue";
import { Cell, getCell, Grid } from "../gameLogic";
export default {
props: { grid: Grid },
setup(
props: {
grid: {
required: true;
type: Map<string, Cell>;
};
},
{ emit }
) {
const grid = computed({
get: () => props.grid,
set: g => emit("update:grid", g)
});
function click(x: number, y: number) {
emit("clicked", x, y);
}
return { getCell, grid, click };
}
};
</script>
<style scoped>
table {
border-collapse: separate;
border-width: 0.5em;
}
td {
width: 3em;
height: 3em;
}
.water,
.unknown {
background: blue;
}
.ship {
background: gray;
}
</style>
import { computed } from "@vue/reactivity";
export enum Cell {
UNKNOWN = "unknown",
WATER = "water",
SHIP = "ship",
DESTROYED = "destroyed"
}
export interface Ship {
x: number;
y: number;
sizeX: number;
sizeY: number;
}
export class Grid extends Map<string, Cell> {
width: number;
height: number;
constructor(width: number, height: number) {
super();
this.width = width;
this.height = height;
}
get ships() {
const found = new Set<Ship>();
const visited = new Set<string>();
const self = this;
function visit(x: number, y: number, lookup = true): Cell {
const coords = `${x | 0},${y | 0}`;
if (visited.has(coords)) return;
visited.add(coords);
const cell = getCell(self, x, y);
if (lookup) return cell;
if (cell !== Cell.SHIP) return;
let sizeX: number = 1;
while (visit(x + sizeX, y) === Cell.SHIP) sizeX++;
let sizeY: number = 1;
while (visit(x, y + sizeY) === Cell.SHIP) sizeY++;
if (sizeX > 1 && sizeY > 1) {
alert("Invalid ships");
}
found.add({ x, y, sizeX, sizeY });
}
for (let x = 1, X = this.width; x <= X; x++)
for (let y = 1, Y = this.height; y <= Y; y++) {
visit(x, y, false);
}
return found;
}
shipCount(length: number) {
let cnt = 0;
for (let ship of this.ships) {
if (Math.max(ship.sizeX, ship.sizeY) === length) cnt++;
}
return cnt;
}
valid(required: { [length: number]: number }) {
return computed(() => {
for (let l = 0; l < Math.max(this.height, this.width); l++) {
const r = required[l] || 0;
if (r !== this.shipCount(l)) return false;
}
return true;
});
}
reset() {
for (let x = 1, X = this.width; x <= X; x++)
for (let y = 1, Y = this.height; y <= Y; y++) {
setCell(this, x, y, Cell.WATER);
}
}
}
export function getCell(grid: Grid, x: number, y: number) {
let cell = grid.get(`${x | 0},${y | 0}`);
if (cell === undefined) cell = Cell.UNKNOWN;
return cell;
}
export function setCell(grid: Grid, x: number, y: number, cell: Cell) {
if (getCell(grid, x - 1, y - 1) === Cell.SHIP) return;
if (getCell(grid, x + 1, y - 1) === Cell.SHIP) return;
if (getCell(grid, x + 1, y + 1) === Cell.SHIP) return;
if (getCell(grid, x - 1, y + 1) === Cell.SHIP) return;
grid.set(`${x | 0},${y | 0}`, cell);
return true;
}
import "../node_modules/fem-bootstrap/dist/css/fem-bootstrap.css";
import { createApp } from "vue";
import App from "./App.vue";
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment