|
@@ -1,85 +1,85 @@
|
|
// (c) alaah
|
|
// (c) alaah
|
|
|
|
|
|
-import React from 'react';
|
|
|
|
|
|
+import React from 'react';
|
|
import ReactDOM from 'react-dom';
|
|
import ReactDOM from 'react-dom';
|
|
import './index.css';
|
|
import './index.css';
|
|
|
|
|
|
-const BOARD_SIZE = 15;
|
|
|
|
-const MINE_COUNT = 30;
|
|
|
|
-
|
|
|
|
const Square = props => {
|
|
const Square = props => {
|
|
let className = "square";
|
|
let className = "square";
|
|
let disabled = props.value.uncovered || props.win;
|
|
let disabled = props.value.uncovered || props.win;
|
|
- let style={};
|
|
|
|
|
|
+ let style = {};
|
|
|
|
|
|
if(props.win !== 1) {
|
|
if(props.win !== 1) {
|
|
- if(props.value.uncovered) {
|
|
|
|
- className += " uncovered";
|
|
|
|
- } else {
|
|
|
|
- className += " covered";
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(props.win === 2 && props.value.bad && !props.value.flagged) {
|
|
|
|
- style = {backgroundImage: 'url("' + props.url + '")'};
|
|
|
|
- }
|
|
|
|
- if(props.win === 2 && !props.value.bad && props.value.flagged) {
|
|
|
|
- className += " nun";
|
|
|
|
- } else if(props.value.flagged) {
|
|
|
|
- className += " cross";
|
|
|
|
- }
|
|
|
|
|
|
+ if(props.value.uncovered) {
|
|
|
|
+ className += " uncovered";
|
|
|
|
+ } else {
|
|
|
|
+ className += " covered";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(props.win === 2 && props.value.bad && !props.value.flagged) {
|
|
|
|
+ style = {backgroundImage: 'url("' + props.url + '")'};
|
|
|
|
+ }
|
|
|
|
+ if(props.win === 2 && !props.value.bad && props.value.flagged) {
|
|
|
|
+ className += " nun";
|
|
|
|
+ } else if(props.value.flagged) {
|
|
|
|
+ className += " cross";
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
- if(props.value.uncovered) {
|
|
|
|
- className += " uncovered-win";
|
|
|
|
- } else {
|
|
|
|
- className += " covered-win";
|
|
|
|
- }
|
|
|
|
|
|
+ if(props.value.uncovered) {
|
|
|
|
+ className += " uncovered-win";
|
|
|
|
+ } else {
|
|
|
|
+ className += " covered-win";
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ style.width = props.cell;
|
|
|
|
+ style.height = props.cell;
|
|
|
|
+// style.lineHeight = props.cell;
|
|
|
|
+
|
|
return (
|
|
return (
|
|
- <button className={className}
|
|
|
|
|
|
+ <button className={className}
|
|
disabled={disabled}
|
|
disabled={disabled}
|
|
onClick={props.onClick}
|
|
onClick={props.onClick}
|
|
style={style}
|
|
style={style}
|
|
onContextMenu={e => {props.onContextMenu(); e.preventDefault();}}>
|
|
onContextMenu={e => {props.onContextMenu(); e.preventDefault();}}>
|
|
- {props.value.value > 0 ? props.value.value : null}
|
|
|
|
- </button>
|
|
|
|
- );
|
|
|
|
|
|
+ {props.value.value > 0 ? props.value.value : null}
|
|
|
|
+ </button>
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
|
|
class Board extends React.Component {
|
|
class Board extends React.Component {
|
|
- renderSquare(i, url) {
|
|
|
|
- return <Square url={url} win={this.props.win} value={this.props.squares[i]} onClick={() => this.props.onClick(i)} onContextMenu={() => this.props.onContextMenu(i)} />;
|
|
|
|
- }
|
|
|
|
|
|
+ renderSquare(i, url) {
|
|
|
|
+ return <td><Square cell={this.props.cell} url={url} win={this.props.win} value={this.props.squares[i]} onClick={() => this.props.onClick(i)} onContextMenu={() => this.props.onContextMenu(i)} /></td>;
|
|
|
|
+ }
|
|
|
|
|
|
- render() {
|
|
|
|
|
|
+ render() {
|
|
const s = [];
|
|
const s = [];
|
|
- let bad = 0;
|
|
|
|
- for(let i = 0; i < BOARD_SIZE; ++i) {
|
|
|
|
|
|
+ const weebUrl = '/res/weeb/';
|
|
|
|
+ const weebCount = 3514;
|
|
|
|
+ for(let i = 0; i < this.props.height; ++i) {
|
|
const items = [];
|
|
const items = [];
|
|
-
|
|
|
|
- for(let j = 0; j < BOARD_SIZE; ++j) {
|
|
|
|
- if(this.props.squares[i * BOARD_SIZE + j].bad && this.props.win === 2) {
|
|
|
|
- items.push(this.renderSquare(i * BOARD_SIZE + j, this.props.anime[bad]));
|
|
|
|
- bad++;
|
|
|
|
|
|
+ for(let j = 0; j < this.props.width; ++j) {
|
|
|
|
+ if(this.props.squares[i * this.props.width + j].bad && this.props.win === 2) {
|
|
|
|
+ items.push(this.renderSquare(i * this.props.width + j, weebUrl + parseInt(Math.random() * weebCount) + '.jpg'));
|
|
} else {
|
|
} else {
|
|
- items.push(this.renderSquare(i * BOARD_SIZE + j), '');
|
|
|
|
|
|
+ items.push(this.renderSquare(i * this.props.width + j), '');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- s.push(<div>{items}</div>);
|
|
|
|
|
|
+ s.push(<tr>{items}</tr>);
|
|
}
|
|
}
|
|
return (
|
|
return (
|
|
- <div>
|
|
|
|
- {s}
|
|
|
|
- </div>
|
|
|
|
|
|
+ <table>
|
|
|
|
+ {s}
|
|
|
|
+ </table>
|
|
);
|
|
);
|
|
- }
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
class Game extends React.Component {
|
|
class Game extends React.Component {
|
|
constructor(props) {
|
|
constructor(props) {
|
|
super(props);
|
|
super(props);
|
|
- let squares = new Array(BOARD_SIZE * BOARD_SIZE);
|
|
|
|
- for(let i = 0; i < BOARD_SIZE * BOARD_SIZE; ++i) {
|
|
|
|
|
|
+ let squares = new Array(this.props.width * this.props.height);
|
|
|
|
+ for(let i = 0; i < this.props.width * this.props.height; ++i) {
|
|
squares[i] = {
|
|
squares[i] = {
|
|
bad: false,
|
|
bad: false,
|
|
flagged: false,
|
|
flagged: false,
|
|
@@ -87,80 +87,95 @@ class Game extends React.Component {
|
|
value: 0,
|
|
value: 0,
|
|
};
|
|
};
|
|
}
|
|
}
|
|
- for(let i = 0; i < MINE_COUNT; ++i) {
|
|
|
|
|
|
+ for(let i = 0; i < this.props.animes; ++i) {
|
|
let n;
|
|
let n;
|
|
do {
|
|
do {
|
|
- n = parseInt(Math.random() * BOARD_SIZE * BOARD_SIZE);
|
|
|
|
|
|
+ n = parseInt(Math.random() * this.props.width * this.props.height);
|
|
} while(squares[n].bad);
|
|
} while(squares[n].bad);
|
|
squares[n].bad = true;
|
|
squares[n].bad = true;
|
|
}
|
|
}
|
|
this.state = {
|
|
this.state = {
|
|
squares: squares,
|
|
squares: squares,
|
|
win: 0,
|
|
win: 0,
|
|
|
|
+ width: 0,
|
|
|
|
+ height: 0,
|
|
};
|
|
};
|
|
- this.count = BOARD_SIZE * BOARD_SIZE;
|
|
|
|
- this.anime = [];
|
|
|
|
|
|
+ this.count = this.props.width * this.props.height;
|
|
|
|
+ this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
|
|
}
|
|
}
|
|
|
|
|
|
componentDidMount() {
|
|
componentDidMount() {
|
|
- fetch('https://alaah.xyz/api/gel/' + MINE_COUNT).then(res => res.json()).then(res => {
|
|
|
|
- if(Array.isArray(res)) {
|
|
|
|
- this.anime = res;
|
|
|
|
- } else {
|
|
|
|
- console.error('Unable to load gelbooru');
|
|
|
|
- }
|
|
|
|
|
|
+ this.updateWindowDimensions();
|
|
|
|
+ window.addEventListener('resize', this.updateWindowDimensions);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ componentWillUnmount() {
|
|
|
|
+ window.removeEventListener('resize', this.updateWindowDimensions);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateWindowDimensions() {
|
|
|
|
+ this.setState({
|
|
|
|
+ width: window.innerWidth,
|
|
|
|
+ height: window.innerHeight,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- clear(squares, x, y, force) {
|
|
|
|
- if(x < 0 || y < 0 || x >= BOARD_SIZE || y >= BOARD_SIZE) {
|
|
|
|
|
|
+ clear(squares, x, y) {
|
|
|
|
+ if(x < 0 || y < 0 || x >= this.props.width || y >= this.props.height) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- const i = y * BOARD_SIZE + x;
|
|
|
|
|
|
+ const i = y * this.props.width + x;
|
|
|
|
|
|
if(!squares[i].flagged && !squares[i].bad && !squares[i].uncovered) {
|
|
if(!squares[i].flagged && !squares[i].bad && !squares[i].uncovered) {
|
|
let count = 0;
|
|
let count = 0;
|
|
- squares[i].uncovered = true;
|
|
|
|
for(let j = -1; j <= 1; ++j) {
|
|
for(let j = -1; j <= 1; ++j) {
|
|
for(let k = -1; k <= 1; ++k) {
|
|
for(let k = -1; k <= 1; ++k) {
|
|
- if((j !== 0 || k !== 0) && y + k >= 0 && y + k < BOARD_SIZE && x + j >= 0 && x + j < BOARD_SIZE) {
|
|
|
|
- if(squares[(y + k) * BOARD_SIZE + (x + j)].bad) {
|
|
|
|
|
|
+ if((j !== 0 || k !== 0) && y + k >= 0 && y + k < this.props.height && x + j >= 0 && x + j < this.props.width) {
|
|
|
|
+ if(squares[(y + k) * this.props.width + (x + j)].bad) {
|
|
count++;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
squares[i].value = count;
|
|
squares[i].value = count;
|
|
|
|
+ squares[i].uncovered = true;
|
|
this.count--;
|
|
this.count--;
|
|
-
|
|
|
|
- if(count === 0 || force) {
|
|
|
|
|
|
+
|
|
|
|
+ if(count === 0) {
|
|
|
|
+ this.clear(squares, x - 1, y - 1);
|
|
this.clear(squares, x , y - 1);
|
|
this.clear(squares, x , y - 1);
|
|
|
|
+ this.clear(squares, x + 1, y - 1);
|
|
this.clear(squares, x - 1, y );
|
|
this.clear(squares, x - 1, y );
|
|
this.clear(squares, x + 1, y );
|
|
this.clear(squares, x + 1, y );
|
|
|
|
+ this.clear(squares, x - 1, y + 1);
|
|
this.clear(squares, x , y + 1);
|
|
this.clear(squares, x , y + 1);
|
|
|
|
+ this.clear(squares, x + 1, y + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
onLeftClick(i) {
|
|
onLeftClick(i) {
|
|
let squares = this.state.squares.slice();
|
|
let squares = this.state.squares.slice();
|
|
|
|
+ //alert(i + ' ' + i % this.props.width + ' ' + parseInt(i / this.props.width));
|
|
|
|
|
|
if(squares[i].flagged) {
|
|
if(squares[i].flagged) {
|
|
// nada
|
|
// nada
|
|
} else if(squares[i].bad) {
|
|
} else if(squares[i].bad) {
|
|
- this.setState({
|
|
|
|
- win: 2,
|
|
|
|
- });
|
|
|
|
|
|
+ if(this.count !== this.props.width * this.props.height) {
|
|
|
|
+ this.setState({
|
|
|
|
+ win: 2,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
- this.clear(squares, i % BOARD_SIZE, parseInt(i / BOARD_SIZE), true);
|
|
|
|
- if(this.count === MINE_COUNT) {
|
|
|
|
- this.setState({
|
|
|
|
- win: 1,
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ this.clear(squares, i % this.props.width, parseInt(i / this.props.width), true);
|
|
|
|
+ if(this.count === this.props.animes) {
|
|
|
|
+ this.setState({
|
|
|
|
+ win: 1,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
this.setState({
|
|
this.setState({
|
|
squares: squares,
|
|
squares: squares,
|
|
@@ -180,19 +195,82 @@ class Game extends React.Component {
|
|
}
|
|
}
|
|
|
|
|
|
render() {
|
|
render() {
|
|
- return (
|
|
|
|
- <div className="game">
|
|
|
|
- <div className={"board" + (this.state.win === 1 ? " jesus" : "")}>
|
|
|
|
- <Board win={this.state.win} anime={this.anime} squares={this.state.squares} onClick={i => this.onLeftClick(i)} onContextMenu={i => this.onRightClick(i)} />
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
+ return (
|
|
|
|
+ <div className="game">
|
|
|
|
+ <div className={"board" + (this.state.win === 1 ? " jesus" : "")}>
|
|
|
|
+ <Board width={this.props.width}
|
|
|
|
+ height={this.props.height}
|
|
|
|
+ cell={this.state.width / this.props.width > this.state.height / this.props.height ? this.state.height / this.props.height : this.state.width / this.props.width}
|
|
|
|
+ win={this.state.win}
|
|
|
|
+ squares={this.state.squares}
|
|
|
|
+ onClick={i => this.onLeftClick(i)}
|
|
|
|
+ onContextMenu={i => this.onRightClick(i)}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+class Form extends React.Component {
|
|
|
|
+ constructor() {
|
|
|
|
+ super();
|
|
|
|
+
|
|
|
|
+ this.state = {
|
|
|
|
+ width: 16,
|
|
|
|
+ height: 16,
|
|
|
|
+ animesPct: 270,
|
|
|
|
+ animesTotal: parseInt(16 * 16 * 270 / 1000.),
|
|
|
|
+ enabled: false,
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateAnime() {
|
|
|
|
+ this.setState({
|
|
|
|
+ animesTotal: parseInt(this.state.width * this.state.height * this.state.animesPct / 1000.),
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ render() {
|
|
|
|
+ if(this.state.enabled) {
|
|
|
|
+ return <Game width={this.state.width} height={this.state.height} animes={this.state.animesTotal}/>
|
|
|
|
+ } else {
|
|
|
|
+ return (
|
|
|
|
+ <form className="config">
|
|
|
|
+ <div className="title">Weebsweeper</div>
|
|
|
|
+ <div className="desc">Current objective: reach The Lord and don't be led astray by the CCP's devilish cartoons.</div>
|
|
|
|
+ Width: {this.state.width}
|
|
|
|
+ <input type="range" name="width" min="8" max="48" defaultValue="16" onChange={event => {
|
|
|
|
+ this.setState({
|
|
|
|
+ width: event.target.value
|
|
|
|
+ }, this.updateAnime);
|
|
|
|
+ }} />
|
|
|
|
+ Height: {this.state.height}
|
|
|
|
+ <input type="range" name="height" min="8" max="48" defaultValue="16" onChange={event => {
|
|
|
|
+ this.setState({
|
|
|
|
+ height: event.target.value,
|
|
|
|
+ }, this.updateAnime);
|
|
|
|
+ }} />
|
|
|
|
+ Devils: {this.state.animesTotal}
|
|
|
|
+ <input type="range" name="animes" min="20" max="700" defaultValue="270" onChange={event => {
|
|
|
|
+ this.setState({
|
|
|
|
+ animesPct: event.target.value,
|
|
|
|
+ }, this.updateAnime);
|
|
|
|
+ }} />
|
|
|
|
+ <input type="button" name="accept" className="button" value="Deus vult" onClick={() => {
|
|
|
|
+ this.setState({
|
|
|
|
+ enabled: true,
|
|
|
|
+ });
|
|
|
|
+ }}/>
|
|
|
|
+ </form>
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
ReactDOM.render(
|
|
ReactDOM.render(
|
|
<div className="main">
|
|
<div className="main">
|
|
- <Game />
|
|
|
|
|
|
+ <Form />
|
|
</div>,
|
|
</div>,
|
|
document.getElementById('root')
|
|
document.getElementById('root')
|
|
);
|
|
);
|