alaah 5 years ago
commit
35bd98e4de
7 changed files with 349 additions and 0 deletions
  1. 3 0
      .gitignore
  2. 1 0
      README.md
  3. 42 0
      public/cross.svg
  4. 16 0
      public/index.html
  5. BIN
      public/jesus.jpg
  6. 89 0
      src/index.css
  7. 198 0
      src/index.js

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+/node_modules
+*.json
+/build

+ 1 - 0
README.md

@@ -0,0 +1 @@
+no description

+ 42 - 0
public/cross.svg

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="457.983px" height="457.983px" viewBox="0 0 457.983 457.983" style="enable-background:new 0 0 457.983 457.983;"
+	 xml:space="preserve">
+<g>
+	<path d="M250.654,123.777h102.12V167.1h-102.12v253.746h-43.326V167.1h-102.12v-43.323h102.12V37.131h43.326V123.777z
+		 M389.906,86.643v117.592h-102.12v253.749H170.197V204.234H68.077V86.643h102.121V0h117.589v86.643H389.906z M371.334,105.206
+		H269.22V18.562h-80.454v86.643H86.646v80.458h102.12v253.743h80.454V185.663h102.127v-80.458H371.334z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 16 - 0
public/index.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <meta name="theme-color" content="#000000" />
+    <meta name="description" content="Web site created using create-react-app" />
+    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
+    <title>Weebsweeper</title>
+  </head>
+  <body>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
+    <div id="root"></div>
+  </body>
+</html>

BIN
public/jesus.jpg


+ 89 - 0
src/index.css

@@ -0,0 +1,89 @@
+body {
+    background-color: #555;
+}
+
+.square {
+    float: left;
+    width: 40px;
+    height: 40px;
+    line-height: 40px;
+    font-size: 15px;
+    font-weight: 1000;
+    padding: 0;
+    background-size: cover;
+}
+
+.game {
+    display: flex;
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    min-width: 320px;
+    transform: translate(-50%, -50%);
+}
+
+.covered {
+    border: 2px dotted #888;
+    background-color: #666;
+}
+
+@keyframes coveredAnim {
+    from {background-color: #666; border: 2px dotted #888;}
+    to {background-color: transparent; border: 0px none;}
+}
+
+
+.covered-win {
+    border: 2px dotted #888;
+    background-color: transparent;
+    animation-name: coveredAnim;
+    animation-duration: 10s;
+}
+
+.uncovered {
+    border: 0px none;
+    color: #fff;
+    background-color: #888;
+}
+
+@keyframes uncoveredAnim {
+    from {background-color: #888; color: #fff;}
+    to {background-color: transparent; color: transparent;}
+}
+
+.uncovered-win {
+    border: 0px none;
+    color: transparent;
+    background-color: transparent;
+    animation-name: uncoveredAnim;
+    animation-duration: 10s;
+}
+
+.nun {
+    background-image: url('https://img2.gelbooru.com//samples/69/d4/sample_69d43b8deae19ac8e6377d1bd0c7ad16.jpg');    
+}
+
+.cross {
+    background-size: 75%;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-image: url('/weebsweeper/cross.svg');
+}
+
+@keyframes jesusAnim {
+  from {background-size: 0% 0%;}
+  to {background-size: 100% 100%;}
+}
+
+.jesus {
+    min-width: 400px;
+    min-height: 400px;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    background-position: center center;
+    background-image: url('/weebsweeper/jesus.jpg');
+    animation-name: jesusAnim;
+    animation-duration: 10s;
+    animation-timing-function: ease-in;
+}
+

+ 198 - 0
src/index.js

@@ -0,0 +1,198 @@
+// (c) alaah
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import './index.css';
+
+const BOARD_SIZE = 15;
+const MINE_COUNT = 30;
+
+const Square = props => {
+    let className = "square";
+    let disabled = props.value.uncovered || props.win;
+    let style={};
+   
+    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";
+	    }
+    } else {
+	    if(props.value.uncovered) {
+		className += " uncovered-win";
+	    } else {
+		className += " covered-win";
+	    }	
+    }
+
+    return (
+		<button className={className}
+                disabled={disabled}
+                onClick={props.onClick}
+                style={style}
+                onContextMenu={e => {props.onContextMenu(); e.preventDefault();}}>
+			{props.value.value > 0 ? props.value.value : null}
+		</button>
+	);
+}
+        
+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)} />;
+	}
+
+	render() {
+        const s = [];
+        let bad = 0;
+        for(let i = 0; i < BOARD_SIZE; ++i) {
+            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++;
+                } else {
+                    items.push(this.renderSquare(i * BOARD_SIZE + j), '');
+                }
+            }
+            s.push(<div>{items}</div>);
+        }
+        return (
+            <div>
+	        {s}
+	    </div>
+        );
+	}
+}
+
+class Game extends React.Component {
+    constructor(props) {
+        super(props);
+        let squares = new Array(BOARD_SIZE * BOARD_SIZE);
+        for(let i = 0; i < BOARD_SIZE * BOARD_SIZE; ++i) {
+            squares[i] = {    
+                bad: false,
+                flagged: false,
+                uncovered: false,
+                value: 0,
+            };
+        }
+        for(let i = 0; i < MINE_COUNT; ++i) {
+            let n;
+            do {
+                n = parseInt(Math.random() * BOARD_SIZE * BOARD_SIZE);
+            } while(squares[n].bad);
+            squares[n].bad = true;
+        }
+        this.state = { 
+            squares: squares,
+            win: 0,
+        };
+        this.count = BOARD_SIZE * BOARD_SIZE;
+	this.anime = [];
+    }
+
+    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');
+            }
+        });
+    }
+
+    clear(squares, x, y, force) {
+        if(x < 0 || y < 0 || x >= BOARD_SIZE || y >= BOARD_SIZE) {
+            return;
+        }
+
+        const i = y * BOARD_SIZE + x;
+
+        if(!squares[i].flagged && !squares[i].bad && !squares[i].uncovered) {
+            let count = 0;
+            squares[i].uncovered = true;
+            for(let j = -1; j <= 1; ++j) {
+                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) {
+                            count++;  
+                        }
+                    }
+                }
+            }
+
+            squares[i].value = count;
+            this.count--;
+
+	        if(count === 0 || force) {
+                this.clear(squares, x    , y - 1);
+                this.clear(squares, x - 1, y    );
+                this.clear(squares, x + 1, y    );
+                this.clear(squares, x    , y + 1);
+            }
+        }
+    }
+
+    onLeftClick(i) {
+        let squares = this.state.squares.slice();
+        
+        if(squares[i].flagged) {
+            // nada
+        } else if(squares[i].bad) {
+            this.setState({
+                win: 2,
+            });
+        } else {
+            this.clear(squares, i % BOARD_SIZE, parseInt(i / BOARD_SIZE), true);
+        	if(this.count === MINE_COUNT) {
+				this.setState({
+					win: 1,
+				});
+			}
+		}
+
+        this.setState({
+            squares: squares,
+        });
+    }
+
+    onRightClick(i) {
+        let squares = this.state.squares.slice();
+        
+        if(!squares[i].uncovered) {
+            squares[i].flagged = !squares[i].flagged;
+        }
+        
+        this.setState({
+            squares: squares,
+        });
+    }
+
+    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>
+		);
+	}
+}	
+
+ReactDOM.render(
+    <div className="main">
+    <Game />
+    </div>,
+    document.getElementById('root')
+);