Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/manuelhenke/minesweeper-for-web
Minesweeper as a WebComponent
https://github.com/manuelhenke/minesweeper-for-web
css game lit-element lit-html minesweeper typescript webcomponent webpack
Last synced: about 2 months ago
JSON representation
Minesweeper as a WebComponent
- Host: GitHub
- URL: https://github.com/manuelhenke/minesweeper-for-web
- Owner: manuelhenke
- License: mit
- Created: 2020-05-06T11:41:08.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2024-01-30T08:43:34.000Z (11 months ago)
- Last Synced: 2024-11-07T17:58:08.254Z (about 2 months ago)
- Topics: css, game, lit-element, lit-html, minesweeper, typescript, webcomponent, webpack
- Language: TypeScript
- Homepage: https://henkebyte.com/minesweeper
- Size: 1.55 MB
- Stars: 3
- Watchers: 2
- Forks: 2
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# minesweeper-for-web
[![CI](https://github.com/manuelhenke/minesweeper-for-web/actions/workflows/ci.yml/badge.svg)](https://github.com/manuelhenke/minesweeper-for-web/actions/workflows/ci.yml)
[![CodeQL](https://github.com/manuelhenke/minesweeper-for-web/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/manuelhenke/minesweeper-for-web/actions/workflows/codeql-analysis.yml)
[![License](https://img.shields.io/github/license/manuelhenke/minesweeper-for-web)](./LICENSE)
[![NPM version](https://img.shields.io/npm/v/minesweeper-for-web.svg?style=flat)](https://www.npmjs.com/package/minesweeper-for-web)This is **Minesweeper** as a **WebComponent**. Once you integrate it as described further, the game just follows the [standard rules](https://www.instructables.com/id/How-to-beat-Minesweeper/). To place a flag just press `ctrl`, `alt` or the meta key while clicking on a field.
## Getting Started
Install the package via `npm` or `yarn` and deliver the script to the user.
This can be done via `import`, `require` or just inserting a `script` tag.```shell
npm i minesweeper-for-web
``````shell
yarn add minesweeper-for-web
```## Attributes
| Param | Type | Description | Default |
| ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `columns` | `number` | Amount of columns of the board. | `9` |
| `rows` | `number` | Amount of rows of the board. | `9` |
| `bombs` | `number` | Amount of bombs of the board. | `10` |
| `long-press-threshold` | `number` | Amount of milliseconds required to trigger a long press (placing a flag). A value of zero or below disabled the long press functionality overall. | `500` |
| `disable-question-marks` | `boolean` | Disables the functionality to place question marks. | `false` |
| `flag-placement-mode` | `boolean` | Enables the flag placement mode. A mode where every click places a flag instead of revealing the field. | `false` |
| `restart-selector` | `string` | If present, attaches a click event listener to the element to trigger a restart. | |
| `bomb-counter-selector` | `string` | If present, changes the `textContent` of the provided element to the amount of bombs minus the amount of placed flags. | |## Events
By default, each event contains the current game state in `event.detail.game`. To discourage cheating, no events should be logged in the browser console.
| Name | Type | Cancelable | Description | `detail` |
| ------------- | ------------- | ------------------ | ------------------------- | ------ |
| `minesweeper:game-won` | `GameWonEvent`| :x: | User just won the game |
- `board`: `MinesweeperBoard` current game state
| `minesweeper:game-lost` | `GameLostEvent`| :x: | User just lost the game |
- `board`: `MinesweeperBoard` current game state
| `minesweeper:field-click` | `FieldClickEvent`| :white_check_mark: | User clicked a field |
- `board`: `MinesweeperBoard` current game state
- `target`: `FieldTarget` target of the click
- `field`: `HTMLElement` clicked field
| `minesweeper:field-long-press` | `FieldLongPressEvent`| :white_check_mark: | User long pressed a field |
- `board`: `MinesweeperBoard` current game state
- `target`: `FieldTarget` target of the long press
- `field`: `HTMLElement` long pressed field
| `minesweeper:field-interaction` | `FieldInteractionEvent`| :x: | Game state change occurred |
- `board`: `MinesweeperBoard` current game state
- `target`: `FieldTarget` target of the interaction
- `interaction`: `Interaction` interaction information
## Usage
### Basic usage
Just a basic 9x9 / 10 Mines minesweeper game. Further examples can be **combined**.
```html
import 'minesweeper-for-web';
// Alternatives:
// import 'minesweeper-for-web/custom-element';
// import 'minesweeper-for-web/custom-element.min';
```
### Custom tag name
Define your own custom tag name
```html
import { MinesweeperGame } from 'minesweeper-for-web/minesweeper-game';
// Alternative:
// import { MinesweeperGame } from 'minesweeper-for-web/minesweeper-game.min';
window.customElements.define('custom-minesweeper-game', MinesweeperGame);
```
### Provide left-bomb-counter container
To keep the user informed how many mines are left, after subtracting the number of placed flags, just provide a container for the counter.
```html
Mines
import 'minesweeper-for-web';
```
### Provide a restart button
Provide a selector where a "click"-event will be attached to, to restart the game.
```html
Restart!
import 'minesweeper-for-web';
```
### Disable Long Press
Provide a number lower or equal to `0` to disable the long press functionality.
```html
import 'minesweeper-for-web';
```
### Trigger Restart via JavaScript
Write custom logic to restart the game.
```html
Restart with Confirm!
import 'minesweeper-for-web';
window.addEventListener('DOMContentLoaded', () => {
const minesweeper = document.querySelector('#minesweeper');
document.querySelector('#restart-game-button-confirm').addEventListener('click', (event) => {
event.preventDefault();
if (window.confirm('Are you sure, that you want to restart the game?')) {
minesweeper.restartGame();
}
});
});
```
### Custom win/lose event listener
Attach an EventListener for the win/lose events.
```html
import 'minesweeper-for-web';
window.addEventListener('DOMContentLoaded', () => {
const minesweeper = document.querySelector('#minesweeper');
minesweeper.addEventListener('minesweeper:game-won', () => {
console.log('win');
});
minesweeper.addEventListener('minesweeper:game-lost', () => {
console.log('lose');
});
});
```
### Different initial game configurations
Of course you can provide different configurations for the game.
```html
import 'minesweeper-for-web';
```
### Providing a selectable gamemode
Furthermore you can implement some own logic to create a selectable gamemode
```html
Easy - 9x9 / 10 Mines
Normal - 16x16 / 40 Mines
Hard - 16x30 / 99 Mines
import 'minesweeper-for-web';
function getGameModeConfiguration(currentGameMode) {
switch (currentGameMode) {
case 'hard':
return {
columns: 30,
rows: 16,
bombs: 99,
};
case 'normal':
return {
columns: 16,
rows: 16,
bombs: 40,
};
default: // 'easy'
return {
columns: 9,
rows: 9,
bombs: 10,
};
}
}
window.addEventListener('DOMContentLoaded', () => {
const minesweeper = document.querySelector('#minesweeper');
document.querySelector('#select-game-mode').addEventListener('change', (event) => {
event.preventDefault();
const gameModeConfiguration = getGameModeConfiguration(event.target.value);
minesweeper.setGameModeConfiguration(gameModeConfiguration);
});
});
```
## Example
Try it out at [CodePen](https://codepen.io/manuelhenke/pen/ExoPKLZ).
![Example Image](minesweeper-example.png)
## TypeScript
The whole package is written in TypeScript and therefore provides a strongly typed system via the `core` export of the package:
```html
```
```typescript
// some-file.ts
import 'minesweeper-for-web/custom-element';
import { FieldInteractionEvent, FieldInteractionType } from 'minesweeper-for-web/core';
import type { MinesweeperGame } from 'minesweeper-for-web/core';
const minesweeperGame = document.querySelector('#minesweeper') as MinesweeperGame;
minesweeperGame.addEventListener(
'minesweeper:field-interaction',
(event: FieldInteractionEvent) => {
const { interaction } = event.detail;
switch (interaction.type) {
case FieldInteractionType.Unveiled:
console.log('Revealed field value:', interaction.value);
break;
case FieldInteractionType.FlagAction:
case FieldInteractionType.QuestionMarkAction:
console.log('Performed action:', interaction.action);
break;
}
}
);
```
## Engine
The engine can be used as a standalone library (`commonjs` and `esm`) via the `engine` export of the package. This enables the usage of the engine in every application (server- or client-side).
```javascript
import { MinesweeperEngine } from 'minesweeper-for-web/engine';
const engine = new MinesweeperEngine();
// Creates a board with 10 columns, 12 rows and 10 bombs
engine.createBoard(10, 12, 10);
// Unveils the field in the first row and second column (indexes)
engine.selectField(0, 1);
// Follows the specification of `selectField`
engine.toggleFlag(0, 2);
// Nothing happens since a flag is present on that field
engine.selectField(0, 2);
// Follows the specification of `selectField`
engine.toggleQuestionMark(0, 3);
// Still unveils the field regardless of the question mark
engine.selectField(0, 3);
if (engine.isGameOver) {
// Restarts the game with the initial configuration
engine.restart();
}
```
```javascript
const { MinesweeperEngine } = require('minesweeper-for-web/engine');
const engine = new MinesweeperEngine();
// ...
```
## License
[MIT License](./LICENSE)
### Icons Copyright
All rights for the icons used in this project belongs to their original creators:
https://commons.wikimedia.org/wiki/Category:Minesweeper
The icons "bomb_red.svg" and "bomb.svg" are based on "number-0.svg" and "flag_missed.svg" is based on "bomb.svg".