I’ve searched long and hard for a dungeon card to go with the dwarven anvil/forge that appeared in White Dwarf 200. In the end I though what the hey I’ll just make one instead. Below is my effort.

As for rules well I haven’t given that much thought but here are a few ideas.

  • The anvil is magically and imbues weapons made using it with random properties.
  • The monsters that start in the room are all armed with magically imbued weapons, but the magic is weak and fades quickly (so you don’t get lots of magical equipment from it).
  • Perhaps all the monsters in this dungeon cause more damage than normal because of their magical weapons.
  • You could involve the lava but frankly if you’re an adventurer you’re survived this long you’re probably not going to stand in the hot stuff.
  • Perhaps one of the party has foolishly put on a magical bracelet that will kill him if he can’t take it off and the only way is the break it on the anvil.
  • Maybe the smith that ran the forge before the evil orcs arrived left behind his magic smithing hammer, or the anvil is magical and has to be carried out, the adventurer carrying the anvil moves slower, half speed perhaps or 1d3 spaces, (you have to get out the way you came in, or maybe there is an escape tunnel?)

Any comments or suggestions let me know.

High Resolution version of the Dwarven Forge/Anvil

High Resolution version of the Dwarven Forge/Anvil

When I started work on this card I decided it would be a good idea to put together a tool so people could make up their own cards. To that end I created the Dungeon Card Maker, just enter a few details and upload a layout and there you have it, just download the new card, print it own and stick it to some card (some cheap playing cards will do, right thickness and shape).

Filed under: Warhammer Quest — Tags: , , , , , , — admin @ 10:40 pm

I’ve always thought that captchas are a barrier to some internet users so I worked out an alternative method.

My method uses random field names and values.

The script generates a random MD5 hash from several blocks of random numbers. This hash is used create a field and variable name for your form and script. A second MD5 hash is generated from more random numbers and stored in the form field names and script variable. The generated variable and value can then be stored in the session (or database).

$var=substr( md5( rand(1000,4000).rand(3000,7500).rand(1000,9999) ),0, 15 );

${$var}=substr( md5( rand(1000,4000).rand(3000,7500).rand(1000,9999) ),0, 15 );

$_SESSION['varname']=$var;
$_SESSION['var']=${$var};
. . .

Once the form has been submitted a script has to confirm that the variables match. Once confirmed (or rejected) your script can proceed.

if ( isset( $_POST[ $_SESSION['varname'] ] ) && $_POST[ $_SESSION['varname'] ]!='' && $_POST[ $_SESSION['varname'] ] == $_SESSION['var'] )
{
.
.
.
}
Filed under: Programming — Tags: , , , — admin @ 9:46 pm

What happens if your page get found on Google but it should be inside an iframe? For me the answer was simple, detect if you’re inside an iframe and if not redirect to the destination you want.

To find out if you’re in an iframe you can get the number of frames from the parent window. If the number of frames if less than 0, you’re not in an iframe and you need to redirect. The same principle can be used to escape from an iframe.

if ( window.parent.frames.length>0 )  {}  // check how many frames, if none do nothing
else
{
  
  window.location="[new destination]";  // else change the current location 
  
}
Filed under: Programming — Tags: , — admin @ 8:49 pm

Having created a Javascript k-means function to process a single dimentional array I moved on to working out how to process a multi-dimentional array. The basic premise is the same, but you have to loop through the additional arrays and use a more advanced Euclidean n-space formula to calculate which cluster to allocate the point to.

Below is my k-means clustering learning machine algorithm.

