├── img ├── cell-0.png ├── cell-covered.png ├── cell-flagged.png ├── display-digit-0.png ├── display-digit-1.png ├── display-digit-2.png ├── display-digit-3.png ├── display-digit-4.png ├── display-digit-5.png ├── display-digit-6.png ├── display-digit-7.png ├── display-digit-8.png ├── display-digit-9.png ├── face-active.png ├── face-clicking.png ├── face-lost.png ├── face-won.png ├── face.png ├── mine-exploded.png ├── minesweeper-icon.png └── share-image.png ├── index.html ├── index.js ├── readme.md └── style.css /img/cell-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/cell-0.png -------------------------------------------------------------------------------- /img/cell-covered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/cell-covered.png -------------------------------------------------------------------------------- /img/cell-flagged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/cell-flagged.png -------------------------------------------------------------------------------- /img/display-digit-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-0.png -------------------------------------------------------------------------------- /img/display-digit-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-1.png -------------------------------------------------------------------------------- /img/display-digit-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-2.png -------------------------------------------------------------------------------- /img/display-digit-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-3.png -------------------------------------------------------------------------------- /img/display-digit-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-4.png -------------------------------------------------------------------------------- /img/display-digit-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-5.png -------------------------------------------------------------------------------- /img/display-digit-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-6.png -------------------------------------------------------------------------------- /img/display-digit-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-7.png -------------------------------------------------------------------------------- /img/display-digit-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-8.png -------------------------------------------------------------------------------- /img/display-digit-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/display-digit-9.png -------------------------------------------------------------------------------- /img/face-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/face-active.png -------------------------------------------------------------------------------- /img/face-clicking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/face-clicking.png -------------------------------------------------------------------------------- /img/face-lost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/face-lost.png -------------------------------------------------------------------------------- /img/face-won.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/face-won.png -------------------------------------------------------------------------------- /img/face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/face.png -------------------------------------------------------------------------------- /img/mine-exploded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/mine-exploded.png -------------------------------------------------------------------------------- /img/minesweeper-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/minesweeper-icon.png -------------------------------------------------------------------------------- /img/share-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tholman/one-square-minesweeper/fabb9dfa146c51d8dc872f20d4682cc1f81a9444/img/share-image.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | One Square Minesweeper 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 21 | 22 | 23 | 24 | 25 | 29 | 33 | 37 | 38 | 39 | 40 |
41 |
42 |
43 | MineMinesweeper 48 |
49 |
50 |
51 |
52 |
53 | 54 | 55 | 56 |
57 | 58 |
59 | 60 | 61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | 74 |
75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 | 84 |
85 | 86 |
87 | 88 |
89 |
90 | A Useless Web Project 91 |
92 |
93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | const digit = document.querySelector(".digit"); 3 | const timer0 = document.querySelector(".timer-0"); 4 | const timer1 = document.querySelector(".timer-1"); 5 | const timer2 = document.querySelector(".timer-2"); 6 | const faceButton = document.querySelector(".face-button"); 7 | const oneSquare = document.querySelector(".one-square"); 8 | 9 | let startTime, animationFrame; 10 | let last = ""; 11 | 12 | startTimer(); 13 | 14 | document.oncontextmenu = function (e) { 15 | if (e.target === oneSquare) return false; 16 | }; 17 | 18 | function reset() { 19 | cancelAnimationFrame(animationFrame); 20 | dead = false; 21 | win = false; 22 | faceButton.classList.remove("face-button-clicking"); 23 | faceButton.classList.remove("face-button-dead"); 24 | faceButton.classList.remove("face-button-won"); 25 | oneSquare.classList.remove("exploded"); 26 | oneSquare.classList.remove("flagged"); 27 | digit.src = "./img/display-digit-1.png"; 28 | startTimer(); 29 | } 30 | 31 | function startTimer() { 32 | startTime = Date.now(); 33 | animationFrame = window.requestAnimationFrame(tick); 34 | } 35 | 36 | function tick() { 37 | setTime(Date.now() - startTime); 38 | animationFrame = window.requestAnimationFrame(tick); 39 | } 40 | 41 | function setTime(duration) { 42 | let seconds = Math.floor((duration / 1000) % 60); 43 | 44 | if (seconds > 999) { 45 | seconds = 999; 46 | } 47 | 48 | const secondString = seconds.toString().padStart(3, 0).split(""); 49 | timer0.src = `./img/display-digit-${secondString[0]}.png`; 50 | timer1.src = `./img/display-digit-${secondString[1]}.png`; 51 | timer2.src = `./img/display-digit-${secondString[2]}.png`; 52 | } 53 | 54 | oneSquare.addEventListener("mousedown", (e) => { 55 | if (e.ctrlKey) { 56 | e.preventDefault(); 57 | e.stopPropagation(); 58 | } 59 | clicking = true; 60 | faceButton.classList.add("face-button-clicking"); 61 | }); 62 | 63 | oneSquare.addEventListener("mouseup", (e) => { 64 | if (clicking === false) { 65 | return; 66 | } 67 | 68 | if (e.ctrlKey || e.which === 3) { 69 | faceButton.classList.remove("face-button-clicking"); 70 | oneSquare.classList.add("flagged"); 71 | faceButton.classList.add("face-button-won"); 72 | digit.src = "./img/display-digit-0.png"; 73 | } else { 74 | faceButton.classList.remove("face-button-clicking"); 75 | oneSquare.classList.add("exploded"); 76 | faceButton.classList.add("face-button-dead"); 77 | digit.src = "./img/display-digit-1.png"; 78 | } 79 | 80 | cancelAnimationFrame(animationFrame); 81 | clicking = false; 82 | }); 83 | 84 | oneSquare.addEventListener("mouseout", () => { 85 | if (clicking === true) { 86 | clicking = false; 87 | faceButton.classList.remove("face-button-clicking"); 88 | } 89 | }); 90 | 91 | faceButton.addEventListener("click", () => { 92 | reset(); 93 | }); 94 | })(); 95 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # One Square Minesweeper 2 | 3 | A game of minesweeper that is easy to complete (or lose). Play at [https://onesquareminesweeper.com](https://onesquareminesweeper.com). 4 | 5 | ### Instructions 6 | - Right click (or crtl + click) is flag 7 | - Normal Click to sweep mines 8 | - Click the face to reset 9 | 10 | One Square Minesweeper 11 | 12 | ### Attributions 13 | Assets and some styles borrowed from this fantastic [open source minesweeper](https://github.com/leyanlo/minesweeper/) (with more than 1 tile to sweep) 14 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | image-rendering: pixelated; 4 | } 5 | 6 | html, 7 | body { 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | .preload { 13 | width: 0; 14 | visibility: hidden; 15 | } 16 | 17 | body { 18 | height: 100vh; 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | background: #fafafa; 23 | font-family: "Segoe UI", sans-serif; 24 | font-size: 11px; 25 | background-color: rgb(0, 134, 137); 26 | } 27 | 28 | .minesweeper { 29 | border-width: 1px; 30 | border-style: solid; 31 | border-image: initial; 32 | border-color: rgb(212, 208, 200) rgb(64, 64, 64) rgb(64, 64, 64) 33 | rgb(212, 208, 200); 34 | } 35 | 36 | .minesweeper-inner { 37 | border-width: 1px; 38 | border-style: solid; 39 | border-image: initial; 40 | border-color: rgb(255, 255, 255) rgb(128, 128, 128) rgb(128, 128, 128) 41 | rgb(255, 255, 255); 42 | background-color: rgb(212, 208, 200); 43 | padding: 1px; 44 | } 45 | 46 | header { 47 | background: linear-gradient(to right, rgb(11, 36, 106), rgb(166, 202, 240)); 48 | color: rgb(255, 255, 255); 49 | display: flex; 50 | font-weight: 700; 51 | height: 18px; 52 | padding: 1px 2px; 53 | align-items: center; 54 | } 55 | 56 | header img { 57 | width: 16px; 58 | height: 16px; 59 | margin-right: 4px; 60 | } 61 | 62 | .game { 63 | padding: 6px; 64 | background-color: rgb(192, 192, 192); 65 | border-width: 3px 0px 0px 3px; 66 | border-style: solid; 67 | border-color: rgb(255, 255, 255); 68 | } 69 | 70 | section { 71 | border-width: 2px; 72 | border-style: solid; 73 | border-image: initial; 74 | border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) 75 | rgb(128, 128, 128); 76 | } 77 | 78 | .scoring { 79 | margin-bottom: 6px; 80 | } 81 | 82 | .scoreboard { 83 | display: flex; 84 | align-items: flex-end; 85 | -webkit-box-pack: justify; 86 | justify-content: space-between; 87 | padding: 4px 5px; 88 | } 89 | 90 | .panel { 91 | border-width: 1px; 92 | border-style: solid; 93 | border-image: initial; 94 | border-color: rgb(128, 128, 128) rgb(255, 255, 255) rgb(255, 255, 255) 95 | rgb(128, 128, 128); 96 | background-color: rgb(0, 0, 0); 97 | gap: 2px; 98 | padding: 2px; 99 | display: flex; 100 | } 101 | 102 | .face-button { 103 | border: none; 104 | padding: 0px; 105 | width: 26px; 106 | height: 28px; 107 | background: none; 108 | margin: 0 2px; 109 | background-image: url("./img/face.png"); 110 | background-position: center; 111 | background-repeat: no-repeat; 112 | } 113 | 114 | .board-items { 115 | background-color: rgb(123 123 123 / 4%); 116 | user-select: none; 117 | height: 160px; 118 | display: flex; 119 | justify-content: center; 120 | align-items: center; 121 | } 122 | 123 | .one-square { 124 | width: 16px; 125 | height: 16px; 126 | background-image: url("./img/cell-covered.png"); 127 | } 128 | 129 | .one-square:active { 130 | background-image: url("./img/cell-0.png"); 131 | } 132 | 133 | .exploded { 134 | pointer-events: none; 135 | background-image: url("./img/mine-exploded.png"); 136 | } 137 | 138 | .flagged { 139 | pointer-events: none; 140 | background-image: url("./img/cell-flagged.png"); 141 | } 142 | 143 | .face-button:active { 144 | background-image: url("./img/face-active.png"); 145 | } 146 | 147 | .face-button-clicking { 148 | background-image: url("./img/face-clicking.png"); 149 | } 150 | 151 | .face-button-won { 152 | background-image: url("./img/face-won.png"); 153 | } 154 | 155 | .face-button-dead { 156 | background-image: url("./img/face-lost.png"); 157 | } 158 | 159 | .sitter { 160 | position: fixed; 161 | bottom: 15px; 162 | font-family: monospace; 163 | font-size: 11px; 164 | font-weight: bold; 165 | text-transform: uppercase; 166 | } 167 | 168 | .watch { 169 | background: rgba(255, 255, 255, 0.6); 170 | padding: 10px 15px; 171 | border-radius: 22px; 172 | display: inline-block; 173 | margin-right: 5px; 174 | } 175 | 176 | .twitter { 177 | background: url("data:image/png;base64,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"); 178 | width: 33px; 179 | height: 33px; 180 | display: inline-block; 181 | background-repeat: no-repeat; 182 | background-color: rgba(255, 255, 255, 0.6); 183 | border-radius: 50%; 184 | background-size: 20px 20px; 185 | background-position: center; 186 | vertical-align: top; 187 | } 188 | 189 | .left { 190 | left: 15px; 191 | } 192 | 193 | .right { 194 | right: 15px; 195 | } 196 | --------------------------------------------------------------------------------