Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Sunday, July 10, 2011

Generating Permutation with Javascript

I got hit by an interesting problem of “Zebra Puzzle” the other day. It is a well known logic puzzle believed to be first invented by Albert Einstein.

The question here is, how do we use our favorite programming language to solve this problem?

The first obstacle I found is that we need to generate all permutation of given list. Say if we have [1,2,3], we have a total of 3! = 6 which are [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1]. I couldn’t find simple Javascript code for this so I ended up writing one. Reinventing the wheel is fun, isn’t it? :))

Wikipedia suggests the following algorithm for generating all permutation systematically.

The following algorithm generates the next permutation lexicographically after a given permutation. It changes the given permutation in-place.

  1. Find the largest index k such that a[k] < a[k + 1]. If no such index exists, the permutation is the last permutation.
  2. Find the largest index l such that a[k] < a[l]. Since k + 1 is such an index, l is well defined and satisfies k < l.
  3. Swap a[k] with a[l].
  4. Reverse the sequence from a[k + 1] up to and including the final element a[n].

Here is my PermutationGenerator module implemented in Javascript.

/////////////////////////////////////////////
// Permutation Generator
// - generate all permutation of given string
// array
// - Natthawut Kulnirundorn <m3rlinez at email by google>
// http://www.solidskill.net 10 July 2011
/////////////////////////////////////////////

var PermutationGenerator = (function () {
var self = {};

// Get start sequence of given array
self.getStartSequence = function (list) {
return list.slice(0).sort();
};

// Get next sequence from given array
// Ref: http://en.wikipedia.org/wiki/Permutation#Systematic_generation_of_all_permutations
self.getNextSequence = function (list) {
// Make clone
var a = list.slice(0);

//The following algorithm generates the next permutation lexicographically after a given permutation. It changes the given permutation in-place.
// 1. Find the largest index k such that a[k] < a[k + 1]. If no such index exists, the permutation is the last permutation.
var k = -1;
for (var i = 0; i < a.length - 1; ++i) {
if (a[i] < a[i + 1]) { k = i; }
}
if (k == -1) return null; // means this is the last one

// 2. Find the largest index l such that a[k] < a[l]. Since k + 1 is such an index, l is well defined and satisfies k < l.
var l = -1;
for (var i = 0; i < a.length; ++i) {
if (a[k] < a[i]) { l = i };
}
if (l == -1) return null; // impossible

// 3. Swap a[k] with a[l].
var tmp = a[k]; a[k] = a[l]; a[l] = tmp;

// 4. Reverse the sequence from a[k + 1] up to and including the final element a[n].
var next = a.slice(0, k + 1).concat(a.slice(k + 1).reverse());

return next;
};

return self;
} ());





Test cases, also serve as a user guide :)



/////////////////////////////////////////////
// Test Cases
/////////////////////////////////////////////

var PermutationGeneratorTest = (function () {
var self = {};

function getStartSequence_Test1() {
var a = ['red', 'white', 'green', 'yellow', 'blue'];
var res = PermutationGenerator.getStartSequence(a);
log('input = ' + a);
log('output = ' + res);
}

function generateSequence(list) {
var current = PermutationGenerator.getStartSequence(list);
var count = 1;
log('start = ' + current);
while (true) {
current = PermutationGenerator.getNextSequence(current);
if (current == null) { break; }
log('next' + (++count) + ' = ' + current);
}
}

function getNextSequence_TestNormal() {
generateSequence(['English', 'Spanish', 'Japanese']);
}

function getNextSequence_TestEmpty() {
generateSequence([]);
}

function getNextSequence_TestRepeat() {
generateSequence(['gant', 'gant', 'korkore', 'jan']);
}

self.runTests = function () {
log("=== getStartSequence 1 ===");
getStartSequence_Test1();
log("=== getNextSequence Normal ===");
getNextSequence_TestNormal();
log("=== getNextSequence Empty ===");
getNextSequence_TestEmpty();
log("=== getNextSequence Repeat ===");
getNextSequence_TestRepeat();
};

return self;
} ());







I have put the working example on http://www.solidskill.net/ZebraPuzzle.htm. There are other parts of code that search through the solution space, setup the constraints for Zebra puzzle. But they are not discussed here.



There are some things to note about this implementation though. First, it is not very efficient. You can see in the getNextSequence(..) loop that there are loops used to search for k and l that satisfy the conditions.



Second, there could be problem with list of integers. The Array.sort() in Javascript sort using string interpretation by default. So [4, –1, 100, 500].sort() would return [-1, 100, 4, 500] instead of expected [-1, 4, 100, 500]. One must give Array.sort() function the comparer in order to properly sort list of integer. I design this module to work with list of strings initially.