function kmeans( arrayToProcess, centroids, clusters )
{	
	
	Groups=Array();
	iterations=0;
	
	function getType(o)
	{
		var _t;
		return ((_t = typeof(o)) == "object" ? o==null && "null" || Object.prototype.toString.call(o).slice(8,-1):_t).toLowerCase();
	}
	
	function deepCopy(target,source)
	{
		for(var p in source)
		{
			if(getType(source[p])=="array"||getType(source[p])=="object")
			{
				target[p]=getType(source[p])=="array"?[]:{};
				arguments.callee(target[p],source[p]);
			}
			else
			{
				target[p]=source[p];
			}
		}
	}						
	
	tempdistance=0;
	oldcentroids=[];
	deepCopy( oldcentroids, centroids );
	
	do
	{	

		for( reset=0; reset < clusters; reset++ )
		{

			Groups[reset]=Array();

		}
		
		changed=false;
		
		for( i=0; i < arrayToProcess.length; i++)
		{	  

			lowdistance=-1;
			lowclusters=0;	

			for( clustersloop=0; clustersloop < clusters; clustersloop++ )
			{	    

				dist=0;	  

				for( j=0;  j < arrayToProcess[i].length; j++ )
				{

					dist+=Math.pow( Math.abs( arrayToProcess[i][j] - centroids[clustersloop][j] ), 2 );

				}

				tempdistance=Math.sqrt( dist );

				if ( lowdistance==-1 )
				{

					lowdistance=tempdistance;
					lowclusters=clustersloop;

				}
				else if ( tempdistance <= lowdistance )
				{

					lowclusters=clustersloop;
					lowdistance=tempdistance;

				}

			}

			Groups[lowclusters].push( arrayToProcess[i].slice() );  

		}

		for( clustersloop=0; clustersloop < clusters; clustersloop++)
		{

			for( i=0, totalGroups=Groups[clustersloop].length; i < totalGroups; i++ )
			{

				for( j=0, totalGroupsSize=Groups[clustersloop][i].length; j < totalGroupsSize; j++ )
				{
				  
					centroids[clustersloop][j]+=Groups[clustersloop][i][j]

				}
					
			}

			for( i=0; i < centroids[clustersloop].length; i++ )
			{

				centroids[clustersloop][i]=( centroids[clustersloop][i]/Groups[clustersloop].length );

				if ( centroids[clustersloop][i]!=oldcentroids[clustersloop][i] )
				{

					changed=true;
					oldcentroids=[];
					deepCopy( oldcentroids, centroids );

				}

			}
		
		}
		
		iterations++;
		
	}
	while(changed==true);

	return Groups;
	
}

Download the script (right click and choose save target as)

Filed under: Mathematics,Programming — Tags: , , , , , , — admin @ 9:32 pm

Having seen a magnetic accelerator cannon advertised on think geek I started to wonder if I could make one. I have some magnets and ball bearings from toy so I thought I’d give it a go.

I started off with an aluminium ruler (it has a groove in it that runs the entire length) but you could use a piece of wood or plastic, the important part is the groove for the ball bearings to run down. Next I started to position the magnets. I wasn’t sure which configuration of magnets would work so I start with attractive poles.

This didn’t have the desired effect. So I tried opposing poles instead.

This returned much better results, but don’t take my word for it, experiment!!

Next I experimented with the distance between the magnets. I started off at 40mm, this distance was too great, the magnets used are not strong enough to capture the ball. Next I tried 35mm, at this distance the magnets are strong enough to capture the ball but too much kinetic energy was lost and did not trigger the next in the sequence. 30mm appears to be functional distance. Less than 30mm and the attraction is too great and the balls won’t stay in their starting positions.

You should keep in mnd that the distance is true for the size of the ball bearings i’m using and the strength of magnets, you may need to try different distances to get the desired results.

Filed under: Uncategorized — Tags: , , , , , , , — admin @ 2:46 pm

A client wanted to find out which links were the most popular without using Google Analytics (yeah….I know). My initial approach was to pass all links through a script and record the details and then perform a rediect, I’ll admit a bit of a quick fix.

Having had a bit of time to sit and think about this I decided to intercept the anchor tags perform the action and then continue. The benefits of this means you can easily apply the script to an existing site.

We start off by listening for clicks on anchor tags.

$(document).ready(function(){

  $("a").click(function(e){

  });

});

Next we want to stop the click from going to its destination.

$(document).ready(function(){

  $("a").click(function(e){

    // as the name would suggest, prevent the default action.
    e.preventDefault();

  });

});

Once the default action has been stopped we can instruct the browser to do what we want. If the script you’ll be calling is on the same server you can use AJAX otherwise you’ll have to be a bit more creative, we’ll move on to that in a bit.

$(document).ready(function(){

  $("a").click(function(e){

    // as the name would suggest, prevent the default action.
    e.preventDefault();

    // put the original URL into a variable
    dest=$(this).attr('href');

    // call your script, passing the variable (you'll probably need to include a random variable to ensure the URL called is unique), once the script returns success, call the callback function, in this instance, go to the original destination.
    $.get( "[your_script]", {[the_data_you_are_passing]}, function(){ window.location.href=dest } ); 

  });

});

What about is the script your calling isn’t on the same server, AJAX prohibits this so we need a way around it. My solution is that once the link has been clicked add a div tag to the site containing an image. The image can be held on another server. Now you’re thinking how can I pass variable to an image. My solution to this was simple, the image isn’t an image but script that returns an image, you can pass any variables you like to the script.

