Mystery Master

Model a Logic Puzzle in JavaScript

Michael Benson


Table of Contents

Detective

Introduction

This article explains how to model a logic grid puzzle in the JavaScript programming language. Logic grid puzzles, also known as logic puzzles or logic problems can be found in magazines by Dell Magazines and Penny Press. The Mystery Master website at http://www.mysterymaster.com is devoted to writing software that can solve logic puzzles. Think "Skynet", but without the intent of eliminating mankind. This article will focus on the logic puzzle "Five Houses". Earlier versions of this two-star puzzle have been called "Einstein's Riddle" or the "Zebra Puzzle". This version of the puzzle appeared in a column by the very cerebral Marilyn vos Savant. Please look at this logic puzzle before continuing. You should have a basic knowledge of JavaScript, know some of the newer constructs, and understand how classes work in JavaScript.

JavaScript

JavaScript is the client-side language of the web. I don't think it is the best language, but there have been improvements over the years. I wish it was strongly-typed, had better scoping rules (public, private, etc.), but I guess I could use TypeScript. It can't do some of the nice things I can do in C# like initialize an object when I instantiate it. It doesn't have the null-coalescing operator ??. It is also very fragile - your IDE and/or browser may not pick up your mistakes. But enough complaining... Here are some of the things I do like.

  1. The "use strict"; option.
  2. Define a constant with the const keyword.
  3. Avoid the hoisting of variables with the let keyword.
  4. The addEventListener method so the method the event calls can be local.
  5. The ability to return closures - functions that refer to local variables. See the sections on Smart Links and Smart Rules for more on closures.
  6. The ability to store/retrieve information in local storage.

What is a Logic Puzzle

A logic puzzle is a story of mystery. But you are not only its reader, you are it's most important character - the detective! And as with any detective worth their spyglass, you must solve the mystery. Most logic puzzles have properties such as its title, author, and number of stars. One star means the puzzle is easy, and five stars means it is very difficult. Each puzzle also has a humorous image. While these properties are important, they won't help you solve a logic puzzle. What does help are the clues of the puzzle. The clues are usually given in a numbered list, but sometimes they can also be in the introduction. The properties, introduction, and list of clues are the text of the logic puzzle.

Note: If you wanted to solve a logic puzzle on your own, you have the following tools at your disposal: the Chart and the Grids. Both of these forms will be discussed in a future article.

To model a logic puzzle, the text of the logic puzzle must be parsed into specific types of data. Everything that is essential to solving a logic puzzle must be captured by this data. There is one important thing to remember as you go forward:

All of the relationships between the nouns in a logic puzzle must be expressed as either facts or rules.

Please read the text of the puzzle with the following questions in mind.

We need data structures to store each type of data, and when we talk data structures in a world of OOP, we're talking classes. And what should we name a class that stores all of the data for a logic puzzle? Why Puzzle of course!

Puzzle

The Puzzle class is the parent class of every puzzle module. This class performs many duties. It has methods to load data into an array for each type of object. It has a method to validate the data. And it needs to make that data available to the classes that view and solve the puzzle.

The Puzzle Class


	

Puzzle Module

The puzzle module stores all of the data and functions necessary to solve it. In order to do this, this class must inherit from the base class Puzzle. Below is the puzzle module for the logic puzzle "Five Houses". Please note that since all of the relationships in this puzzle can be represented by facts, there are no rules.

The FiveHouses Class

/* Puzzle module. Copyright by Michael Benson for Mystery Master. 2018-04-12. */
/* jshint unused:true, eqnull:true, esversion:6 */
"use strict";

