mirror of
https://github.com/Username-ejg-not-available/snake-vuejs.git
synced 2024-10-27 19:24:01 +00:00
Snake
This commit is contained in:
commit
7110d73ea6
20
game.py
Normal file
20
game.py
Normal file
@ -0,0 +1,20 @@
|
||||
import http.server
|
||||
import socketserver
|
||||
import webbrowser
|
||||
|
||||
class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||
extensions_map={
|
||||
".js": "application/x-javascript",
|
||||
".html": "text/html",
|
||||
".css": "text/css",
|
||||
".json": "application/json",
|
||||
"": "application/octet-stream",
|
||||
}
|
||||
|
||||
PORT = 8000
|
||||
|
||||
httpd = socketserver.TCPServer(("", PORT), HTTPRequestHandler)
|
||||
webbrowser.register('firefox',None,webbrowser.BackgroundBrowser("C:\\Program Files\\Mozilla Firefox\\firefox.exe"))
|
||||
#input("zonks:")
|
||||
webbrowser.get('firefox').open_new_tab("http://localhost:8000")
|
||||
httpd.serve_forever()
|
17
index.html
Normal file
17
index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
<title>Snake</title>
|
||||
<link rel="stylesheet" href="./src/style/css.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="vuewrapper">
|
||||
<top-comp></top-comp>
|
||||
</div>
|
||||
<script src='./lib/vue.js'></script>
|
||||
<script src='./lib/vuetranslit.js' type='module'></script>
|
||||
<script src='./src/main.js' type='module'></script>
|
||||
</body>
|
||||
</html>
|
11965
lib/vue.js
Normal file
11965
lib/vue.js
Normal file
File diff suppressed because it is too large
Load Diff
72
lib/vuetranslit.js
Normal file
72
lib/vuetranslit.js
Normal file
@ -0,0 +1,72 @@
|
||||
export default class Transliterator {
|
||||
constructor(components) {
|
||||
this.components = components;
|
||||
this.execute();
|
||||
}
|
||||
|
||||
execute() {
|
||||
for (const Comp of this.components) {
|
||||
|
||||
const method_list = Object.getOwnPropertyNames(Comp.prototype);
|
||||
|
||||
const watch = {}
|
||||
const methods = {}
|
||||
const computed = {}
|
||||
|
||||
for (let x of method_list) {
|
||||
if (x.startsWith("watch_")) {
|
||||
let name = x.substr(6);
|
||||
const handler = function(...args) {
|
||||
return Comp.prototype[x].bind(this)(...args);
|
||||
}
|
||||
watch[name] = handler;
|
||||
} else if (x.startsWith("compute_")) {
|
||||
let name = x.substr(8);
|
||||
const handler = function(...args) {
|
||||
return Comp.prototype[x].bind(this)(...args);
|
||||
}
|
||||
computed[name] = handler;
|
||||
} else {
|
||||
const handler = function(...args) {
|
||||
return Comp.prototype[x].bind(this)(...args);
|
||||
}
|
||||
methods[x] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
Vue.component(Comp.tag,{
|
||||
props: Comp.props,
|
||||
template: Comp.template,
|
||||
data: () => {
|
||||
return new Comp();
|
||||
},
|
||||
watch,
|
||||
computed,
|
||||
methods,
|
||||
created: function() {
|
||||
if (typeof this.on_create === 'function') this.on_create();
|
||||
},
|
||||
updated: function() {
|
||||
if (typeof this.on_update === 'function') this.on_update();
|
||||
},
|
||||
mounted: function() {
|
||||
if (typeof this.on_mount === 'function') this.on_mount();
|
||||
},
|
||||
destroyed: function() {
|
||||
if (typeof this.on_destroy === 'function') this.on_destroy();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Component {
|
||||
static get tag() { return ""; }
|
||||
static get props() { return {} }
|
||||
static get template() { return ""; }
|
||||
|
||||
on_create() {}
|
||||
on_update() {}
|
||||
on_mount() {}
|
||||
on_destroy() {}
|
||||
}
|
28
src/application.js
Normal file
28
src/application.js
Normal file
@ -0,0 +1,28 @@
|
||||
import {GameState,clone} from './util/util.js'
|
||||
|
||||
class GameApplication {
|
||||
|
||||
rowCount = 0;
|
||||
colCount = 0;
|
||||
gameWin = 'undefined';
|
||||
current_state = GameState.SizeSelect;
|
||||
hasAI = false;
|
||||
endFunction = null
|
||||
ready = false;
|
||||
passFunction = null;
|
||||
|
||||
get_current_state() {
|
||||
return clone(this.current_state);
|
||||
}
|
||||
|
||||
initEnd(victory) {
|
||||
this.endFunction(this.current_state, victory);
|
||||
}
|
||||
|
||||
tester(hand) {
|
||||
this.endFunction = hand;
|
||||
}
|
||||
}
|
||||
|
||||
const app = new GameApplication();
|
||||
export default app;
|
13
src/componentlist.js
Normal file
13
src/componentlist.js
Normal file
@ -0,0 +1,13 @@
|
||||
//list of imported component names
|
||||
import CellComponent from './components/CellComponent.js'
|
||||
import BoardComponent from './components/BoardComponent.js'
|
||||
import TopComponent from './components/TopComponent.js'
|
||||
import AIComponent from './components/AIComponent.js'
|
||||
|
||||
//put classnames in here
|
||||
export default [
|
||||
CellComponent,
|
||||
BoardComponent,
|
||||
TopComponent,
|
||||
AIComponent,
|
||||
]
|
251
src/components/AIComponent.js
Normal file
251
src/components/AIComponent.js
Normal file
@ -0,0 +1,251 @@
|
||||
import {Component} from '../../lib/vuetranslit.js'
|
||||
import app from '../application.js'
|
||||
import {GameState, snakeDirection} from '../util/util.js'
|
||||
|
||||
const template = `<div></div>`
|
||||
|
||||
class AIComponent extends Component {
|
||||
static get tag() { return 'ai'; }
|
||||
static get template() { return template; }
|
||||
static get props() { return {}; }
|
||||
|
||||
ready = app;
|
||||
hamiltonCircuit = [];
|
||||
move_snake = null;
|
||||
set_sD = null;
|
||||
|
||||
async play() {
|
||||
const start = parseInt(app.rowCount / 2);
|
||||
|
||||
this.createHamiltonCircuit(app.rowCount, app.colCount, start + ',2');
|
||||
let currInstruction = this.hamiltonCircuit.length - 1;
|
||||
|
||||
while (app.get_current_state() === GameState.Gameplay) {
|
||||
let nextLoc;
|
||||
if (currInstruction === this.hamiltonCircuit.length - 1) nextLoc = 0;
|
||||
else nextLoc = currInstruction + 1;
|
||||
|
||||
this.travel(currInstruction,nextLoc);
|
||||
|
||||
currInstruction = nextLoc;
|
||||
await this.sleep(Math.ceil(5000/(app.rowCount * app.colCount)));
|
||||
}
|
||||
}
|
||||
|
||||
travel(point1,point2) {
|
||||
const p1 = this.hamiltonCircuit[point1].split(',');
|
||||
const p2 = this.hamiltonCircuit[point2].split(',');
|
||||
|
||||
if (parseInt(p1[0]) < parseInt(p2[0])) {
|
||||
this.set_sD(snakeDirection.Down);
|
||||
} else if (parseInt(p1[0]) > parseInt(p2[0])) {
|
||||
this.set_sD(snakeDirection.Up);
|
||||
} else if (parseInt(p1[1]) < parseInt(p2[1])) {
|
||||
this.set_sD(snakeDirection.Right);
|
||||
} else if (parseInt(p1[1]) > parseInt(p2[1])) {
|
||||
this.set_sD(snakeDirection.Left);
|
||||
}
|
||||
this.move_snake();
|
||||
}
|
||||
|
||||
sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve,ms));
|
||||
}
|
||||
|
||||
createHamiltonCircuit(rows,cols,start) {
|
||||
const getLast = () => { return this.hamiltonCircuit[this.hamiltonCircuit.length - 1]; }
|
||||
this.move_hor(1,start);
|
||||
if (cols % 2) {
|
||||
/*
|
||||
10x7: top zigzag, vertical zigzag, full bottom zigzag
|
||||
10x9: top zigzag, vertical zigzag, full bottom zigzag
|
||||
*/
|
||||
if (rows % 4) {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === 1) break;
|
||||
this.move_hor_until(1,cols - 3,getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === 1) break;
|
||||
this.move_hor_until(-1,0,getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
}
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[1]) === cols - 2) break;
|
||||
this.move_vert(-1,getLast());
|
||||
this.move_hor(1,getLast());
|
||||
if (parseInt(getLast().split(',')[1]) === cols - 2) break;
|
||||
this.move_vert(1,getLast());
|
||||
this.move_hor(1,getLast());
|
||||
}
|
||||
while (true) {
|
||||
if (!this.move_hor(1,getLast())) break;
|
||||
if (!this.move_vert(1,getLast())) break;
|
||||
if (!this.move_hor(-1,getLast())) break;
|
||||
if (!this.move_vert(1,getLast())) break;
|
||||
}
|
||||
while (true) {
|
||||
this.move_hor(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[1]) === 0) break;
|
||||
this.move_vert_until(-1,parseInt(start.split(',')[0]) + 1, getLast());
|
||||
this.move_hor(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[1]) === 0) break;
|
||||
this.move_vert_until(1,rows - 1, getLast());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((cols - 1) % 4) {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === 0) break;
|
||||
this.move_hor_until(1,cols - 3, getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === 0) break;
|
||||
this.move_hor_until(-1,0, getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
}
|
||||
this.move_hor_until(1,cols - 1,getLast());
|
||||
while (true) {
|
||||
this.move_vert(1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === parseInt(start.split(',')[0]) + 1) break;
|
||||
this.move_hor(-1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === parseInt(start.split(',')[0]) + 1) break;
|
||||
this.move_hor(1,getLast());
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === 0) break;
|
||||
this.move_hor_until(1,cols - 2, getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === 0) break;
|
||||
this.move_hor_until(-1,0, getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
}
|
||||
this.move_hor_until(1,cols-1,getLast());
|
||||
this.move_vert_until(1,parseInt(start.split(',')[0]) + 1, getLast());
|
||||
}
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === rows - 1) break;
|
||||
this.move_hor_until(-1,1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === rows - 1) break;
|
||||
this.move_hor_until(1,cols-1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
}
|
||||
this.move_hor_until(-1,0,getLast());
|
||||
}
|
||||
this.move_vert_until(-1,parseInt(start.split(',')[0]),getLast());
|
||||
this.move_hor_until(1,parseInt(start.split(',')[1]),getLast());
|
||||
}
|
||||
else {
|
||||
if ((rows - parseInt(start.split(',')[0]) - (rows % 2)) % 2) {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === 1) break;
|
||||
this.move_hor_until(1,cols - 2,getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === 1) break;
|
||||
this.move_hor_until(-1,0, getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
}
|
||||
while (true) {
|
||||
if (!this.move_vert(-1,getLast())) break;
|
||||
if (!this.move_hor(1,getLast())) break;
|
||||
if (!this.move_vert(1,getLast())) break;
|
||||
if (!this.move_hor(1,getLast())) break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === 0) break;
|
||||
this.move_hor_until(1,cols - 2,getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === 0) break;
|
||||
this.move_hor_until(-1,0, getLast());
|
||||
this.move_vert(-1,getLast());
|
||||
}
|
||||
this.move_hor_until(1,cols - 1, getLast());
|
||||
}
|
||||
this.move_vert_until(1,parseInt(start.split(',')[0]) + 1,getLast());
|
||||
|
||||
if ((rows - parseInt(start.split(',')[0]) - 1) % 2) {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === rows - 1) break;
|
||||
this.move_hor_until(-1,1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === rows - 1) break;
|
||||
this.move_hor_until(1,cols - 1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
}
|
||||
this.move_hor_until(-1,0,getLast());
|
||||
}
|
||||
else {
|
||||
while (true) {
|
||||
if (parseInt(getLast().split(',')[0]) === rows - 2) break;
|
||||
this.move_hor_until(-1,1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
if (parseInt(getLast().split(',')[0]) === rows - 2) break;
|
||||
this.move_hor_until(1,cols - 1,getLast());
|
||||
this.move_vert(1,getLast());
|
||||
}
|
||||
while (true) {
|
||||
if (!this.move_vert(1,getLast())) break;
|
||||
if (!this.move_hor(-1,getLast())) break;
|
||||
if (!this.move_vert(-1,getLast())) break;
|
||||
if (!this.move_hor(-1,getLast())) break;
|
||||
}
|
||||
}
|
||||
this.move_vert_until(-1,parseInt(start.split(',')[0]),getLast());
|
||||
this.move_hor_until(1,parseInt(start.split(',')[1]),getLast());
|
||||
}
|
||||
}
|
||||
|
||||
move_vert_until(dir,row,start) {
|
||||
let lastLoc = start.split(',');
|
||||
while (parseInt(lastLoc[0]) != row) {
|
||||
let nextLoc = (parseInt(lastLoc[0]) + dir) + ',' + lastLoc[1];
|
||||
this.hamiltonCircuit.push(nextLoc);
|
||||
lastLoc = nextLoc.split(',');
|
||||
}
|
||||
}
|
||||
|
||||
move_hor_until(dir, col, start) {
|
||||
let lastLoc = start.split(',');
|
||||
while (parseInt(lastLoc[1]) != col) {
|
||||
let nextLoc = lastLoc[0] + ',' + (parseInt(lastLoc[1]) + dir);
|
||||
this.hamiltonCircuit.push(nextLoc);
|
||||
lastLoc = nextLoc.split(',');
|
||||
}
|
||||
}
|
||||
|
||||
move_vert(dir,start) {
|
||||
const currLoc = start.split(',');
|
||||
if (parseInt(currLoc[0]) + dir > -1 && parseInt(currLoc[0]) + dir < app.rowCount) {
|
||||
const newLoc = (parseInt(currLoc[0]) + dir) + ',' + currLoc[1];
|
||||
if (this.hamiltonCircuit.filter(x => x === newLoc).length === 0) {
|
||||
this.hamiltonCircuit.push(newLoc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
move_hor(dir,start) {
|
||||
const currLoc = start.split(',');
|
||||
if (parseInt(currLoc[1]) + dir > -1 && parseInt(currLoc[1]) + dir < app.colCount) {
|
||||
const newLoc = currLoc[0] + ',' + (parseInt(currLoc[1]) + dir);
|
||||
if (this.hamiltonCircuit.filter(x => x === newLoc).length === 0) {
|
||||
this.hamiltonCircuit.push(newLoc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
on_create() {
|
||||
this.set_sD = app.passFunction[1];
|
||||
this.move_snake = app.passFunction[0];
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
|
||||
export default AIComponent;
|
126
src/components/BoardComponent.js
Normal file
126
src/components/BoardComponent.js
Normal file
@ -0,0 +1,126 @@
|
||||
import {Component} from '../../lib/vuetranslit.js'
|
||||
import {snakeDirection as sD, CellState, GameState} from '../util/util.js'
|
||||
import app from '../application.js'
|
||||
|
||||
const template = `
|
||||
<div class="grid-container">
|
||||
<div class='gridrow' v-for="i in rows">
|
||||
<cell-comp v-for="j in cols" :key="(i-1) + ',' + (j-1)" :ref="(i-1) + ',' + (j-1)" :size='cellsize'></cell-comp>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
class BoardComponent extends Component {
|
||||
static get tag() { return 'board-comp'; }
|
||||
static get template() { return template; }
|
||||
static get props() {
|
||||
return {
|
||||
rows: Number,
|
||||
cols: Number,
|
||||
cellsize: Number,
|
||||
};
|
||||
}
|
||||
|
||||
bound_listener = null;
|
||||
|
||||
snake = [];
|
||||
snakeDirection = sD.Right;
|
||||
ateFood = false;
|
||||
|
||||
async on_create() {
|
||||
const start = parseInt(app.rowCount / 2);
|
||||
this.snake = [start + ",2", start + ",1", start + ",0"];
|
||||
|
||||
const keydown_fn = this.on_keydown.bind(this);
|
||||
this.bound_listener = keydown_fn;
|
||||
|
||||
window.addEventListener('keydown', keydown_fn);
|
||||
app.passFunction = [this.move_snake,this.set_snake_direction];
|
||||
app.ready = true;
|
||||
}
|
||||
|
||||
async on_destroy() {
|
||||
const keydown_fn = this.bound_listener;
|
||||
window.removeEventListener('keydown', keydown_fn);
|
||||
}
|
||||
|
||||
async on_mount() {
|
||||
for (let i of this.snake) {
|
||||
this.$refs[i][0].set_current_state(CellState.Snake);
|
||||
}
|
||||
this.place_food();
|
||||
}
|
||||
|
||||
move_snake() {
|
||||
if ((this.snakeDirection === sD.Up && this.snake[0].split(',')[0] === '0') ||
|
||||
(this.snakeDirection === sD.Down && this.snake[0].split(',')[0] == app.rowCount - 1) ||
|
||||
(this.snakeDirection === sD.Left && this.snake[0].split(',')[1] === '0') ||
|
||||
(this.snakeDirection === sD.Right && this.snake[0].split(',')[1] == app.colCount - 1)) {
|
||||
app.current_state = GameState.Fin;
|
||||
console.log("wall")
|
||||
app.initEnd(this.test_for_win());
|
||||
return;
|
||||
}
|
||||
let nextSpace = this.snake[0].split(',');
|
||||
if (this.snakeDirection === sD.Up) {
|
||||
nextSpace[0] = parseInt(nextSpace[0]) - 1;
|
||||
} else if (this.snakeDirection === sD.Down) {
|
||||
nextSpace[0] = parseInt(nextSpace[0]) + 1;
|
||||
} else if (this.snakeDirection === sD.Left) {
|
||||
nextSpace[1] = parseInt(nextSpace[1]) - 1;;
|
||||
} else if (this.snakeDirection === sD.Right) {
|
||||
nextSpace[1] = parseInt(nextSpace[1]) + 1;;
|
||||
}
|
||||
nextSpace = nextSpace[0] + ',' + nextSpace[1];
|
||||
if (this.snake.some(x => x === nextSpace)) {
|
||||
app.current_state = GameState.Fin;
|
||||
app.initEnd(this.test_for_win());
|
||||
return;
|
||||
}
|
||||
if (this.$refs[nextSpace][0].get_current_state() === "food") {
|
||||
this.ateFood = true;
|
||||
}
|
||||
this.snake.unshift(nextSpace);
|
||||
this.$refs[nextSpace][0].set_current_state(CellState.Snake);
|
||||
if (!this.ateFood) {
|
||||
this.$refs[this.snake[this.snake.length - 1]][0].set_current_state(CellState.Empty);
|
||||
this.snake.pop();
|
||||
} else {
|
||||
this.place_food();
|
||||
this.ateFood = false;
|
||||
}
|
||||
}
|
||||
|
||||
place_food() {
|
||||
if (this.test_for_win()) return;
|
||||
let loc = Math.floor(Math.random() * app.rowCount) + ',' + Math.floor(Math.random() * app.colCount);
|
||||
while (this.$refs[loc][0].get_current_state() !== CellState.Empty) {
|
||||
loc = Math.floor(Math.random() * app.rowCount) + ',' + Math.floor(Math.random() * app.colCount);
|
||||
}
|
||||
this.$refs[loc][0].set_current_state(CellState.Food);
|
||||
}
|
||||
|
||||
set_snake_direction(dir) {
|
||||
this.snakeDirection = dir;
|
||||
}
|
||||
|
||||
test_for_win() {
|
||||
return this.snake.length == app.rowCount * app.colCount;
|
||||
}
|
||||
|
||||
on_keydown(e) {
|
||||
if (!app.hasAI) {
|
||||
if (e.key === 'ArrowUp' && this.snakeDirection !== sD.Down) {
|
||||
this.snakeDirection = sD.Up;
|
||||
} else if (e.key === 'ArrowDown' && this.snakeDirection !== sD.Up) {
|
||||
this.snakeDirection = sD.Down;
|
||||
} else if (e.key === 'ArrowLeft' && this.snakeDirection !== sD.Right) {
|
||||
this.snakeDirection = sD.Left;
|
||||
} else if (e.key === 'ArrowRight' && this.snakeDirection !== sD.Left) {
|
||||
this.snakeDirection = sD.Right;
|
||||
} else return;
|
||||
this.move_snake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BoardComponent;
|
38
src/components/CellComponent.js
Normal file
38
src/components/CellComponent.js
Normal file
@ -0,0 +1,38 @@
|
||||
import {Component} from '../../lib/vuetranslit.js'
|
||||
import {CellState, clone} from '../util/util.js'
|
||||
|
||||
const template = `
|
||||
<div
|
||||
class='cell-component'
|
||||
v-bind:class='{ emptycell: state === CellState.Empty, snakecell: state === CellState.Snake, foodcell: state === CellState.Food }'
|
||||
:style="{width: size + 'px', height: size + 'px'}">
|
||||
|
||||
</div>
|
||||
`
|
||||
|
||||
class CellComponent extends Component {
|
||||
CellState = CellState;
|
||||
|
||||
static get tag() { return 'cell-comp'; }
|
||||
static get template() { return template; }
|
||||
static get props() {
|
||||
return {
|
||||
size: {
|
||||
type: Number,
|
||||
default: 30
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state = CellState.Empty;
|
||||
|
||||
set_current_state(stateVar) {
|
||||
this.state = stateVar;
|
||||
}
|
||||
|
||||
get_current_state() {
|
||||
return clone(this.state);
|
||||
}
|
||||
}
|
||||
|
||||
export default CellComponent;
|
92
src/components/TopComponent.js
Normal file
92
src/components/TopComponent.js
Normal file
@ -0,0 +1,92 @@
|
||||
import {Component} from '../../lib/vuetranslit.js'
|
||||
import {GameState, instructions} from '../util/util.js'
|
||||
import app from '../application.js'
|
||||
|
||||
const template = `
|
||||
<div class='top-level-container'>
|
||||
<div v-if="current_state === GameState.SizeSelect">
|
||||
<div>
|
||||
<hr class='separator--line'/>
|
||||
<h1 class='header_title' id="test">Snake</h1>
|
||||
<hr class='separator--dot' />
|
||||
</div>
|
||||
<div id="diminput">
|
||||
<span class="instructions" v-if='instructions'>{{instructions}}</span><br />
|
||||
<input type="number" v-model="rowinput"/>
|
||||
<input type="number" v-model="colinput"/>
|
||||
</div>
|
||||
<button id='ai-btn' v-bind:class="{ hasai: has_ai, noai: !has_ai }" @click='set_has_ai()'>AI?</button>
|
||||
<button id='start-btn' v-if="accept_bounds" @click='set_game_state(GameState.Gameplay)'>Start</button>
|
||||
</div>
|
||||
<div v-if="current_state === GameState.Gameplay">
|
||||
<board-comp ref="board" v-bind:rows="rowinput" v-bind:cols="colinput" v-bind:cellsize="celldim"></board-comp>
|
||||
<ai v-if="has_ai"></ai>
|
||||
</div>
|
||||
<div v-if="current_state === GameState.Fin">
|
||||
<span class="instructions" id="endcredits" v-if='instructions'>{{instructions.replace('{end}', victory)}}</span>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
class TopComponent extends Component {
|
||||
GameState = GameState
|
||||
|
||||
static get tag() { return 'top-comp'; }
|
||||
static get template() { return template; }
|
||||
static get props() { return {}; }
|
||||
|
||||
current_state = GameState.SizeSelect;
|
||||
rowinput = 6;
|
||||
colinput = 6;
|
||||
has_ai = app.hasAI;
|
||||
instructions = instructions[this.current_state];
|
||||
victory = "";
|
||||
|
||||
watch_rowinput() {
|
||||
this.rowinput = parseInt(this.rowinput);
|
||||
app.rowCount = this.rowinput;
|
||||
}
|
||||
|
||||
watch_colinput() {
|
||||
this.colinput = parseInt(this.colinput);
|
||||
app.colCount = this.colinput;
|
||||
}
|
||||
|
||||
watch_current_state() {
|
||||
this.instructions = instructions[this.current_state];
|
||||
}
|
||||
|
||||
compute_celldim() {
|
||||
let height = parseInt((window.screen.height - 150) / this.rowinput);
|
||||
let width = parseInt(window.screen.width / this.colinput);
|
||||
return Math.min(width, height);
|
||||
}
|
||||
|
||||
compute_accept_bounds() {
|
||||
return this.rowinput > 5 && this.colinput > 5 && (!(this.rowinput % 2) || !(this.colinput % 2));
|
||||
}
|
||||
|
||||
set_game_state(state) {
|
||||
this.current_state = state;
|
||||
app.current_state = state;
|
||||
}
|
||||
|
||||
set_has_ai() {
|
||||
app.hasAI = !app.hasAI;
|
||||
this.has_ai = app.hasAI;
|
||||
}
|
||||
|
||||
on_create() {
|
||||
app.rowCount = this.rowinput;
|
||||
app.colCount = this.colinput;
|
||||
this.current_state = app.get_current_state();
|
||||
|
||||
app.tester(async (state,victory) => {
|
||||
this.current_state = state;
|
||||
this.instructions = instructions[this.current_state];
|
||||
if (victory) this.victory = 'win';
|
||||
else this.victory = 'lose';
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default TopComponent;
|
11
src/main.js
Normal file
11
src/main.js
Normal file
@ -0,0 +1,11 @@
|
||||
import componentlist from './componentlist.js'
|
||||
import Transliterator from '../lib/vuetranslit.js'
|
||||
|
||||
const translit = new Transliterator(componentlist);
|
||||
|
||||
const vueapp = new Vue({
|
||||
el: '#vuewrapper',
|
||||
data: {},
|
||||
});
|
||||
|
||||
export {vueapp, translit};
|
191
src/style/css.css
Normal file
191
src/style/css.css
Normal file
@ -0,0 +1,191 @@
|
||||
#vuewrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
background-color: #182025;
|
||||
}
|
||||
|
||||
.header_title {
|
||||
text-align: center;
|
||||
letter-spacing: .1em;
|
||||
color: #ec8d2e;
|
||||
}
|
||||
|
||||
.top-level-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.gridrow {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
margin: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#diminput {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#diminput input {
|
||||
border: 1px solid #204a61;
|
||||
background: none;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
text-align:center;
|
||||
padding: 10px 0px;
|
||||
width: 5%;
|
||||
margin: 10px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#start-btn {
|
||||
/*width: 70px;
|
||||
height: 20px;
|
||||
margin: 10px;*/
|
||||
border: none;
|
||||
}
|
||||
|
||||
#ai-btn {
|
||||
/*width: 70px;
|
||||
height: 20px;
|
||||
margin: 10px;*/
|
||||
border: none;
|
||||
}
|
||||
|
||||
.hasai {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.noai {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#endcredits {
|
||||
color: white;
|
||||
font-size: 3em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
margin: 100px;
|
||||
padding: 100px;
|
||||
}
|
||||
|
||||
/*********CELLS**********
|
||||
*************************/
|
||||
.cell-component {
|
||||
|
||||
}
|
||||
|
||||
.cell-component.emptycell {
|
||||
background-color: #182025;
|
||||
border: 1px solid #1d272e;
|
||||
}
|
||||
|
||||
.cell-component.snakecell {
|
||||
background-color: #05ff3f;
|
||||
border: 1px solid #18b53c;
|
||||
}
|
||||
|
||||
.cell-component.foodcell {
|
||||
background-color: red;
|
||||
border: 1px solid darkred;
|
||||
}
|
||||
/*******END CELLS********
|
||||
*************************/
|
||||
|
||||
/********HR LINES********
|
||||
*************************/
|
||||
.separator--line {
|
||||
border: 0;
|
||||
border-bottom: 5px solid #ec8d2e;
|
||||
width: 0;
|
||||
-webkit-animation: separator-width 1s ease-out forwards;
|
||||
animation: separator-width 1s ease-out forwards;
|
||||
}
|
||||
|
||||
.separator--dot {
|
||||
border: 0;
|
||||
border-bottom: 5px dotted #ec8d2e;
|
||||
width: 0;
|
||||
-webkit-animation: separator-width 1.5s ease-out forwards;
|
||||
animation: separator-width 1.5s ease-out forwards;
|
||||
}
|
||||
|
||||
@-webkit-frames separator-width {
|
||||
0% {
|
||||
width: 0;
|
||||
}
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes separator-width {
|
||||
0% {
|
||||
width: 0;
|
||||
}
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes dot-move-right {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dot-move-right {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes dot-move-left {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: -32px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dot-move-left {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: -32px;
|
||||
}
|
||||
}
|
||||
/****END OF HR LINES*****
|
||||
*************************/
|
57
src/util/util.js
Normal file
57
src/util/util.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**@module util*/
|
||||
|
||||
/**
|
||||
* Enum, all cell states
|
||||
*/
|
||||
export const CellState = {
|
||||
//No snake, no food
|
||||
Empty: 'empty',
|
||||
|
||||
//Snake
|
||||
Snake: 'snake',
|
||||
|
||||
//Food
|
||||
Food: 'food',
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum, Game states
|
||||
*/
|
||||
export const GameState = {
|
||||
//Choose grid size
|
||||
SizeSelect: 'sizeselect',
|
||||
|
||||
//actual game
|
||||
Gameplay: 'gameplay',
|
||||
|
||||
//end game
|
||||
Fin: 'fin',
|
||||
}
|
||||
|
||||
export const instructions = {
|
||||
[GameState.SizeSelect]: "Decide on the size of the Board\nRows -- Cols",
|
||||
[GameState.Gameplay]: "",
|
||||
[GameState.Fin]: "You {end}!",
|
||||
}
|
||||
|
||||
export const snakeDirection = {
|
||||
Up: 'up',
|
||||
Down: 'down',
|
||||
Left: 'left',
|
||||
Right: 'right',
|
||||
}
|
||||
|
||||
export function clone(obj) {
|
||||
//not an object or array
|
||||
if (obj === null || typeof obj !== 'object') return obj;
|
||||
|
||||
//is an array
|
||||
if (Array.isArray(obj)) return obj.map(x => clone(x));
|
||||
|
||||
//is an object
|
||||
const copy = {};
|
||||
for (const prop in obj) {
|
||||
copy[prop] = clone(obj[prop]);
|
||||
}
|
||||
return copy;
|
||||
}
|
Loading…
Reference in New Issue
Block a user