Hope this helps those who are looking for permutation generation code.

Sunday, March 30, 2008

Prevent _IG_FetchContent from caching data

_IG_FetchContent is a Java Script function provided by Google for facilitating iGoogle's Gadget development. Its function is simply to fetch data from a HTTP location.
_IG_FetchContent('http://www.google.com/', function (responseText) {
// do something
}
);

However, the HTTP request is NOT directly send from client to web server of that location like most AJAX calls. Google itself cache the content too. Which cause problems for Gadgets which need dynamic data.

To prevent Google from caching the data, the third parameter which is refreshInterval has to be specified.
_IG_FetchContent('http://www.google.com/', function (responseText) {
// do something
}
,{ refreshInterval: 1 });
The '1' means that the content at this location is cached for one second. Which is a reasonable amount of time.

Tuesday, July 31, 2007

Simple Tic-Tac-Toe AI in JavaScript

Click here to see the Tic-Tac-Toe game in action! (open in new window)

Last year, I was challenged by the thread at Thaiadmin to implement a two-player OX (or Tic-Tac-Toe, XO, what you may call) game. I had done this kind of program in VB6 before, so I decided to implement the one-player JavaScript version.

The hardest part of of this project is debugging the JavaScript. I had to write the value of each variable and things done in each step to the screen (as you see in the bottom of the figure above) to diagnose the problems. I was so embarrassed that I did not know any of the great web developer's tools such as FireBug.

The ideas behind the decisions making part (or the AI) are to search every possible moves and take the best one. In each move, We assumed that the opponent chose his best move and we chose our best move. This method is "Minimax" method. As described in Wikipedia:

Minimax (sometimes minmax) is a method in decision theory for minimizing the maximum possible loss. Alternatively, it can be thought of as maximizing the minimum gain (maximin). It started from two player zero-sum game theory, covering both the cases where players take alternate moves and those where they make simultaneous moves. It has also been extended to more complex games and to general decision making in the presence of uncertainty.

The Minimax method can be applied to many other board games too. But in some complex games such as Chess, there was so many game states that you cannot search into them entirely (it would take many many years on an ordinary computer). So some heuristic must be used to approximately determine value of each state and the search must be limited at a fixed level (deeper level of search makes the AI cleverer).

In my case, there was not too many game states so I can search on them entirely. You can test my game here - http://m3rlinez.googlepages.com/oxai.htm. Choose View->Source to view the JavaScript source code.

Monday, December 18, 2006

How to consume UrbanDictionary service with Java Script

From my last entry, I had wrote that my instructor assign a project on mashing-up three web services together. Today I had to help my friend who need to consume a service from UrbanDictionary, a slang dictionary, using SOAP and JavaScript.

Actually there is an example of how to consume a service with JavaScript on their website too. However, it is still hard for a complete JavaScript newbies to understand and use.

So I had to code the skeleton part for my friend. Here is the code

function lookup(key, word) {
req = new XMLHttpRequest();
req.open("POST", "http://api.urbandictionary.com/soap", true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
var results = req.responseXML.getElementsByTagName("item");
var len = results.length;
var resp = "";
for(var i = 0 ; i < len ; i++)
{
var item = results[i];
for(var j = 0 ; j < item.childNodes.length ; j++)
{
var node = item.childNodes[j];
resp+="<br />";
if(node.nodeName == "word")
resp+= "คำว่า : " + node.firstChild.data;
else if(node.nodeName == "definition")
resp+= "คำจำกัดความ : " + node.firstChild.data;
else if(node.nodeName == "author")
resp += "ผู้แต่ง : " + node.firstChild.data;
else if(node.nodeName == "url")
resp += "URL : " + node.firstChild.data;


}
resp += "<hr />";
}
spanResp.innerHTML = resp;
}
}

var post = '<?xml version="1.0" encoding="UTF-8"?>' +
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
'<soapenv:Body>' +
'<ns1:lookup soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:UrbanSearch">' +
'<key xsi:type="xsd:string">' + escape(key) + '</key>' +
'<term xsi:type="xsd:string">' + escape(word) + '</term>' +
'</ns1:lookup>' +
'</soapenv:Body>' +
'</soapenv:Envelope>';

req.setRequestHeader('Content-Type', 'text/xml');
req.send(post);
}

function doLookUp()
{
var oTxt = document.getElementById('txtWord');
lookup('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', oTxt.value);
}

You have to replace "xxxxxxxxxxxxxx" with your UrbanDictionary passkey to get this code working.

One of the problem I encountered during coding this example is the "getElementsByTagName" method. I first use the "getElementByTagName" (no 's' in 'Element') method which does not exist. It takes me a while to figure this out.