GithubHelp home page GithubHelp logo

solved's Introduction

solved

A puzzle solver in TypeScript

Build Status

Usage

First run npm install in this directory to fetch the dependencies. Then, run npm test in this directory with a node version between 6 and 6.4 installed. (Not any newer! The versions of v8 they use seems to have an optimizer bug which causes the slitherlink FollowedEdges strategy to behave erratically and cause solving to fail * I don't have time to look into this, but I imagine it's very interesting!)

What's Included

A Rain Radar solver (and sample puzzle generation script)

  • This solver is mostly brute force with a few simple heuristics such as not bothering with placements which would bring a constraint to 1.

A Slitherlink solver which utilizes the following strategies:

  • ConstainZero
    • Marks all sides of a zero as not a wall
  • ConstrainThree
    • If one side of a three is marked as not a wall, marks the other three as walls
    • If three sides are walls, marks the last as not a wall
  • ConstrainOne
    • If one side is marked as a wall, marks the other three as not walls
    • If three sides are marked as not walls, the remaining side is marked as not a wall
  • ConstrainTwo
    • If two sides are marked as walls, the other two are marked as not walls and vice*versa
  • AdjacentThrees
    • Adjacent threes must share walls on their shared edges and must have edges on the sides opposite that shared edge. Additionally, the shared edge must go towards one of the threes, and not out.
  • DiagonalThrees
    • Diagonal threes must have walls opposite one another.
  • ThreeDeductions
    • An edge leading towards a three implies edges on the opposite two corners.
    • Two sides marked not a wall leading towards the same corner of a three imply the other two sides connecting to that corner must be walls.
  • TwosSemicorner
    • This one is complicated. Trust me. There are 8 cases of a pattern involving 3 not a wall markers around a two at each rotation, each of which implies a different wall.
  • NonWallsByOnes
    • Ones with not a walls leading to them imply the connecting edges are also not walls.
  • FollowedEdges
    • If three edges leading to a point are not walls, the last is not a wall.
    • If two walls are connected to a point, the last two are not walls.
    • If one wall and two not wall markers connect to a point, the last edge is a wall.
  • GuessContinuous
    • Enumerates all potential continuations of existing walls. First and best fallback when applying a known pattern fails.
  • GuessConstrained
    • Enumerates all potential walls alongside an existing constraint. Unlikely but theoretically possible to be used to guess a puzzle start.
  • GuessBlank
    • Enumerates all completely unconstrained potential wall places. Literally only possible when a puzzle only has zeros for constraints.

Much credit to @mooman219 for helping me dream up and verify some of the more interesting strategies here!

API

While not packaged as a library, if included by a script, this package does provide a well-defined and typed public API. The top level members are the following:

  • RainRadar
    • Namespace containing a RainRadar Solver and related types
  • Slitherlink
    • Namespace containing a Slitherlink Solver, related types, and a Strategies namespace containing all strategies which have been implemented. The solver accepts a list of strategies as optional arguments if you wish to limit what it solves with (useful for verifying if a puzzle can only be solved using simple inductions!)

Writing Your Own

Solvers

./solver/index.ts contains abstract base classes for both a generic backtracking solver and a solver which specifically attempts to utilize various strategies. Simply inherit from one of these and implement the required members. I keep mine in the ./puzzles subdirectory, and reexport the solvers and their associated types and machinery under a namespace via the index.ts.

Tests

I use mocha as a test runner alongside chai as an assertion library. I used exclusively expectation-style assertions within BDD-style describe/it blocks. Adding a new test is accomplished simply by dropping a new .ts or .js file into the ./test subdirectory. By my own convention, files are named [puzzle].test.ts, and test the named puzzle exclusively.

Scripts

This repository is not packaged for individual resale - the solvers are not transpiled by a build step and are not immediately distributable as a library. It is easiest to work with them (to, for example, actually solve a puzzle with one) by writing a short .ts file in the scripts folder which does what you want (since different puzzles have different state construction requirements), which you then run with ts-node. For example, if I wanted to solve this simple slitherlink puzzle:

     ·   ·   ·   ·
       1   3   2     
     ·   ·   ·   ·
       0       2 
     ·   ·   ·   ·
       1   3   2 
     ·   ·   ·   ·

Failing adding it to the permanent tests in the ./test dir, I would write the following out to a ./scripts/slither-1.ts:

import {Slitherlink} from "../";
const initial = Slitherlink.newState([
    [1,3,2,],
    [0, ,2,],
    [1,3,2,],
]);
const solver = new Slitherlink.Solver();
console.log("Initial:");
solver.display(initial);
console.log("");
const gen = solver.solutions(initial);
const first = gen.next().value;
solver.display(first);

and execute it with ts-node ./scripts/slither-1.ts to see the result. Having the entire library available to you also allows you do do nice things like check for more than one solution:

import {Slitherlink} from "../";
const initial = Slitherlink.newState([
    [1,3,2,],
    [0, ,2,],
    [1,3,2,],
]);
const solver = new Slitherlink.Solver();
const gen = solver.solutions(initial);
const first = gen.next().value;
const second = gen.next().value;
if (!first) {
    console.error("No solution!");
} else if (second) {
    console.error("More than one solution!");
} else {
    solver.display(first);
}

Or, as is done in the provided rain radar script, search for a puzzle fitting certain constraints.

solved's People

Contributors

weswigham avatar

Watchers

 avatar  avatar

solved's Issues

Improve Slitherlink Solver Efficiency

It takes approximately 15 seconds to solve the medium puzzle, and it will probably take longer than is reasonable on a larger, harder puzzle (the more branches which must be made when the inference strategies fail, the higher the branch complexity and the longer it takes to find a solution). The isInvalid and traceLoop functions are prime targets for optimization. traceLoop currently uses a naive edge following method to look for loops, when combined with the requirements of isInvalid (tracing all the potential loops and ensuring there are none or one complete one). There's also potential for savings in how strategies are executed - many of them iterate over the same sets of things (edges or grid squares) - combining all these walks into one simultaneous walk which only applies changes from the highest-ranking strategy could be beneficial.

Obviously, more branchless strategies can make the solver faster for puzzles within which they're utilized, too. (Though I'm having trouble thinking of many more which don't involve a look-ahead, which the backtracking-and-guessing strategies accomplish already.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.