npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

minesweeper-redux

v7.0.0

Published

A JavaScript minesweeper game engine implementation supporting the use of redux via the provided actions and reducer. It is written in TypeScript in an immutable approach.

Downloads

64

Readme

Minesweeper Redux

A JavaScript minesweeper game engine implementation supporting the use of redux via the provided actions and reducer. It is written in TypeScript in an immutable approach.

Example Usage

Basic Usage

Here are the basics of importing and using minesweeper-redux in your app.

1. Import minesweeper-redux gameReducer into your reducer.

import { createStore, combineReducers } from 'redux'
import { gameReducer } from 'minesweeper-redux'

const reducers = combineReducers({
  minesweeper: gameReducer,
})

const store = createStore(reducers)

export default store

2. Dispatching actions to the reducer.

Create a component, create the mapStateToProps and mapDispatchToProps functions and connect the component to the store.

import {
  createDifficultyLevel,
  getLoadableGameState,
  createCoordinate,
  startGame,
  loadGame,
  revealCell,
  toggleFlag,
  undoLoosingMove,
  tickTimer,
  difficulties,
} from 'minesweeper-redux'
import { connect } from 'react-redux'

function MyComponent(props) {
  return (
    <div>
      <h1>My Component</h1>
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    minesweeper: state.minesweeper,
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    startGame: (options) => dispatch(startGame(options)),
    loadGame: (options) => dispatch(loadGame(options)),
    revealCell: (options) => dispatch(revealCell(options)),
    toggleFlag: (options) => dispatch(toggleFlag(options)),
    undoLoosingMove: () => dispatch(undoLoosingMove()),
    tickTimer: () => dispatch(tickTimer()),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)

Using startGame action

// function that will be called every second. In this case we want to call tickTimer().
const timerCallback = () => {
  props.tickTimer()
}
// value to seed the random number generator.
const myRandSeed = Math.random()
const myDifficulty = difficulties.easy // .easy .medium .hard
// OR
const myDifficulty = createDifficultyLevel(4, 4, 2) // custom difficulty

props.startGame({
  timerCallback: timerCallback, // is optional
  randSeed: myRandSeed,
  difficulty: myDifficulty,
})

Using loadGame action

// function that will be called every second. In this case we want to call tickTimer().
const myTimerCallback = () => {
  props.tickTimer()
}
// serialize a loadable game state from the current game state.
const loadableGameState = getLoadableGameState(props.minesweeper)

props.loadGame({
  timerCallback: myTimerCallback, // is optional
  gameState: loadableGameState,
})

Using revealCell action

const myCoordinate = createCoordinate(2, 1)
props.revealCell({ coordinate: myCoordinate })

Using toggleCell action

const myCoordinate = createCoordinate(2, 1)
props.toggleCell({ coordinate: myCoordinate })

Using undoLoosingMove action.

props.undoLoosingMove()

The Game State and Types

/** Contains the necessary values for a minesweeper game. */
export type Minesweeper = Readonly<{
  /** The difficulty of the game. */
  difficulty: Difficulty
  /** The current status of the game. */
  status: GameStatus
  /** The number of cells on the grid. */
  numCells: number
  /** The game grid. */
  grid: Grid
  /** The previously saved grid state. */
  savedGridState?: Grid
  /** The number of flagged cells. */
  numFlagged: number
  /** The remaining flags. */
  remainingFlags: number
  /** The number to seed RandomNumberGenerator */
  randSeed: number
  /** The amount of time in ms since the game began.  */
  elapsedTime: number
  /** Function that is called once every second. */
  timerCallback?: TimerCallback
  /** Stops the timer. The property is set when timer has been started. */
  timerStopper?: TimerStopper
}>

/** The status of a cell. */
export type CellStatus = 'hidden' | 'flagged' | 'revealed' | 'detonated'

/** A cell of a minesweeper game. */
export type Cell = Readonly<{
  /** The status of the cell. */
  status: CellStatus
  /** The amount of adjacent mines surrounding the cell. Is `-1` if cell is a mine. */
  mineCount: number
}>

/** A coordinate of a grid. */
export type Coordinate = Readonly<{
  x: number
  y: number
}>

/** The minesweeper game's difficulty level. */
export type Difficulty = Readonly<{
  height: number
  width: number
  numMines: number
}>

/** The current status of the game. */
export type GameStatus = 'waiting' | 'ready' | 'running' | 'loss' | 'win'

/** A callback for the game timer. */
export type TimerCallback = () => void

/** Stops a timer. It is the function returned when timer is started. */
export type TimerStopper = () => void

/** A grid made up of cells. */
export type Grid = ReadonlyArray<ReadonlyArray<Cell>>

/** Generates a random number from a seed number. */
export type RandomNumberGenerator = (max?: number, min?: number) => number

Actions

/** Create a minesweeper game. */
export const startGame = (options: StartGameActionOptions): StartGameAction => ({
  type: 'START_GAME',
  ...options,
})

/** Load a game from given game state. */
export const loadGame = (options: LoadGameActionOptions): LoadGameAction => ({
  type: 'LOAD_GAME',
  ...options,
})

/** Make cell revealed at the given coordinate. */
export const revealCell = (options: RevealCellActionOptions): RevealCellAction => ({
  type: 'REVEAL_CELL',
  ...options,
})

/** Toggle the flag value of cell at the given coordinate. */
export const toggleFlag = (options: ToggleFlagActionOptions): ToggleFlagAction => ({
  type: 'TOGGLE_FLAG',
  ...options,
})

/** Load the previous state before the game was lost. */
export const undoLoosingMove = (): UndoLoosingMoveAction => ({
  type: 'UNDO_LOOSING_MOVE',
})

/** Tick the game timer. Add 1 (seconds) to elapsed time. */
export const tickTimer = (): TickTimerAction => ({
  type: 'TICK_TIMER',
})

Action Options

// startGame
interface StartGameActionOptions {
  difficulty: IDifficulty
  randSeed: number
  timerCallback?: TimerCallback
}

// loadGame
interface LoadGameActionOptions {
  gameState: IMinesweeper
  timerCallback?: TimerCallback
}

// revealCell
interface RevealCellActionOptions {
  coordinate: Coordinate
}

// toggleFlag
interface ToggleFlagActionOptions {
  coordinate: Coordinate
}

// both undoLoosingMove & tickTimer have no parameters