let FiveHouses = function () {
	// Properties
	this.myName = "FiveHouses";
	this.myTitle = "Five Houses";

	// Nouns.
	let nounType1 = this.addNounType("House");
	nounType1.addNoun("1st");
	nounType1.addNoun("2nd");
	nounType1.addNoun("3rd");
	nounType1.addNoun("4th");
	nounType1.addNoun("5th");

	let nounType2 = this.addNounType("Color");
	nounType2.addNoun("red");
	nounType2.addNoun("green");
	nounType2.addNoun("white");
	nounType2.addNoun("yellow");
	nounType2.addNoun("blue");

	let nounType3 = this.addNounType("Nationality");
	nounType3.addNoun("Englishman");
	nounType3.addNoun("Spaniard");
	nounType3.addNoun("Ukrainian");
	nounType3.addNoun("Norwegian");
	nounType3.addNoun("Japanese man", "Japanese");

	let nounType4 = this.addNounType("Hobby");
	nounType4.addNoun("stamps");
	nounType4.addNoun("antiques");
	nounType4.addNoun("singing");
	nounType4.addNoun("gardening");
	nounType4.addNoun("cooking");

	let nounType5 = this.addNounType("Pet");
	nounType5.addNoun("dogs");
	nounType5.addNoun("snails");
	nounType5.addNoun("fox");
	nounType5.addNoun("horse");
	nounType5.addNoun("zebra");

	let nounType6 = this.addNounType("Drink");
	nounType6.addNoun("coffee");
	nounType6.addNoun("tea");
	nounType6.addNoun("milk");
	nounType6.addNoun("juice");
	nounType6.addNoun("water");

	// Links.
	let link1 = this.addLink("directly to the right of", nounType1);
	link1.grid = [
		[0,0,0,0,0],
		[1,0,0,0,0],
		[0,1,0,0,0],
		[0,0,1,0,0],
		[0,0,0,1,0]
	];

	let link2 = this.addLink("next to", nounType1);
	link2.grid = [
		[0,1,0,0,0],
		[1,0,1,0,0],
		[0,1,0,1,0],
		[0,0,1,0,1],
		[0,0,0,1,0]
	];

	// Facts.
	this.addFact("The Englishman lives in the red house (clue 1).");
	this.addFact("The Spaniard owns dogs (clue 2).");
	this.addFact("Coffee is drunk in the green house (clue 3).");
	this.addFact("The Ukrainian drinks tea (clue 4).");
	this.addFact("The green house is directly to the right of the white one (clue 5).");
	this.addFact("The stamp collector owns snails (clue 6).");
	this.addFact("The antiques collector lives in the yellow house (clue 7).");
	this.addFact("The man in the middle house drinks milk (clue 8).");
	this.addFact("The Norwegian lives in the first house (clue 9).");
	this.addFact("The man who sings lives next to the man with the fox (clue 10).");
	this.addFact("The man who gardens drinks juice (clue 11).");
	this.addFact("The antiques collector lives next to the man with the horse (clue 12).");
	this.addFact("The Japanese man's hobby is cooking (clue 13).");
	this.addFact("The Norwegian lives next to the blue house (clue 14).");
};

Prototypal Inheritance

You can see that the name of the puzzle module class is FiveHouses. So how does our child class inherit the powers of the Puzzle class? The last three lines of every puzzle module performs "inheritance" for a prototype-based language. Note: the variable puzzle was defined earlier as a global.

	FiveHouses.prototype = new Puzzle();
	FiveHouses.prototype.constructor = FiveHouses;
	puzzle = new FiveHouses();
	

Here is a description of what each line does.

  1. Sets the FiveHouses class to inherit from the base class Puzzle. Unfortunately, the constructor for the child class FiveHouses is now set to the constructor of the parent class Puzzle.
  2. Sets the constructor for FiveHouses to its own constructor.
  3. Instantiates (creates) an object of class FiveHouses, which inherits from Puzzle, and invokes its own constructor.

I currently do not use the class and constructor keywords introduced in ECMAScript 2015. So when I say constructor, I really mean the function FiveHouses that I treat as a class. Let's discuss each section you may see in a puzzle module.

Properties

