{"id":20699408,"url":"https://github.com/manuelhenke/minesweeper-for-web","last_synced_at":"2025-04-22T22:03:18.805Z","repository":{"id":40668289,"uuid":"261740924","full_name":"manuelhenke/minesweeper-for-web","owner":"manuelhenke","description":"Minesweeper as a WebComponent","archived":false,"fork":false,"pushed_at":"2024-01-30T08:43:34.000Z","size":1622,"stargazers_count":3,"open_issues_count":15,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-29T19:11:29.447Z","etag":null,"topics":["css","game","lit-element","lit-html","minesweeper","typescript","webcomponent","webpack"],"latest_commit_sha":null,"homepage":"https://henkebyte.com/minesweeper","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/manuelhenke.png","metadata":{"funding":{"github":["manuelhenke"]},"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-06T11:41:08.000Z","updated_at":"2024-10-13T18:25:44.000Z","dependencies_parsed_at":"2024-01-30T09:52:38.409Z","dependency_job_id":null,"html_url":"https://github.com/manuelhenke/minesweeper-for-web","commit_stats":{"total_commits":340,"total_committers":5,"mean_commits":68.0,"dds":0.35,"last_synced_commit":"270417c21ec6a893a29c4a864c459eca4da85316"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelhenke%2Fminesweeper-for-web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelhenke%2Fminesweeper-for-web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelhenke%2Fminesweeper-for-web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelhenke%2Fminesweeper-for-web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manuelhenke","download_url":"https://codeload.github.com/manuelhenke/minesweeper-for-web/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250331803,"owners_count":21413100,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css","game","lit-element","lit-html","minesweeper","typescript","webcomponent","webpack"],"created_at":"2024-11-17T00:29:37.421Z","updated_at":"2025-04-22T22:03:18.759Z","avatar_url":"https://github.com/manuelhenke.png","language":"TypeScript","funding_links":["https://github.com/sponsors/manuelhenke"],"categories":[],"sub_categories":[],"readme":"# minesweeper-for-web\n\n[![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)\n[![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)\n[![License](https://img.shields.io/github/license/manuelhenke/minesweeper-for-web)](./LICENSE)\n[![NPM version](https://img.shields.io/npm/v/minesweeper-for-web.svg?style=flat)](https://www.npmjs.com/package/minesweeper-for-web)\n\nThis 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.\n\n## Getting Started\n\nInstall the package via `npm` or `yarn` and deliver the script to the user.\nThis can be done via `import`, `require` or just inserting a `script` tag.\n\n```shell\nnpm i minesweeper-for-web\n```\n\n```shell\nyarn add minesweeper-for-web\n```\n\n## Attributes\n\n| Param                    | Type      | Description                                                                                                                                       | Default |\n| ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |\n| `columns`                | `number`  | Amount of columns of the board.                                                                                                                   | `9`     |\n| `rows`                   | `number`  | Amount of rows of the board.                                                                                                                      | `9`     |\n| `bombs`                  | `number`  | Amount of bombs of the board.                                                                                                                     | `10`    |\n| `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`   |\n| `disable-question-marks` | `boolean` | Disables the functionality to place question marks.                                                                                               | `false` |\n| `flag-placement-mode`    | `boolean` | Enables the flag placement mode. A mode where every click places a flag instead of revealing the field.                                           | `false` |\n| `restart-selector`       | `string`  | If present, attaches a click event listener to the element to trigger a restart.                                                                  |         |\n| `bomb-counter-selector`  | `string`  | If present, changes the `textContent` of the provided element to the amount of bombs minus the amount of placed flags.                            |         |\n\n## Events\n\nBy default, each event contains the current game state in `event.detail.game`. To discourage cheating, no events should be logged in the browser console.\n| Name | Type | Cancelable | Description | `detail` |\n| ------------- | ------------- | ------------------ | ------------------------- | ------ |\n| `minesweeper:game-won` | `GameWonEvent`| :x: | User just won the game | \u003cul\u003e\u003cli\u003e`board`: `MinesweeperBoard` current game state\u003c/li\u003e\u003c/ul\u003e |\n| `minesweeper:game-lost` | `GameLostEvent`| :x: | User just lost the game | \u003cul\u003e\u003cli\u003e`board`: `MinesweeperBoard` current game state\u003c/li\u003e\u003c/ul\u003e |\n| `minesweeper:field-click` | `FieldClickEvent`| :white_check_mark: | User clicked a field | \u003cul\u003e\u003cli\u003e`board`: `MinesweeperBoard` current game state\u003c/li\u003e\u003cli\u003e`target`: `FieldTarget` target of the click\u003c/li\u003e\u003cli\u003e`field`: `HTMLElement` clicked field\u003c/li\u003e\u003c/ul\u003e |\n| `minesweeper:field-long-press` | `FieldLongPressEvent`| :white_check_mark: | User long pressed a field | \u003cul\u003e\u003cli\u003e`board`: `MinesweeperBoard` current game state\u003c/li\u003e\u003cli\u003e`target`: `FieldTarget` target of the long press\u003c/li\u003e\u003cli\u003e`field`: `HTMLElement` long pressed field\u003c/li\u003e\u003c/ul\u003e |\n| `minesweeper:field-interaction` | `FieldInteractionEvent`| :x: | Game state change occurred | \u003cul\u003e\u003cli\u003e`board`: `MinesweeperBoard` current game state\u003c/li\u003e\u003cli\u003e`target`: `FieldTarget` target of the interaction\u003c/li\u003e\u003cli\u003e`interaction`: `Interaction` interaction information\u003c/li\u003e\u003c/ul\u003e |\n\n## Usage\n\n### Basic usage\n\nJust a basic 9x9 / 10 Mines minesweeper game. Further examples can be **combined**.\n\n```html\n\u003cminesweeper-game\u003e\u003c/minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n  // Alternatives:\n  // import 'minesweeper-for-web/custom-element';\n  // import 'minesweeper-for-web/custom-element.min';\n\u003c/script\u003e\n```\n\n### Custom tag name\n\nDefine your own custom tag name\n\n```html\n\u003ccustom-minesweeper-game\u003e\u003c/custom-minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import { MinesweeperGame } from 'minesweeper-for-web/minesweeper-game';\n  // Alternative:\n  // import { MinesweeperGame } from 'minesweeper-for-web/minesweeper-game.min';\n  window.customElements.define('custom-minesweeper-game', MinesweeperGame);\n\u003c/script\u003e\n```\n\n### Provide left-bomb-counter container\n\nTo keep the user informed how many mines are left, after subtracting the number of placed flags, just provide a container for the counter.\n\n```html\n\u003cp\u003e\u003cspan id=\"bomb-counter\"\u003e\u003c/span\u003e Mines\u003c/p\u003e\n\u003cminesweeper-game bomb-counter-selector=\"#bomb-counter\"\u003e\u003c/minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\u003c/script\u003e\n```\n\n### Provide a restart button\n\nProvide a selector where a \"click\"-event will be attached to, to restart the game.\n\n```html\n\u003cminesweeper-game restart-selector=\"#restart-game-button\"\u003e\u003c/minesweeper-game\u003e\n\u003cbutton id=\"restart-game-button\"\u003eRestart!\u003c/button\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\u003c/script\u003e\n```\n\n### Disable Long Press\n\nProvide a number lower or equal to `0` to disable the long press functionality.\n\n```html\n\u003cminesweeper-game long-press-threshold=\"0\"\u003e\u003c/minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\u003c/script\u003e\n```\n\n### Trigger Restart via JavaScript\n\nWrite custom logic to restart the game.\n\n```html\n\u003cminesweeper-game id=\"minesweeper\"\u003e\u003c/minesweeper-game\u003e\n\u003cbutton id=\"restart-game-button-confirm\"\u003eRestart with Confirm!\u003c/button\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\n  window.addEventListener('DOMContentLoaded', () =\u003e {\n    const minesweeper = document.querySelector('#minesweeper');\n\n    document.querySelector('#restart-game-button-confirm').addEventListener('click', (event) =\u003e {\n      event.preventDefault();\n      if (window.confirm('Are you sure, that you want to restart the game?')) {\n        minesweeper.restartGame();\n      }\n    });\n  });\n\u003c/script\u003e\n```\n\n### Custom win/lose event listener\n\nAttach an EventListener for the win/lose events.\n\n```html\n\u003cminesweeper-game id=\"minesweeper\"\u003e\u003c/minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\n  window.addEventListener('DOMContentLoaded', () =\u003e {\n    const minesweeper = document.querySelector('#minesweeper');\n\n    minesweeper.addEventListener('minesweeper:game-won', () =\u003e {\n      console.log('win');\n    });\n\n    minesweeper.addEventListener('minesweeper:game-lost', () =\u003e {\n      console.log('lose');\n    });\n  });\n\u003c/script\u003e\n```\n\n### Different initial game configurations\n\nOf course you can provide different configurations for the game.\n\n```html\n\u003cminesweeper-game rows=\"30\" columns=\"16\" bombs=\"99\"\u003e\u003c/minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\u003c/script\u003e\n```\n\n### Providing a selectable gamemode\n\nFurthermore you can implement some own logic to create a selectable gamemode\n\n```html\n\u003cselect name=\"select-game-mode\" id=\"select-game-mode\"\u003e\n  \u003coption value=\"easy\" selected\u003eEasy - 9x9 / 10 Mines\u003c/option\u003e\n  \u003coption value=\"normal\"\u003eNormal - 16x16 / 40 Mines\u003c/option\u003e\n  \u003coption value=\"hard\"\u003eHard - 16x30 / 99 Mines\u003c/option\u003e\n\u003c/select\u003e\n\n\u003cminesweeper-game id=\"minesweeper\"\u003e\u003c/minesweeper-game\u003e\n\n\u003cscript type=\"module\"\u003e\n  import 'minesweeper-for-web';\n\n  function getGameModeConfiguration(currentGameMode) {\n    switch (currentGameMode) {\n      case 'hard':\n        return {\n          columns: 30,\n          rows: 16,\n          bombs: 99,\n        };\n      case 'normal':\n        return {\n          columns: 16,\n          rows: 16,\n          bombs: 40,\n        };\n      default: // 'easy'\n        return {\n          columns: 9,\n          rows: 9,\n          bombs: 10,\n        };\n    }\n  }\n\n  window.addEventListener('DOMContentLoaded', () =\u003e {\n    const minesweeper = document.querySelector('#minesweeper');\n\n    document.querySelector('#select-game-mode').addEventListener('change', (event) =\u003e {\n      event.preventDefault();\n\n      const gameModeConfiguration = getGameModeConfiguration(event.target.value);\n      minesweeper.setGameModeConfiguration(gameModeConfiguration);\n    });\n  });\n\u003c/script\u003e\n```\n\n## Example\n\nTry it out at [CodePen](https://codepen.io/manuelhenke/pen/ExoPKLZ).\n\n![Example Image](minesweeper-example.png)\n\n## TypeScript\n\nThe whole package is written in TypeScript and therefore provides a strongly typed system via the `core` export of the package:\n\n```html\n\u003c!-- some-file.html --\u003e\n\u003cminesweeper-game id=\"minesweeper\"\u003e\u003c/minesweeper-game\u003e\n```\n\n```typescript\n// some-file.ts\nimport 'minesweeper-for-web/custom-element';\nimport { FieldInteractionEvent, FieldInteractionType } from 'minesweeper-for-web/core';\nimport type { MinesweeperGame } from 'minesweeper-for-web/core';\n\nconst minesweeperGame = document.querySelector('#minesweeper') as MinesweeperGame;\nminesweeperGame.addEventListener(\n  'minesweeper:field-interaction',\n  (event: FieldInteractionEvent) =\u003e {\n    const { interaction } = event.detail;\n    switch (interaction.type) {\n      case FieldInteractionType.Unveiled:\n        console.log('Revealed field value:', interaction.value);\n        break;\n      case FieldInteractionType.FlagAction:\n      case FieldInteractionType.QuestionMarkAction:\n        console.log('Performed action:', interaction.action);\n        break;\n    }\n  }\n);\n```\n\n## Engine\n\nThe 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).\n\n```javascript\nimport { MinesweeperEngine } from 'minesweeper-for-web/engine';\n\nconst engine = new MinesweeperEngine();\n\n// Creates a board with 10 columns, 12 rows and 10 bombs\nengine.createBoard(10, 12, 10);\n\n// Unveils the field in the first row and second column (indexes)\nengine.selectField(0, 1);\n\n// Follows the specification of `selectField`\nengine.toggleFlag(0, 2);\n// Nothing happens since a flag is present on that field\nengine.selectField(0, 2);\n\n// Follows the specification of `selectField`\nengine.toggleQuestionMark(0, 3);\n// Still unveils the field regardless of the question mark\nengine.selectField(0, 3);\n\nif (engine.isGameOver) {\n  // Restarts the game with the initial configuration\n  engine.restart();\n}\n```\n\n```javascript\nconst { MinesweeperEngine } = require('minesweeper-for-web/engine');\n\nconst engine = new MinesweeperEngine();\n\n// ...\n```\n\n## License\n\n[MIT License](./LICENSE)\n\n### Icons Copyright\n\nAll rights for the icons used in this project belongs to their original creators:\nhttps://commons.wikimedia.org/wiki/Category:Minesweeper\n\nThe icons \"bomb_red.svg\" and \"bomb.svg\" are based on \"number-0.svg\" and \"flag_missed.svg\" is based on \"bomb.svg\".\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuelhenke%2Fminesweeper-for-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanuelhenke%2Fminesweeper-for-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuelhenke%2Fminesweeper-for-web/lists"}