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

morris

v0.1.4

Published

Nine Men's Morris implementation in Node.js

Downloads

465

Readme

Nine Men's Morris

I separated the board logic from the game logic to make the game extensible and modular. The game logic implements parts like rule validation.

Installation

npm install morris

CLI Usage

To use the morris CLI program, install it globally.

npm install morris -g

The board is completely modular which means that you are not focused on the normal look of a Nine Men's Morris board. By using the property points in board options, you can define how many points exist on each side and wether they are connected with the upper row. And the amount or rows can be defined with the property rows in board options. More about the idea behind points in Points.

To require the module you can browserify it simply with browserify. In the case of a browser's API the module will add the class MorrisGame to the window object you can use instead.

As Node.js module, just require it:

const Morris = require('morris');

To create a new game instance call:

var myGame = new Morris({
  board: {
    rows: 3,
    points: [false, true, false]
  },
  pieces: 9,
  rules: true
});

The Morris class will automatically create a new MorrisBoard instance for itself. You find it at as board property of your game instance. As I already said, the board is own class instance for controlling the board. Normally you do not need manipulating it directly but if you want to know how, have a look at [Morris Board](#Morris Board).

That is just good to know to understand why addressing a point will be done by defining a row and a position (Index within the row).

The reason why I separated board and game logic is, that this keeps the process completely clean extensible.

Important

Please note that the board works with a circular coordinate system. What that means is described more detailed below.

Your instance should look like:

{
  board: <MorrisBoard>, // The instance of the board your game instance uses
  points: [Array], // Array containing the template for points on each side
  rules: true || false, // Wether rule validation is enabled
  // More information about the structure of a team and a 'piece' object you will find below
  teams: [
    {
      name: "white",
      pieces: [Array] // Array containing your defined amount of pieces for each team as objects
    },
    {
      name: "black",
      pieces: [Array] // Array containing your defined amount of pieces for each team as objects
    }
  ],
  // Object containing some information to validate rules like 'nextTeam' or 'nextAction'
  __rule: {
    nextTeam: [Getter], // Returns the next team using the information about the last changeset
    nextAction: [Getter], // Returns the next action using the information about the last changeset
    __lastChangeset: <ChangeSet> // The last successfull changeset. Used to get next team or action
  }
}

Ruling

The algorithms for validating rules and all related properties and methods are absolutely responsive which means, that your game instance will not modify more properties than needed. The only important property that will always be edited by your game instance is the __lastChangeset property in __rule (More about this below). All the other stuff like phase, gameOver, nextTeam, nextAction

Points

The points property of your instance is the same as you used as argument when creating the instance. If you did not specified one, the default one is used. In detail this array describes, how many points your board has on each side and wether they are connected with each other.

For example, the default points array looks like:

[false, true, false]

This means that the points left and right side are not connected with the upper and lower one but the point in the middle is. Because a Nine Men's Morris board normally looks like this, this is the default value.

Teams

The teams array of your instance contains objects that represent each team. Normally there exist exactly two teams, called black and white but theoretically more teams would be possible. And also the algorithms behind rule validation and game logic are made for more than two teams.

But that is just the general theory behind it.

A team object looks like:

{
  name: "teamName",
  pieces: [Array] // Array containing your defined amount of pieces for each team as objects
}

Pieces

As you saw, the pieces array within a team object contains each piece as an object. You can define the amount of the pieces for each team in pieces property when creating your game instance.

A piece object literal contains thre properties. point whose value represents an index in map array within the in game's board instance. If the piece is not set yet, point is null. The other property is removed that contains a boolean value. It is used to declare a piece as removed. The third one is the Getter activePieces that just returns an array with all pieces of the team that are not removed but still active.

{
  name: "teamName", // "white" or "black"
  pieces: [
    ...
    {
      point: null, // null or the index of the point, the piece is standing on
      removed: false // Wether the piece is already removed
    }
    ...
  ]
}

Rules

To handle internally with rules and the logic of a game, a object for rules, named __rule exist in your game instance.

Get Moves

To get a list of all valid moves call:

myGame.getMoves();

This will return an array containing objects representing each movement specially for the kind of movement. For example, a set & remove movement only needs a targetPoint property wether a move movement usually has also a startPoint property containing the point the movement is going to start from.

Movement Object Literal

{
  action: "movementName", // "set", "move" or "remove"; String describing the kind of movement
  startPoint: [Object], // Optional. Point object literal who refers to the start point within the 'board.map'
  targetPoint: [Object], // Point object literal who refers to the target point within the 'board.map'
  team: "teamName" // "white" or "black"
}

Get Piece

To get a piece that is related to a point's position, use the getPiece method.

// Returns the piece object literal
var piece = myGame.getPiece({
  row: 0,
  position: 0
});
// Log the piece object
console.log(piece);

Important

If not piece is related to this point, the method will return undefined.

Set

To set a new piece to the board use the set method of your game instance. (More about the coordinating system in MorrisBoard->Coordinating)

var changeset = myGame.set({
  team: "white", // Name of the team you want to use
  row: 0,
  position: 0
});
// If an error occured (Set action was not allowed)
if (changeset.error) {
  console.error(err);
}
// The set action was successfully
else {
  console.log(changeset);
}

Move

To move a piece from one point to another one, use the move method of your game instance.

var changeset = myGame.move({
  row: 0,
  position: 0,
}, {
  row: 0,
  position: 1,
});

// If an error occured (Movement was not allowed)
if (changeset.error) {
  console.error(err);
}
// The movement was successfully
else {
  console.log(changeset);
}

Remove

To remove a piece from the board, use the remove method of your game instance.

var changeset = myGame.remove({
  row: 0,
  position: 0
});
// If an error occured (Removement was not allowed)
if (changeset.error) {
  console.error(err);
}
// The removement was successfully
else {
  console.log(changeset);
}

Next Team

To get the next team just get the property nextTeam of your game instance. Please keep in mind that this property is a getter and is related to the __lastChangeset object of your game instance.

// Get the next team
var nextTeam = myGame.nextTeam;

// Log it
console.log(nextTeam);

Important

Please keep in mind that after a created mill, the next action is normally remove. But the next team is* not the team that is removing (Normally the same team that created the mill before) but the contrary team whose piece will be removed.

Next Action

To get the next action that should be performed within the game, just get the property nextAction of your game instance.

// Get the next action
var nextAction = myGame.nextAction;

// Log it
console.log(nextAction);

Phase

The phase property of your game instance returns the current phase of the match. (0-2) / (1-3)

// Get the current match's phase
var phase = myGame.phase;

// Log it
console.log(phase);

Game Over

To get wether the game is over, just get the gameOver property of your game instance.

// Get wether the game is over
var isGameOver = myGame.gameOver;

// Log it
console.log(isGameOver);

Draw

To get wether the game is a draw, just get the draw property of your game instance.

// Get wether the game is a draw
var isDraw = myGame.draw;

// Log it
console.log(isDraw);