Properties are the metadata of a logic puzzle. The only properties we care about are the puzzle's name and title. This information is set via the Puzzle members myName and myTitle. I use these names instead of the more generic name and title to avoid naming collisions.

	// Properties.
	this.myName = "FiveHouses";
	this.myTitle = "Five Houses";
	

Nouns

The nouns in a logic puzzle must be organized into categories. These categories are called noun types. A puzzle must have at least two noun types. The noun types for our example puzzle are: House, Color, Nationality, Hobby, Pet, and Drink. Note that the names of the noun types are singular, not plural. For this puzzle, there are five nouns for each type. Below is a table of the nouns, where the column header is the noun type. Please keep in mind that each noun type must have the same number of nouns, and there must be at least two nouns per noun type.

Nouns
#HouseColorNationalityHobbyPetDrink
11stRedEnglishmanStampsDogsCoffee
22ndGreenSpaniardAntiquesSnailsTea
33rdWhiteUkrainianSingingFoxMilk
44thYellowNorwegianGardeningHorseJuice
55thBlueJapaneseCookingZebraWater

The first column (#) in this table shows the one-based number of the noun. Usually, the order of the nouns within a noun type is not important, but there is one major exception:

If a link references a noun type, then the nouns for that type must be in a logical order.

You'll understand why when you read the section on Links.

Placeholders

While most logic puzzles will give you all of the nouns in the puzzle, some very difficult puzzles may not give you all of the values of the nouns. This means the values must be calculated by one or more rules. Nouns where the initial value is unknown are called placeholders. Usually these values are numeric, such as the number of people who attended a talk in "Astrophysics Conference", or the age of a salesperson in "Dandy Salespeople".

The NounType Class

	
	

The Noun Class

	
	

Adding Nouns

A noun type is created using the Puzzle method addNounType. The nouns for each noun type are created using the NounType method addNoun. Here is the code for the first noun type House.

	// Nouns.
	let houses = this.addNounType("House");
	let house1 = houses.addNoun("1st");
	let house2 = houses.addNoun("2nd");
	let house3 = houses.addNoun("3rd");
	let house4 = houses.addNoun("4th");
	let house5 = houses.addNoun("5th");
	

Verbs

There are always three verbs in a logic puzzle. The three verbs are: the negative (false) verb, the possible (unknown) verb, and the positive (true) verb. Each verb has a brief text phrase for its name, and a character for its code. Our example logic puzzle has the following verbs.

Verbs
#TypeNameCode
-1Negativeis notX
0Possiblemay be
1PositiveisO

Here is a brief description of each verb.

The tense for the names of the verbs can be present, past, or future, and only affects the negative and positive verbs. As a general rule, the names of the negative and positive verbs should come from the clues. Here is an example.

The characters you see in the Grids form are given by the character for each verb. Before you begin solving a logic puzzle, each cell in the grids contains the possible verb, usually represented by a blank character. To solve a logic puzzle, each cell that contains the possible verb must be replaced by either the negative verb ('X'), or the positive verb ('O'). When all of the cells have been properly filled in, then you have the solution to the logic puzzle.

The Verb Class

	
	

Adding Verbs

The three nouns are always defined for each puzzle module. These three global variables are: IsNot, Maybe, and Is. Since the predefined attributes for these verbs are acceptable, this section is not needed for our puzzle module.

Note: I know I should avoid globals, but I also want to avoid having to prefix each class member with "this". So this is my compromise.

All of the relationships between two nouns in a puzzle must be expressed as verbs and links. When you examine the clues in a puzzle and the relationship is not obvious, this means the link is "with". For example, the first clue in our example puzzle states: "The Englishman lives in the red house." This clue can be expressed as a fact, where the first noun is "The Englishman", the verb is positive, and the link is "with". Anytime a clue states that one noun is or is not with another noun, just use the default link "with". In other words, the phrase "lives in" really means "with". The data for this fact could be interpreted as: fact(englishman, is, with, red).

For our example puzzle, there are three links: "with", "directly to the right of", and "next to". All of the links use the noun type House. To understand these links, draw a picture of the five houses in this puzzle. You want a picture of five numbered houses in a row, where the 1st house is on the far left, and the 5th house is on the far right. Assume each house is initially colorless.

1st House 2nd House 3rd House 4th House 5th House
1st 2nd 3rd 4th 5th

With

The first clue in our logic puzzle states: "The Englishman lives in the red house." If a clue states that one noun is or is not with another noun, then the default link "with" is used. In less-than-stellar English, the first clue tells us "The Englishman is with the red house." The "with" link is a one-to-one relationship because it means that a noun is with itself. This link is automatically defined for you, and it defaults to the first noun type of the puzzle. For our puzzle, here are the only statements that are true:

I highly recommend that if a noun type is referenced by the links, then it should be the first noun type you define. With that in mind, I should point out that a logic puzzle may have some links that reference one noun type, and other links that reference another noun type. For example "Small Town Motels" has seven links that reference three different noun types. Now that's a hard logic puzzle! In cases like this, have the most logical noun type be first.

Directly To The Right Of

The second link given by the clues is "directly to the right of". This link is in clue 5 "The green house is directly to the right of the white one." Going back to our picture, this means only the following statements are true.

This type of link has a "one-to-one" relationship because exactly one house is directly to the right of another house.

Next To

The third link given by the clues is "next to". This link is in clues 10, 12, and 14. While some houses are only next to one house, other houses are between two houses. Therefore, this link is not "one-to-one". Can you determine all of the statements that are true for this link?

Comparisons

The "directly to the right of" link is a "more than" comparison because we want to see if noun A is higher than noun B. This comparison is done using the one-based number of the noun. To reduce the number of links in a logic puzzle, use either "more than" or "less than" comparisons, but not both. For example, if a fact stated "A is less than B", you can also say "B is more than A", and vice versa. Below are the links for our example puzzle. The first table displays the links. Here is a brief description for each column.

  1. # is the zero-based number of the link.
  2. Noun Type is the noun type referenced by the link.
  3. Name is the name of the link.
  4. 1:1 tells use if the link is one-to-one (checked) or not (unchecked).

The subsequent tables display the link grid for each link. This type of grid visually informs us the relationship between noun A (left-most column of row headers) and noun B (top-most row of column headers). If the intersecting cell has a 'O', then the relationship between noun A and noun B is true. If the intersecting cell has a 'X', then the relationship between noun A and noun B is false.


with
House1st2nd3rd4th5th
1stOXXXX
2ndXOXXX
3rdXXOXX
4thXXXOX
5thXXXXO

directly to the right of
House1st2nd3rd4th5th
1stXXXXX
2ndOXXXX
3rdXOXXX
4thXXOXX
5thXXXOX

next to
House1st2nd3rd4th5th
1stXOXXX
2ndOXOXX
3rdXOXOX
4thXXOXO
5thXXXOX

The Link Class

	
	

Adding Links

The first link "with" is defined as a global, so it is always available for each puzzle module. Each link is created via the Puzzle method addLink. Here is the code for the other links in our puzzle.

	let directlyRightOf = this.addLink("directly to the right of", houses);
	directlyRightOf.f = SmartLink.getIsMoreBy(1);

	let nextTo = this.addLink("next to", houses);
	nextTo.f = SmartLink.getIsNextTo();
	

Note: The function assigned to each link via the f member is given by a method in the SmartLink static class. See the section on Smart Links for more information. If you cannot find what you want in the SmartLink class, you will need to "roll your own".

Facts

The facts are the static relationships between two nouns. An example is "A is next to B." A fact has the following form.

"Noun 1 Verb Link Noun 2.", where (1) the verb is positive or negative, and (2) the verb and link is the relationship between the two nouns.

The first clue in our example puzzle can be expressed directly as a fact: "The Englishman lives in the red house." In fact (pun intended), what makes this puzzle unique is that each clue is a fact. Here are the facts for this puzzle.

Facts
#XHitsName
10
20
30
40
50
60
70
80
90
100
110
120
130
140

Here is a brief description for each column.

  1. # is the one-based number of the fact.
  2. X tells you if the fact is enabled (checked) or disabled (unchecked).
  3. Hits is the number of times a fact is referenced.
  4. Name is the text of the fact.

Types of Facts

The types of facts are given below. While the first type of fact yields only one mark, the other types of facts usually produce more than one mark.

Type 1

A type 1 fact has the default link "with". Only a type 1 fact has "with" as the link. It is the easiest to process, and the easiest to notice when a mark contradicts it. Most of the facts in our example puzzle "Five Houses" are type 1 facts.

I must point out that both nouns in a type 1 fact cannot have the same noun type. Why? Because in any logic grid puzzle, two nouns of the same noun type can never be together! If you had the fact with two first names such as "Abe is with Bob", this would be a violation. And if you had the fact "Abe is not with Bob", this would simply be redundant.

Type 2

A type 2 fact has exactly one noun where its noun type matches the noun type of the link. It is slightly harder to process, and is harder to catch when a mark contradicts it. This puzzle, along with most puzzles, does not have this type of fact.

A logic puzzle that does have facts of type 2 is "Lucky Streets". In this puzzle, fact 15 states "She found the quarter earlier than Friday." This means the quarter was not found on Friday or Saturday. The quarter has the noun type "Coin", while the link "earlier than" and Friday both have the noun type "Day". In this puzzle, facts 16 and 17 are type 2 facts as well.

Again, I must point out that both nouns in a type 2 fact cannot have the same noun type. Why? Because this is like saying "Thursday is earlier than Friday." While this may be factually true, this is already defined within the link "earlier than".

Type 3

A type 3 fact has the same noun type for both nouns, but this noun type is different from the noun type of the link. A fact of type 3 from our example puzzle is fact 5: "The green house is directly to the right of the white one." The green house and the white house have the noun type "Color", and the link "directly to the right of" has the noun type "House".

Type 4

A type 4 fact is where the noun types for both nouns and the link are all different. From our example puzzle, facts 10, 12, and 14 are facts of type 4. Let's examine fact 10: "The man who sings lives next to the man with the fox." The man who sings has the noun type "Hobby". The link "next to" has the noun type "House". And the man with the fox has the noun type "Pet".

An important issue concerning logic puzzles has to do with whether two objects given in a clue are distinct, and therefore cannot be paired. For type 1 facts, the answer is explicitly given. For the other types of facts, usually the link will let you know whether this is true or not. If a fact states: "Abe is in a room next to the room the cat is in", then you know that Abe can never be in the same room as the cat.

But if the fact states: "Abe is in a room that is not next to the room the cat is in", it may be possible that Abe is in the same room as the cat. My suggestion is that if the clue does not say otherwise, assume that the two nouns given in the clue are distinct.

The Fact Class

	
	

Adding Facts

This logic puzzle is unique in that each clue corresponds to exactly one fact. This is usually not the case! Each fact is created via the Puzzle method addFact. Here is the first fact.

	this.addFact("1", englishman, Is, With, red, "The Englishman lives in the red house.");
	

Note: As you can see in this fact, the variables Is and With do not need to be prefixed by the this keyword because they are globals. I wish "this" was not an issue.

This method appears very straightforward. But I must tell you this method has overloads where you can enter more than one fact at a time. So let's discuss what those overloads are in another article.

Validating Facts

Before the Mystery Master solves a logic puzzle, it first validates the logic puzzle by looking for various logic errors. The Puzzle method that validates the puzzle is appropriately named validate. Here are some reasons a fact is invalid.

  1. The fact's verb is the possible verb ("maybe"). It must be either the positive verb ("is") or the negative verb ("is not").
  2. Both nouns in the fact are the same. The nouns in a fact must be different.
  3. The fact's link is "with", but both nouns have the same type. This is like saying "Bob is not Abe", or "Abe is Bob". For logic grid puzzles, two nouns of the same type are never together anyway.
  4. The fact's link is not "with", but both nouns have the same type as the link. For example "The 2nd person in line is ahead of the 4th person in line.", may make sense, but this is a relationship, not a fact! This statement is exactly what the "ahead of" link is suppose to define.

Rules

A rule is a conditional relationship between two or more nouns such as "If A is next to B, then C is not next to D." Rules are needed when facts cannot represent the clues in a logic puzzle. Since our example puzzle does not have rules, below is the puzzle module for the puzzle "All Tired Out".

/* Puzzle module. Copyright by Michael Benson for Mystery Master. 2018-04-10. */
/* global IsNot, Is, With, SmartLink, SmartRule, Puzzle, puzzle */
/* jshint unused:true, eqnull:true, esversion:6 */
"use strict";

let AllTiredOut = function () {
	print("exec AllTiredOut");

	// Properties.
	this.myName = "AllTiredOut";
	this.myTitle = "All Tired Out";

	// Nouns.
	let nounType1 = this.addNounType("Order");
	nounType1.addNoun("1st");
	nounType1.addNoun("2nd");
	nounType1.addNoun("3rd");
	nounType1.addNoun("4th");
	nounType1.addNoun("5th");

	let nounType2 = this.addNounType("Customer");
	nounType2.addNoun("Ethan");
	nounType2.addNoun("Grace");
	nounType2.addNoun("Jeff");
	nounType2.addNoun("Lisa");
	nounType2.addNoun("Marge");

	let nounType3 = this.addNounType("Wanted");
	nounType3.addNoun("alignment");
	nounType3.addNoun("chains");
	nounType3.addNoun("jack");
	nounType3.addNoun("shock absorbers", "Shocks");
	nounType3.addNoun("tires");

	// Links.
	let link1 = this.addLink("just ahead of", nounType1);
	link1.grid = [
		[0,1,0,0,0],
		[0,0,1,0,0],
		[0,0,0,1,0],
		[0,0,0,0,1],
		[0,0,0,0,0]
	];
	
	let link2 = this.addLink("three places ahead of", nounType1);
	link2.grid = [
		[0,0,0,1,0],
		[0,0,0,0,1],
		[0,0,0,0,0],
		[0,0,0,0,0],
		[0,0,0,0,0]
	];
	
	let link3 = this.addLink("next to", nounType1);
	link3.grid = [
		[0,1,0,0,0],
		[1,0,1,0,0],
		[0,1,0,1,0],
		[0,0,1,0,1],
		[0,0,0,1,0]
	];

	// Facts
	this.addFact("Ethan was not the 3rd person in line (clue 1).");
	this.addFact("Ethan did not buy the chains (clue 1).");
	this.addFact("The 3rd person in line did not buy the chains (clue 1).");
	this.addFact("The person who bought the jack was just ahead of Lisa (clue 2).");
	this.addFact("The 2nd person in line was not Ethan (clue 3).");
	this.addFact("The 2nd person in line was not Jeff (clue 3).");
	this.addFact("The person who bought the tires was three places ahead of the one who bought the alignment (clue 4).");
	this.addFact("Jeff was just ahead of the person who bought the shock absorbers (clue 6).");

	// Rules.
	this.addRule("Marge wasn't the second of the three women in line (clue 5).");
	this.addRule("Grace stood next to at least one man in line (clue 7).");

	print("done AllTiredOut");
};

In this puzzle module, you can see that I set the names for the verbs to be past tense.

	// Verbs.
	IsNot.name = "was not";
	Is.name = "was";
	

For this logic puzzle, clues 5 and 7 need to be expressed as rules. Here are the rules for this puzzle.

Rules
#XHitsName
10
20

Here is a brief description for each column.

  1. # is the one-based number of the rule.
  2. X tells you if the rule is enabled (checked) or disabled (unchecked).
  3. Hits is the number of times a rule is referenced.
  4. Name is the text of the rule.

The Rule Class

	
	

Adding Rules

Here are the rules that will satisfy clues 5 and 7.

	// Rules.
	let rule1 = this.addRule("5", "Marge wasn't the second of the three women in line.");
	rule1.f = SmartRule.getIsNotBetween(this, rule1, slots, marge, grace, lisa);

	let rule2 = this.addRule("7", "Grace stood next to at least one man in line.");
	rule2.f = SmartRule.getIsRelated(this, rule2, grace, nextTo, [ethan, jeff]);
	

Rules, along with links, require programming. The function f for each rule is provided by a method in the SmartRule static class. See the section on Smart Rules for more information. A rule usually does something based on the marks, and returns a status code. The status code is either negative for a violation, or zero for success. A rule may perform one or more of the following tasks.

Enforce Violations

A violation occurs when a mark contradicts the clues of a puzzle. A mark that violates the clues is called a contradiction. This should only happen when assumptions are made. A violation means the program should undo the last assumption, and make another one. If an assumption was not made, this is a fatal logic error, and the program will stop solving the puzzle. In the puzzle "All Tired Out", if a mark created the situation where Grace was first and a woman was second, this mark would contradict the clues. When a rule encounters this, it must inform the program of the violation.

Trigger Marks

A rule that examines the current mark to enter additional marks is called a trigger. The status of a trigger is the status of the submitted mark. If there are no problems with the mark, the status is zero. If there is a problem with the mark, the status is negative, and is returned immediately. If the mark entered by a trigger is rejected, this is the same as a rule violation. If the trigger was successful, the current rule can continue, and additional rules can be invoked.

For the logic puzzle "All Tired Out", a rule must look for a situation such as "If no man can be 2nd in line, then Grace cannot be 1st in line." When this situation is found, the rule enters 'X' for 1st and Grace. In general, rule violations should be handled first, followed by triggers.

Updating Placeholders

Some logic puzzles may not give you all of the values of the nouns. This means the values must be calculated by a rule. Nouns where the initial value is unknown are called placeholders. Usually these values are numeric, such as the number of people who attended a talk in "Astrophysics Conference", or the age of a salesperson in "Dandy Salespeople". Rules that update placeholders can be quite complex.

To summarize, rules are laws that are specific to a logic puzzle. The laws for solving a logic puzzle will be discussed in a future article.

Solution

This is the encoded solution to the logic puzzle, but is optional. If you know the solution, you can encode it here. See if you can "decode" this.

	// Solution.
	this.answer = [ [ 3, 4, 0, 2, 1 ], [ 3, 2, 0, 1, 4 ], [ 1, 2, 0, 3, 4 ], [ 2, 3, 1, 0, 4 ], [ 4, 1, 2, 3, 0 ] ];
	

Helper

The Helper static class defines global variables and helpful methods. This class is referenced by several of my classes. Though global variables and methods are discouraged, below are some of the globals defined in this module.

The Helper Class


	
	

The SmartLink static class defines methods that return a function for the links in a puzzle module.

The SmartLink Class

	
	

Smart Rules

The SmartRule static class defines methods that return a function for the rules in a puzzle module.

The SmartRule Class

	
	

Globals

Throughout this article I kept apologizing about my use of globals, but some globals are unavoidable. Here are some examples.

Note: The files head.php and WebWorker.js will be discussed in a future article.

Conclusion

I hope you enjoyed reading this article. My motivation for writing this article is that you will try to model a logic puzzle on your own. Then together we can find better ways to model and/or solve logic puzzles. Thank you.

About the Author

Michael Benson Michael Benson

My current position is zookeeper of the Mystery Master website at http://www.mysterymaster.com. My favorite languages are C#, Java, and JavaScript. When I'm not at my computer, I am travelling far more than I like to places far more exciting than I can handle.