$(document).ready(function(){

  $("a").click(function(e){
 
    e.preventDefault();
 
    // make sure we have a unique url
    random=Math.random()*999999;

    dest=$(this).attr('href');

    // the variables you want to pass to the script
    variables='boo='+yaa;

    // allocate space for the image	
    var img = new Image();

   // append the div tag to the body	
   $("body").append('
'); // load the script into the image and append to the div tag, then redirect to the original destination $(img).load(function () { $('#trackingdiv').append(this); window.location.href=dest; }).error( function () {} ).attr('src', '[the_url_of_your_script]?rand='+random+'&'+variables); }); });
Filed under: Programming — Tags: , , — admin @ 6:54 pm

Javascript bubble sort

April 9, 2010

One of the first things I was taught was how to sort an array. Most modern languages have functions to do this for you but it’s still worth knowing the basics behind how. You would be surprised the number of times the same principles are used to perform other operations. Below is my Bubble sort written in Javascript.

A bubble sort works by accending the array and comparing the value at your current location “O(n)” with the value in the next location “O(n+1)”. If the value in the next location is less than the value of your current location “O(n+1) < O(n)” then the two values are swapped “O(n+1) = O(n) and visa versa”.

You can expand on the bubble sort further by running comparisons both accending and descending at the same time, this is known as a double bubble sort. The descending sort has to compare the current position with the one before “O(n-1) > O(n)”, if true the positions are swapped.

function bubbleSort( arrayToSort )
{

  do
  {

    changed=false;

    // loop through the array
    for( i=0;i<(arrayToSort.length-1);i++)
	{

	  // if the O(n) > O(n+1) move O(n) to O(n+1) and O(n+1) to O(n)
	  if ( arrayToSort[i] > arrayToSort[i+1] )
	  {

	    current=arrayToSort[i+1];	  

	    arrayToSort[i+1]=arrayToSort[i];
		arrayToSort[i]=current;

	    changed=true;

	  }

	}

  }
  while( changed==true );
  // break out of loop if no changes are made.

  return arrayToSort;

}

Click the buttons below to see the sort in progress



Filed under: Programming — Tags: , , — admin @ 7:29 pm

After reading an article by Howard Yeend (Pure Mango) I decided I would try to write a version of the basic learn algorithm.

Below is what I came up with.

function kmeans( arrayToProcess, Clusters )
{

  var Groups = new Array();
  var Centroids = new Array();
  var oldCentroids = new Array();
  var changed = false;

  // initialise group arrays
  for( initGroups=0; initGroups < Clusters; initGroups++ )
  {

    Groups[initGroups] = new Array();

  }  

  // pick initial centroids

  initialCentroids=Math.round( arrayToProcess.length/(Clusters+1) );  

  for( i=0; i < Clusters; i++ )
  {

    Centroids[i]=arrayToProcess[ (initialCentroids*(i+1)) ];

  }

  do
  {

    for( j=0; j < Clusters; j++ )
	{

	  Groups[j] = [];

	}

    changed=false;

	for( i=0; i < arrayToProcess.length; i++ )
	{

	  Distance=-1;
	  oldDistance=-1

 	  for( j=0; j < Clusters; j++ )
	  {

        distance = Math.abs( Centroids[j]-arrayToProcess[i] );	

		if ( oldDistance==-1 )
		{

		   oldDistance = distance;
		   newGroup = j;

		}
		else if ( distance <= oldDistance )
		{

		    newGroup=j;
			oldDistance = distance;

		}

	  }	

	  Groups[newGroup].push( arrayToProcess[i] );	  

	}

    oldCentroids=Centroids;

    for ( j=0; j < Clusters; j++ )
	{

      total=0;
	  newCentroid=0;

	  for( i=0; i < Groups[j].length; i++ )
	  {

	    total+=Groups[j][i];

	  } 

	  newCentroid=total/Groups[newGroup].length;  

	  Centroids[j]=newCentroid;

	}

    for( j=0; j < Clusters; j++ )
	{

	  if ( Centroids[j]!=oldCentroids[j] )
	  {

	    changed=true;

	  }

	}

  }
  while( changed==true );

  return Groups;

}

Download the script (right click and choose save target as)

I’ve expanded the script now to support multiple dimensions, you can see my script here.

Filed under: Mathematics,Programming — Tags: , , , , , — admin @ 8:35 pm

Rewriting the old school

August 9, 2009

snake

For the people that went to school with me (17 years ago) they may remember a game called Snake. The objective was simple move the snake around with the arrow keys and eat the apples (your snake got longer). The game was seen as a waste of school resources and banned…this didn’t stop me from writing a replacement. Having taken a trip down memory lane I thought it might be fun to rewrite the game in Flash (….I must be bored). Anyway here it is Snake for Flash

Stay tuned for my next experiment….a Flash game for the Wii

Filed under: Programming — Tags: , , , , , , , — admin @ 6:39 pm

About me

Jonathan Spicer

My CV

My curriculum vitae and a wealth of other facts about me.

Warhammer Quest tools

Flickering flame effect Flickering flame effect Flickering flame effect

Powered by WordPress