Hightlight active row/column, show error when field cannot be selected.

This commit is contained in:
2020-12-22 20:27:17 +01:00
parent eebca998cb
commit 411720765d
5 changed files with 99 additions and 15 deletions

View File

@@ -27,7 +27,7 @@
matrix: [ matrix: [
"AA", "BB", "CC", "AA", "BB", "CC",
"DD", "AA", "BB", "DD", "AA", "BB",
"CC", "DD", "AA", "CC", "DD", "DD",
], ],
sequences: [ sequences: [
["AA", "CC", "DD"], ["AA", "CC", "DD"],

View File

@@ -2,34 +2,84 @@
<div class="matrix"> <div class="matrix">
<h2>Code-Matrix</h2> <h2>Code-Matrix</h2>
<div class="matrix-row" v-for="i in size" :key="i"> <div class="matrix-row" v-for="i in size" :key="i">
<div class="matrix-column" v-for="j in size" :key="j" v-on:click="select(i, j)"> <div :class="{'matrix-column': true, active: active.row === j || active.column === i, used: game.getCell(j-1, i-1).isUsed, error: error.row === j && error.column === i}"
{{matrix[(j - 1)*size + (i - 1)]}} v-for="j in size" :key="j"
v-on:click="select(j, i)">
{{game.getCell(j-1, i-1).value}}
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Game } from "@/game/Game"; import { Game, matchState, matchSelectionState } from "@/game/Game";
import {defineComponent, inject, computed, Ref} from "vue"; import {defineComponent, inject, computed, Ref, ref} from "vue";
export default defineComponent({ export default defineComponent({
setup() { setup() {
const game = inject("game") as Ref<Game>; const game = inject("game") as Ref<Game>;
const size = computed(() => game.value.size); const size = computed(() => game.value.size);
const matrix = computed(() => game.value.matrix); const matrix = computed(() => game.value.matrix);
const state = computed(() => game.value.state);
const active = ref({row: -1, column: -1});
const error = ref({row: -1, column: -1});
let errorTimeout: number;
function select(row: number, column: number) { function select(row: number, column: number) {
try { try {
game.value.pick(row-1, column-1); const newState = game.value.pick(row-1, column-1);
matchState({
Won: () => {
console.log("Won!");
},
Lost: () => {
console.log("Lost!");
},
InProgress: state => {
matchSelectionState({
Free: () => {/**/},
Row: () => {
active.value = {
row: -1,
column,
};
},
Column: () => {
active.value = {
row,
column: -1,
};
},
})(state);
},
})(newState);
} catch (e) { } catch (e) {
console.log("nö!"); error.value = {
row,
column,
};
if(errorTimeout) {
clearTimeout(errorTimeout);
}
errorTimeout = setTimeout(() => {
error.value = {
row: -1,
column: -1,
};
}, 500) as unknown as number;
} }
} }
return { return {
game,
size, size,
matrix, matrix,
state,
active,
error,
select select
} }
} }

View File

@@ -14,8 +14,20 @@
const game = inject("game") as Ref<Game>; const game = inject("game") as Ref<Game>;
const remainingMilliseconds = ref(game.value.remainingMilliseconds); const remainingMilliseconds = ref(game.value.remainingMilliseconds);
const timeoutMilliseconds = computed(() => game.value.timeoutMilliseconds); const timeoutMilliseconds = computed(() => game.value.timeoutMilliseconds);
const progress = computed(() => remainingMilliseconds.value/timeoutMilliseconds.value*100); const progress = computed(() => {
const countdown = computed(() => (remainingMilliseconds.value/1000).toFixed(2)); if(remainingMilliseconds.value > 0) {
return remainingMilliseconds.value/timeoutMilliseconds.value*100;
}
return 0;
});
const countdown = computed(() => {
if(remainingMilliseconds.value > 0) {
return (remainingMilliseconds.value/1000).toFixed(2);
}
return "0.00";
});
const updateTime = () => { const updateTime = () => {
remainingMilliseconds.value = game.value.remainingMilliseconds; remainingMilliseconds.value = game.value.remainingMilliseconds;

View File

@@ -35,7 +35,7 @@ interface StateSpecificHandler<T> {
InProgress(selectionState: SelectionState): T InProgress(selectionState: SelectionState): T
} }
function matchState<T>(h: StateSpecificHandler<T>): (a: State) => T { export function matchState<T>(h: StateSpecificHandler<T>): (a: State) => T {
return (a: State) => { return (a: State) => {
switch (a) { switch (a) {
case EndState.Won: case EndState.Won:
@@ -54,7 +54,7 @@ interface SelectionStateSpecificHandler<T> {
Column(column: number): T; Column(column: number): T;
} }
function matchSelectionState<T>(h: SelectionStateSpecificHandler<T>): (a: SelectionState) => T { export function matchSelectionState<T>(h: SelectionStateSpecificHandler<T>): (a: SelectionState) => T {
return (a: SelectionState) => { return (a: SelectionState) => {
switch (a.selectionMode) { switch (a.selectionMode) {
case SelectionMode.FreePick: case SelectionMode.FreePick:
@@ -162,7 +162,7 @@ export class Game {
} }
} }
pick(row: number, column: number): void { pick(row: number, column: number): State {
if (row < 0 || column < 0 || row >= this.size || column >= this.size) { if (row < 0 || column < 0 || row >= this.size || column >= this.size) {
throw new IllegalMoveError() throw new IllegalMoveError()
} }
@@ -215,6 +215,7 @@ export class Game {
})(this.state) })(this.state)
this.checkEndGame(); this.checkEndGame();
return this.state;
} }
get maxBufferLength(): number { get maxBufferLength(): number {

View File

@@ -2,6 +2,8 @@
$background: #121018; $background: #121018;
$yellow: #d0ee58; $yellow: #d0ee58;
$red: rgb(211, 0, 0);
$dark-gray: rgb(49, 49, 49);
* { * {
box-sizing: border-box; box-sizing: border-box;
@@ -103,16 +105,35 @@ main {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 32px; width: 64px;
height: 32px; height: 64px;
margin: 0 5px 5px 0; margin: 0 5px 5px 0;
cursor: pointer; cursor: pointer;
font-size: 32px;
&:hover { &:hover {
background: $yellow; background: $yellow !important;
color: $background; color: $background;
} }
} }
.used {
opacity: 0.5;
&:hover {
background: none;
color: #fff;
}
}
.active {
background: $dark-gray;
}
.error {
background: $red !important;
color: #fff;
}
} }
h1, h2 { h1, h2 {