Last Good Quote: Son's are the seasoning on our lives. - Someone on Facebook

Wednesday, July 14

5 Ways to be Lucky and Successful

Quite often I find myself talking about these rules during our weekly programming training classes (BDPA - HSCC).

Luck and success is all around you. But you have to be open to it. There is a mindset to being lucky and being successful. The following are some rules that help me to be lucky and successful:

Rule 1. Roll with the Changes
Change is going to come. We all make plans and life promptly crushes them. But when everything is falling apart, take the time to look around. Somewhere in the madness is an opportunity.

Grab it, catch it, put it in your back pocket, clean up your life, get back on track, then pull the opportunity out of your pocket and explore it.

Rule 2. Walk with open eyes
The simple act of noticing will bring luck to you. We don't always have to rush. Take the time to stroll and look around. You never know...
See that lady with the screaming four year old? She might have the job you've been looking for. Maybe you should have stopped and helped her.

Did you see that billboard about the master's degree? They might have a grant with your name on it.

See that flyer on the wall, don't you recognize that face? It's an old co-worker looking for a partner to start their next business.


3. Be Bold

Take risk, you don't have as much to lose as you think. Really has rejection ever killed anyone. Put yourself out there, so someone can pick you up. Keep in mind that if you let yourself, you will talk yourself out of everything that was meant for you.

4. Know when to quit
Because you are now taking risks and being bold, you will find a lot of things going on in your life. This is good, you're enjoying life. But at some point it will be too much. I know when I reach this point because I start to habitually avoid doing things. So, the time has come to trim to fat and let something go. Choose carefully, but admit and realize that something has to go.

On the other hand, be honest about your efforts are they profitable, monetarily or emotionally. If you ain't getting no satisfaction its a good sign that it's time to cut it loose. Life is to short to spend it on the un-enjoyable.

5. Make "me" time
Leave time to do nothing. I repeat nothing. Pretend that you're going to sit on your butt and do...wait for it...nothing. You'll find that this is the most enjoyable time you have. You will look forward to this time. You will crave it. The day just won't seem right without it. Why?

Because your nothing time turns into the time you do the thing you absolutely 100% enjoy doing above anything else. You have no obligations, you can do anything you want. You will naturally do what you like the most. Surprisingly you will find that this activity will change week to week. Your brain's appetite is large, once you allow it to join the buffet.

Now, don't go crazy, you can't have "me" time all of the time. Then the pleasure of it goes away, not to mention that the rest of your life will go sideways on you.

So there you have it. 5 simple rules that I live by. They help me be lucky and successful,. They can definitely help you.

What rules would you add?

Monday, July 12

Intro to Data Warehouses

This is a recent presentation I gave on data marts and data warehousing techniques. This only scratches the surface and there are a loot of places to dive deeper.


Date Warehousing

Monday, May 17

5 min Intro to PHP

If your interested in learning or playing with PHP. Here is a short introduction to get you started. I expect that you have some basic programming skills already. (or the will power to stay and play for a while)

Download It

If your using a window OS you will want an "XAMP" installation. It installs Apache, PHP and MySQL on windows. Most of them are simple: download, unzip and click the "start" executable. I like to use Uniform Server. I won't go into debugging apache in this article, but I will suggest that you shut off any program that uses the web server ports. (Visual Studio, IIS, Skype).

Alternatively you can play on any website you have, most will have php enabled.

Basic Things to know

  • Save your page with a .php extension
  • Surround your code with <?php ...code.... ?>
  • You can use <? ...code.... ?> but that is non-standards compliant
  • All statements in php must end with ";"
  • Variables start with $. IE: $username, $today, $yesterday, $i
  • Variables "live" to the end of page, but do not carry over into functions
  • Single line comments use //
  • Multi line comments use /* .... */
  • To add strings use "." (IE: $firstName . " " . $lastName)
  • To add numbers use "+" (IE: $age + 10)
  • Use print to print (IE: print "Hello " . $username)
  • Use echo to print (IE: echo "Hello " . $username)
If statements

if( boolean )
{
//...some code
}
elseif( boolean )
{
//...some code
}
else
{
//...other code
}

Loops

for($i=0;$i<10;$i++)
{
//...code
}

while( boolean )
{
// ...code
}

Variables, Sessions and Forms

Normal Variable: $username;
Session Variable: $_SESSION["username"]
Form Post Variable: $_POST["username"]
Form Get Variable: $_GET["username"]

Kill a session variable: $_SESSION["username"] = "";


Database

PHP normally uses mySQL, but each of the functions below have an equivalent function for most database systems.

$db_host = "localhost";
$db_user = "user";
$database = "dbname";
$db_passwd = "pass";
mysql_connect($db_host, $db_user, $db_passwd);
$q = mysql_query("select * from user");

while($row = mysql_fetch_object($q))
{
print $row->username;
}


Alternativly you can use mysql_fetch_row($q)...this will get an array of the field values and you can access them by $row[0], $row[1]....etc.

As with most high level languages, php has a number of functions available to it. You can search the very friendly documentation at www.php.net


Objects and Classes
Class DateUtils
{

function DateUtils()
{
//...constructor
}


function getToday($format)
{
return date($format);
}
}

And here is how to use the class

$util = new DateUtils();
print $utils->getToday();



What else would you like to know?

Monday, April 26

CSS: Tabbed Menu

Free Code. This comes directly from this site http://www.webcredible.co.uk/user-friendly-resources/css/css-round-corners.shtml



Creates rounded menus.

You will need the following four images:
  • - Right Tab
  • Left Tab

  • Right Tab Hover

  • Left Tab Hover



  • Code

    <html>

    <style>
    #navigation a
    {
    color: #000;
    background: #ffa20c url(left-tab.gif) left top no-repeat;
    text-decoration: none;
    padding-left: 10px
    }

    #navigation a span
    {
    background: url(right-tab.gif) right top no-repeat;
    padding-right: 10px
    }

    #navigation a, #navigation a span
    {
    display: block;
    float: left
    }

    /* Hide from IE5-Mac \*/
    #navigation a, #navigation a span
    {
    float: none
    }
    /* End hide */

    #navigation a:hover
    {
    color: #fff;
    background: #781351 url(left-tab-hover.gif) left top no-repeat;
    padding-left: 10px
    }

    #navigation a:hover span
    {
    background: url(right-tab-hover.gif) right top no-repeat;
    padding-right: 10px
    }

    #navigation ul
    {
    list-style: none;
    padding: 0;
    margin: 0
    }

    #navigation li
    {
    list-style: none;
    float: left;
    margin: 0;
    }
    </style>



    <body>
    <h1>Tabbed Menu Test</h1>

    <ul id="navigation">
    <li><a href="#"><span>Home</span></a></li>
    <li><a href="#"><span>Services</span></a></li>
    <li><a href="#"><span>Take a tour</span></a></li>
    <li><a href="#"><span>About us</span></a></li>
    <li><a href="#"><span>Contact us</span></a></li>
    </ul>

    </body>
    </html>

    Friday, April 23

    Javascript - 2D Map Library

    This article is a wrap up of a series of articles in which I walk through building a simple 2d top down map library. Below are the articles that build this library:
    For those of you that want the code, scroll past the explanations, it's at the bottom.

    Style.css.
    While testing and playing I usually will include the style in one page, for the ease of editing, but it's always a good idea to separate the style sheet from the main body of code. This allows an artist to come along and play with the look and feel of the site without screwing with your brilliantly created code.

    Map.js.
    All the general re-usable functions for mapping. If you ever finish coding a function and think, man I'll never have to touch this again, its so perfect and I'll use it all the time! First, slap yourself, cause we all know it's going to have a bug in it at some time. Second realize that the function in question, is prime material to go into a library of sorts. The functions in map.js are generic and can be kept from game to game as you build different things. At least that is my hope.

    TileClicked()
    I left tile clicked in the main body of the page because the actions you might want to take when a tile is clicked will change from game to game. Thus it is not library material.

    DestReached()
    This is a new function that was not discussed in other articles. Once a unit is done moving to it's destination of location, this function is called. I figured game builders might want to change this function depending on the game.

    Play()
    This is the heart of your game, if you want enemies to run around randomly, here is where you put that stuff. This function will call itself every few milliseconds, the more code in this function the slower your game is going to run.

    ObjectsCollided()
    This function is called when ever two units combine. The unit that moved last and did the collision is passed along with the id of each unit that is involved in the collision. You'll want to customize this function.


    The Body Tag
    The body tag calls the buildMap and addUnit function. I'd expect that you will want to change that.

    Div Elements
    There are two divs in the html one to hold the map and another to hold the score. You can move those around, but they must be somewhere in the page for the library to work.

    Map.js Function List

    BuildMap(width, height)
    Builds a map of width and height. It will also add walls to all edges of the map, so units don't wonder off it. Comment out the "addBorders()" line if you don't want this.

    AddBorders()
    Ummm, it adds borders...nuff said

    addWall(x,y)
    Turns tile x,y into a wall. Sets tile's flag = -1, sets the background color

    addUnit(unitID, x, y)
    Adds a unit with that ID to the map at tile location x, y. Multiple units can be added. If unitID is 1000 it is given the css class "unit". Otherwise the class is "enemy"

    setWalkableFlag(x, y, flag)
    Sets tile x, y "flag" variable to the flag passed.

    jumpUnit(unitID, tileDestX, tileDestY)
    Moves a unit directly to that tile, no animation at all...unit just jumps to location.

    move(unitID, dir)
    Move a unit one tile in the direction specified. Valid directions are N, E, S, W. This is an animated move (one pixel at a time). This uses the moveUnit() function.

    moveUnit(unitID, tileDestX, tileDestY)
    Moves a unit to the tile passed in. If at anytime the unit hits a none walkable tile, the unit will move back to last position. (no route finding). Calls DestReached() when completed.

    isWalkable(x,y)
    Returns "Y" or "N" if pixel x, y is walkable

    isWalkableTile(x,y)
    Returns "Y" or "N" if tile x, y is walkable

    getTop(obj)
    Return the top pixel (y) of the object. Could use some optimization

    getLeft(obj)
    Return the left pixel (x) of the object. Could use some optimization

    translateTileX(x), translateTileY(y)
    return the tileX that pixel x is located within

    getTileX(unitID), getTileY(unitID)
    return the tile x and tile y that the unit is located on

    Here be code!

    Style Sheet (style.css)


    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .unit {
    background:green;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .enemy {
    background:red;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .food {
    background:black;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }



    Map.js (the library)



    var originX = 0;
    var originY = 0;
    var tileSize = 16;
    var mapHeight = 0;
    var mapWidth =0;
    var score=0;
    var playSpeed = 1000;
    var numUnits = 0;
    var maxNumUnits = 40;


    function buildMap(width, height)
    {
    mapHeight = height;
    mapWidth = width;

    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("flag","0");
    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
    document.getElementById("divMap").appendChild(d);
    }

    addBorders();



    }

    function addBorders()
    {
    for(x=0;x<mapWidth;x++)
    {
    addWall(x, 0);
    addWall(x, mapHeight-1);
    }


    for(y=0;y<mapHeight;y++)
    {
    addWall(0, y);
    addWall(mapWidth-1,y);
    }
    }

    function addWall(x,y)
    {
    var tile = document.getElementById("tile_" + x + "_" + y)
    tile.setAttribute("flag","-1");
    tile.style.background = "#777"
    }


    function addUnit(unitID, x,y)
    {
    var d = document.createElement("DIV");
    var tile = document.getElementById("tile_" + x + "_" + y)
    if(unitID == 1000)
    {
    d.className="unit";
    }
    else
    {
    d.className="enemy";
    }
    d.setAttribute("xVel", 0);
    d.setAttribute("yVel", 0);
    d.setAttribute("ID","unit_" + unitID);
    d.style.top = tile.style.top;
    d.style.left = tile.style.left;
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("currTileX",x);
    d.setAttribute("currTileY",y);
    d.setAttribute("priorTileX",x);
    d.setAttribute("priorTileY",y);

    setWalkableFlag(x, y, unitID);

    document.getElementById("divMap").appendChild(d);
    }

    function setWalkableFlag(x, y, flag)
    {
    var tmpTile = document.getElementById("tile_" + x + "_" + y)
    tmpTile.setAttribute("flag", flag);

    }

    function jumpUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    unit.style.left = getLeft(tile);
    unit.style.top = getTop(tile);
    //
    //mark the current tile as UNwalkable
    //
    setWalkableFlag(unit.getAttribute("currTileX"), unit.getAttribute("currTileY"), "0");

    //
    //mark the old tile as WALKABLE
    //
    setWalkableFlag(unit.getAttribute("priorTileX"), unit.getAttribute("priorTileY"), "0");

    unit.setAttribute("currTileX",x);
    unit.setAttribute("currTileY",y);
    unit.setAttribute("priorTileX",x);
    unit.setAttribute("priorTileY",y);

    }



    function move(unitID, dir)
    {
    x = getTileX(unitID)
    y = getTileY(unitID)

    if(dir == "N")
    {
    y--;
    }

    if(dir == "E")
    {
    x++;
    }

    if(dir == "S")
    {
    y++;
    }

    if(dir == "W")
    {
    x--;
    }


    if(isWalkableTile(x, y) == "Y")
    {
    moveUnit(unitID, x, y);
    }


    }


    function moveUnit(unitID, tileDestX, tileDestY)
    {

    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    unit.setAttribute("priorTileX",getTileX(unitID));
    unit.setAttribute("priorTileY",getTileY(unitID));

    if(!tile)
    {
    alert("no tile found");
    return;
    }
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile);
    destY = getTop(tile);
    newX = x;
    newY = y;

    if(x > destX) newX--;
    if(x < destX) newX++;
    if(y > destY) newY--;
    if(y < destY) newY++;

    if(isWalkable(newX, newY) == "Y" && isWalkable(newX+tileSize-2, newY + tileSize-2) == "Y")
    {
    unit.style.left = newX;
    unit.style.top = newY;

    if(newX != destX || newY != destY)
    {
    setTimeout("moveUnit(" + unitID + "," + tileDestX +"," + tileDestY+")",5);
    }
    else
    {
    destReached(unitID, destX, destY);
    }
    }

    }

    function isWalkable(x,y)
    {
    var tile = document.getElementById("tile_" + translateTileX(x) + "_" + translateTileY(y))
    if(tile.getAttribute("flag") >= 0) return "Y";


    return "N";
    }


    function isWalkableTile(x,y)
    {
    var tile = document.getElementById("tile_" + x + "_" + y)
    if(tile.getAttribute("flag") >= 0) return "Y";


    return "N";
    }

    function getTop(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.top.replace("px",""));
    }

    return 0;
    }

    function getLeft(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.left.replace("px",""));
    }

    return 0;
    }


    function translateTileX(x)
    {
    return Math.floor(x/tileSize - originX);
    }

    function translateTileY(y)
    {
    return Math.floor(y/tileSize - originY);
    }


    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    return translateTileY(getTop(unit));
    }

    function getTileX(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    return translateTileY(getLeft(unit));
    }

    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    x = Math.floor(getLeft(unit)/tileSize - originX);
    y = Math.floor(getTop(unit)/tileSize - originY);

    return y;
    }




    Basic HTML page (index.html)


    <html>
    <link type="text/css" href="style.css"rel="stylesheet" />
    <script language=javascript src="map.js"></script>

    <script language=javascript>
    function tileClicked(x,y)
    {
    //called whenever a tile is clicked
    moveUnit(1000, x, y);
    }

    function destReached(unitID, x, y)
    {
    //called when ever the unit is done moving to a spot

    }


    function play()
    {
    //once called, this will loop forever, checking the game state and other things
    setTimeout("play()",playSpeed);
    }


    function objectsCollided(unit, unitID, enemyID)
    {
    //called whenever two objects collide

    }

    </script>

    <body onload="buildMap(10,10); addUnit(1000,4,4);">

    <div id="divMap"></div>

    <div id="score" style="font-family:verdana;size:14px; background:green;position:absolute;top:5px;left:350px; width:100px height:15px;border:5px solid green;">
    Score: 0
    </div>


    </body>
    </html>

    Thursday, April 22

    Stock Guessing - Programatically

    I've always been interested in stock analytics. Mostly because I have this un-reasonable dream that if I can program a stock "machine" which will trade stocks for me and make me richer than my wildest dreams.

    *Watches as you fall on the floor laughing*

    So now that you are done laughing....I started a blog about a year ago on creating such a program. If your interested it's here. I don't think I'm going to post to it anymore and it..."wonders"...a bit.

    Last night, I fired up the old program I wrote and tinkered with it for a little while. Tormenting myself with that dream I mentioned. To my surprise, I found something interesting...

    The program is setup to run once a day, pick a few stocks and then invest $1,000 into it. It then examines it's buys every day and sells the stock. There is a lot of other stuff going on, but that's the important part.

    If I had $10,000 to invest over the past 60 days and I had done ever trade and sell recommended by the program. I'd have gained $3,679.02.

    I'd have done 33 trades, assuming a $10 commission on each buy and sell, the commissions would cost me $660.

    The program churns through around 3,500 stocks (NYSE and NASDAQ) looking for good trades. It's a lucky day when it finds two picks in a given day.

    For those who are interesting..here are the last 10 or so picks it spit out.




    I'm at a loss on how to further test the program to ensure this is not some coincidence. Any suggestions?

    Monday, April 5

    Code: Simple 2D Javascript Map - Part 6

    This code will create a map grid, when you click the grid the green box will move to the tile you clicked. Red boxes will "fall" from the top down at random intervals. If the green box hits a red box, the red box disappears and starts to fall again. Think of it as a catching game.

    This was built to demonstrate one form of collision detection.In my mind there are two ways you can do collision detection. The first method is what most systems and algorithms perform:
    • Calculate the new position of the unit
    • Cycle through all other units to see if one of them occupies the new position
    • If no one is occupying then move the unit

    The second method is to make tiles as walkable as a unit steps on the tile. Then rather then cycling through all the units, you just check the tile the unit is moving to.

    • Calculate the new position of the unit
    • Check to see if that tile is occupied
    • If no one is occupying then move the unit

    The second method means that it "cost" more to move a unit. However it cost less than cycling through all units, every time there is any movement on the screen.

    How did I implement? First, I had to edit the buildMap() function so that each tile has a flag for who is standing on it. So I added the following line inside my buildMap() loops:

    d.setAttribute("flag","0");


    I then needed a function to set and unset this flag. If you un comment out a few lines, it will change the background of the tile, so that you can see which tiles get marked as unwalkable.

    function setWalkableFlag(x, y, flag)
    {
    var tmpTile = document.getElementById("tile_" + x + "_" + y)
    tmpTile.setAttribute("flag", flag);

    /*
    if(flag > 0)
    {
    tmpTile.style.background = "yellow";
    }
    else
    {
    tmpTile.style.background = "#BBB";
    }
    */
    }


    I also need the unit to "remember" what tile they are on (currTile) and what tile they were on (priorTile). To do this, I add the following code to the addUnit() function:


    d.setAttribute("currTileX",x);
    d.setAttribute("currTileY",y);
    d.setAttribute("priorTileX",x);
    d.setAttribute("priorTileY",y);
    setWalkableFlag(x, y, unitID);


    Again, I needed a few "wrapper" functions. One translates a pixel point X to a tile X. To keep things clean I changed the getTile function to use the new translate function. Again, there is plenty of room to optimize.


    function translateTileX(x)
    {
    return Math.floor(x/tileSize - originX);
    }

    function translateTileY(y)
    {
    return Math.floor(y/tileSize - originY);
    }


    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    return translateTileY(getTop(unit));
    }

    function getTileX(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    return translateTileY(getLeft(unit));
    }


    Now we get to the meat and potatoes of coding. The move unit function is where all the collision detection takes place. Reading through the logic of this function reads as follows:
    1. Grab the unit object and the destination tile object
    2. If the destination tile does not exist, stop
    3. Move 1 pixel closer to the destination
    4. Get the tile located at the center of the new position. (Center of the unit)
    5. If that tile is not flagged or if it is flagged as this unit
    6. Move the unit to the new location
    7. Set the priorTile and currentTile values
    8. Flag the new current tile as walkable
    9. Flag the old prior tile as unwalkable
    10. If we still have not found our destination, repeat in 5 milliseconds
    11. If there is a collision (back at #5), call the collide function



    function moveUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    unit.setAttribute("priorTileX",getTileX(unitID));
    unit.setAttribute("priorTileY",getTileY(unitID));

    if(!tile)
    {
    return;
    }
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile);
    destY = getTop(tile);
    newX = x;
    newY = y;

    if(x > destX) newX--;
    if(x < destX) newX++; if(y > destY) newY--;
    if(y < destY) newY++; checkX = newX + tileSize/2; checkY = newY + tileSize/2; var newTile = document.getElementById("tile_" + translateTileX(checkX) + "_" + translateTileY(checkY)) if(newTile.getAttribute("flag") == "0" || newTile.getAttribute("flag") == unitID) { unit.style.left = newX; unit.style.top = newY; unit.setAttribute("currTileX",getTileX(unitID)); unit.setAttribute("currTileY",getTileY(unitID)); if(unit.getAttribute("priorTileY") != unit.getAttribute("currTileY") || unit.getAttribute("priorTileX") != unit.getAttribute("currTileX") ) { // //mark the current tile as UNwalkable // setWalkableFlag(unit.getAttribute("currTileX"), unit.getAttribute("currTileY"), unitID); // //mark the old tile as WALKABLE // setWalkableFlag(unit.getAttribute("priorTileX"), unit.getAttribute("priorTileY"), "0"); } if(newX != destX || newY != destY) { setTimeout("moveUnit(" + unitID + "," + tileDestX +"," + tileDestY+")",5); } } else { // //we collided //snap back to last tile // objectsCollided(unit, unitID, newTile.getAttribute("flag")); } }


    In our game, if the user/player manages to collide with an enemy we will pop the enemy back up to the top for them to start over.



    function objectsCollided(unit, unitID, enemyID)
    {
    var tmpTile = document.getElementById("tile_" + unit.getAttribute("priorTileX") + "_" + unit.getAttribute("priorTileY"))
    unit.style.top = getTop(tmpTile);
    unit.style.left = getLeft(tmpTile);

    if(unitID == 1000)
    {
    x = Math.floor(Math.random()*9);
    y = 0;
    jumpUnit(enemyID, x, y);
    }

    if(enemyID == 1000)
    {
    x = Math.floor(Math.random()*9);
    y = 0;
    jumpUnit(unitID, x, y);
    }

    }



    One last change, I had to make was in the jumpUnit() function. I found that I needed to flag and unflag the tiles as the unit jumped.

    function jumpUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    unit.style.left = getLeft(tile);
    unit.style.top = getTop(tile);
    //
    //mark the current tile as UNwalkable
    //
    setWalkableFlag(unit.getAttribute("currTileX"), unit.getAttribute("currTileY"), "0");

    //
    //mark the old tile as WALKABLE
    //
    setWalkableFlag(unit.getAttribute("priorTileX"), unit.getAttribute("priorTileY"), "0");

    unit.setAttribute("currTileX",x);
    unit.setAttribute("currTileY",y);
    unit.setAttribute("priorTileX",x);
    unit.setAttribute("priorTileY",y);

    }


    And that's the entire change I made...the following is the entire code set:

    <html>
    <style>
    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .unit {
    background:green;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .enemy {
    background:red;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }
    </style>
    <script language=javascript>

    var originX = 0;
    var originY = 0;
    var tileSize = 32;
    var mapHeight = 0;
    var mapWidth =0;
    function buildMap(width, height)
    {
    mapHeight = height;
    mapWidth = width;

    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("flag","0");
    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
    document.getElementById("divMap").appendChild(d);
    }
    }

    function tileClicked(x,y)
    {
    //var tile = document.getElementById("tile_" + x + "_" + y)
    //tile.style.background = "yellow"

    moveUnit(1000, x, y);
    }

    function addUnit(unitID, x,y)
    {
    var d = document.createElement("DIV");
    var tile = document.getElementById("tile_" + x + "_" + y)
    if(unitID == 1000)
    {
    d.className="unit";
    }
    else
    {
    d.className="enemy";
    }
    d.setAttribute("xVel", 0);
    d.setAttribute("yVel", 0);
    d.setAttribute("ID","unit_" + unitID);
    d.style.top = tile.style.top;
    d.style.left = tile.style.left;
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("currTileX",x);
    d.setAttribute("currTileY",y);
    d.setAttribute("priorTileX",x);
    d.setAttribute("priorTileY",y);

    setWalkableFlag(x, y, unitID);

    document.getElementById("divMap").appendChild(d);
    }

    function setWalkableFlag(x, y, flag)
    {
    var tmpTile = document.getElementById("tile_" + x + "_" + y)
    tmpTile.setAttribute("flag", flag);

    /*
    if(flag > 0)
    {
    tmpTile.style.background = "yellow";
    }
    else
    {
    tmpTile.style.background = "#BBB";
    }
    */
    }

    function jumpUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    unit.style.left = getLeft(tile);
    unit.style.top = getTop(tile);
    //
    //mark the current tile as UNwalkable
    //
    setWalkableFlag(unit.getAttribute("currTileX"), unit.getAttribute("currTileY"), "0");

    //
    //mark the old tile as WALKABLE
    //
    setWalkableFlag(unit.getAttribute("priorTileX"), unit.getAttribute("priorTileY"), "0");

    unit.setAttribute("currTileX",x);
    unit.setAttribute("currTileY",y);
    unit.setAttribute("priorTileX",x);
    unit.setAttribute("priorTileY",y);

    }



    function moveUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    unit.setAttribute("priorTileX",getTileX(unitID));
    unit.setAttribute("priorTileY",getTileY(unitID));

    if(!tile)
    {
    return;
    }
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile);
    destY = getTop(tile);
    newX = x;
    newY = y;

    if(x > destX) newX--;
    if(x < destX) newX++;
    if(y > destY) newY--;
    if(y < destY) newY++;

    //if(newX < 0) newX = 0;
    //if(newX > mapWidth-1) newX = mapWidth-1;
    //if(newY < 0) newY = 0;
    //if(newY > mapHeight-1) newY = mapHeight-1;

    checkX = newX + tileSize/2;
    checkY = newY + tileSize/2;

    var newTile = document.getElementById("tile_" + translateTileX(checkX) + "_" + translateTileY(checkY))
    if(newTile.getAttribute("flag") == "0" || newTile.getAttribute("flag") == unitID)
    {
    unit.style.left = newX;
    unit.style.top = newY;

    unit.setAttribute("currTileX",getTileX(unitID));
    unit.setAttribute("currTileY",getTileY(unitID));

    if(unit.getAttribute("priorTileY") != unit.getAttribute("currTileY") || unit.getAttribute("priorTileX") != unit.getAttribute("currTileX") )
    {
    //
    //mark the current tile as UNwalkable
    //
    setWalkableFlag(unit.getAttribute("currTileX"), unit.getAttribute("currTileY"), unitID);

    //
    //mark the old tile as WALKABLE
    //
    setWalkableFlag(unit.getAttribute("priorTileX"), unit.getAttribute("priorTileY"), "0");
    }

    if(newX != destX || newY != destY)
    {
    setTimeout("moveUnit(" + unitID + "," + tileDestX +"," + tileDestY+")",5);
    }
    }
    else
    {
    //
    //we collided
    //snap back to last tile
    //
    objectsCollided(unit, unitID, newTile.getAttribute("flag"));


    }



    }


    function objectsCollided(unit, unitID, enemyID)
    {
    var tmpTile = document.getElementById("tile_" + unit.getAttribute("priorTileX") + "_" + unit.getAttribute("priorTileY"))
    unit.style.top = getTop(tmpTile);
    unit.style.left = getLeft(tmpTile);

    if(unitID == 1000)
    {
    x = Math.floor(Math.random()*9);
    y = 0;
    jumpUnit(enemyID, x, y);
    }

    if(enemyID == 1000)
    {
    x = Math.floor(Math.random()*9);
    y = 0;
    jumpUnit(unitID, x, y);
    }

    }


    function getTop(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.top.replace("px",""));
    }

    return 0;
    }

    function getLeft(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.left.replace("px",""));
    }

    return 0;
    }


    function translateTileX(x)
    {
    return Math.floor(x/tileSize - originX);
    }

    function translateTileY(y)
    {
    return Math.floor(y/tileSize - originY);
    }


    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    return translateTileY(getTop(unit));
    }

    function getTileX(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    return translateTileY(getLeft(unit));
    }

    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    x = Math.floor(getLeft(unit)/tileSize - originX);
    y = Math.floor(getTop(unit)/tileSize - originY);

    return y;
    }


    var playSpeed = 1000;
    var numUnits = 0;
    var maxNumUnits = 5;
    function play()
    {
    if(numUnits < maxNumUnits)
    {
    unitID = 1001+numUnits
    x = Math.floor(Math.random()*9);
    speed = Math.floor(Math.random()*3);
    addUnit(unitID,x,0);
    var unit = document.getElementById("unit_" + unitID);
    unit.setAttribute("xVel", 0);
    unit.setAttribute("yVel", speed+1);
    numUnits++;
    }

    for(i=0;i<numUnits;i++)
    {
    unitID = 1001+i;
    var unit = document.getElementById("unit_" + unitID);
    x = getTileX(unitID) + parseInt(unit.getAttribute("xVel"));
    y = getTileY(unitID) + parseInt(unit.getAttribute("yVel"));

    if(y >= mapHeight)
    {
    x = Math.floor(Math.random()*9);
    y=0;
    jumpUnit(unitID, x, y);
    }
    moveUnit(1001+i, x,y);
    }

    setTimeout("play()",playSpeed);
    }


    </script>
    <body onload="buildMap(10,10); addUnit(1000,4,4);play();">

    <div id="divMap"></div>

    </body>
    </html>


    Question: How would you go about adding a score indicator?

    Code: Simple 2D Javascript Map - Part 5

    This code will show how to create enemies and move them around the screen. It's going to randomly create 5 red boxes which will "fall" from the top of the grid to the bottom. The user can click a tile and the green box will move to the tile clicked. There is no collision detection...yet. I'm keeping this as simple as possible so in this example, "enemies" will drop from the top of the screen. Your job is to dodge them.

    The play function will get called every one second (playSpeed). It will add a new enemy until it has added 5 enemies. It chooses a random location at the top of the map, places the unit there.

    It will then pick a random speed and set the y velocity (think downward speed) equal to this random speed value.

    The second piece has the magic. It cycles through all enemy units and sets their next location to 3 spaces below where the unit currently is. Notice that this where our new functions get called.

    var playSpeed = 1000;
    var numUnits = 0;
    var maxNumUnits = 5;
    function play()
    {
    if(numUnits < unitid =" 1001+numUnits" x =" Math.floor(Math.random()*9);" speed =" Math.floor(Math.random()*3);" unit =" document.getElementById(" i="0;i= mapHeight)
    {
    x = Math.floor(Math.random()*9);
    y=0;
    jumpUnit(unitID, x, y);
    }
    moveUnit(1001+i, x,y);
    }

    setTimeout("play()",playSpeed);
    }


    Other changes



    Again, we have some plain Jane functions to get the tile location (x and y) of where our units is located. Make a note to yourself, there is plenty of room to optimize this code. It's dog slow.


    function getTileX(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    x = getLeft(unit)/tileSize - originX;
    y = getTop(unit)/tileSize - originY;

    return x;
    }

    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    x = getLeft(unit)/tileSize - originX;
    y = getTop(unit)/tileSize - originY;

    return y;
    }


    We also need to create a style for our enemy units. So I added this to the style.

    .enemy {
    background:red;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }


    Since we are moving random objects around, we need to start tracking the map height and width. So I changed the build map function.

    var mapHeight = 0;
    var mapWidth =0;
    function buildMap(width, height)
    {
    mapHeight = height;
    mapWidth = width;

    for(x=0;x<width;x++) y=0;y<height;y++);x++)


    Again, because we are moving enemies around randomly, need a bit of error catching added to the move function. If we try to move to a tile that does not exist, just stop moving.

    function moveUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile)
    ......


    Finally, I needed a function which will take an existing unit and "jump" them to a specific place on the map. This means they don't "move" one pixel at a time, but instead are immediately placed at that location:

    function jumpUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    unit.style.left = getLeft(tile);
    unit.style.top = getTop(tile);
    }


    Last but not least, we have to call our new play function from within the body tag.

    <body onload="buildMap(10,10); addUnit(1000,4,4); play()">





    Finally, the entire page looks like this:


    <html>
    <style>
    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .unit {
    background:green;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .enemy {
    background:red;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }
    </style>
    <script language=javascript>

    var originX = 0;
    var originY = 0;
    var tileSize = 32;
    var mapHeight = 0;
    var mapWidth =0;
    function buildMap(width, height)
    {
    mapHeight = height;
    mapWidth = width;

    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
    document.getElementById("divMap").appendChild(d);
    }
    }

    function tileClicked(x,y)
    {
    //var tile = document.getElementById("tile_" + x + "_" + y)
    //tile.style.background = "yellow"

    moveUnit(1000, x, y);
    }

    function addUnit(unitID, x,y)
    {
    var d = document.createElement("DIV");
    var tile = document.getElementById("tile_" + x + "_" + y)
    if(unitID == 1000)
    {
    d.className="unit";
    }
    else
    {
    d.className="enemy";
    }
    d.setAttribute("xVel", 0);
    d.setAttribute("yVel", 0);
    d.setAttribute("ID","unit_" + unitID);
    d.style.top = tile.style.top;
    d.style.left = tile.style.left;
    d.style.width = tileSize;
    d.style.height = tileSize;
    document.getElementById("divMap").appendChild(d);
    }


    function jumpUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    unit.style.left = getLeft(tile);
    unit.style.top = getTop(tile);
    }



    function moveUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    if(!tile)
    {
    return;
    }
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile);
    destY = getTop(tile);
    newX = x;
    newY = y;

    if(x > destX) newX--;
    if(x < destX) newX++;
    if(y > destY) newY--;
    if(y < destY) newY++;

    unit.style.left = newX;
    unit.style.top = newY;

    if(newX != destX || newY != destY)
    {
    setTimeout("moveUnit(" + unitID + "," + tileDestX +"," + tileDestY+")",5);
    }

    }


    function getTop(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.top.replace("px",""));
    }

    return 0;
    }

    function getLeft(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.left.replace("px",""));
    }

    return 0;
    }

    function getTileX(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    x = getLeft(unit)/tileSize - originX;
    y = getTop(unit)/tileSize - originY;

    return x;
    }

    function getTileY(unitID)
    {
    var unit = document.getElementById("unit_" + unitID);
    x = getLeft(unit)/tileSize - originX;
    y = getTop(unit)/tileSize - originY;

    return y;
    }


    var playSpeed = 1000;
    var numUnits = 0;
    var maxNumUnits = 5;
    function play()
    {
    if(numUnits < maxNumUnits)
    {
    unitID = 1001+numUnits
    x = Math.floor(Math.random()*9);
    speed = Math.floor(Math.random()*3);
    addUnit(unitID,x,0);
    var unit = document.getElementById("unit_" + unitID);
    unit.setAttribute("xVel", 0);
    unit.setAttribute("yVel", speed+1);
    numUnits++;
    }

    for(i=0;i<numUnits;i++)
    {
    unitID = 1001+i;
    var unit = document.getElementById("unit_" + unitID);
    x = getTileX(unitID) + parseInt(unit.getAttribute("xVel"));
    y = getTileY(unitID) + parseInt(unit.getAttribute("yVel"));

    if(y >= mapHeight)
    {
    x = Math.floor(Math.random()*9);
    y=0;
    jumpUnit(unitID, x, y);
    }
    moveUnit(1001+i, x,y);
    }

    setTimeout("play()",playSpeed);
    }


    </script>
    <body onload="buildMap(10,10); addUnit(1000,4,4); play()">

    <div id="divMap"></div>

    </body>
    </html>

    Friday, April 2

    Code: Simple 2D Javascript Map - Part 4

    What's that you say, you want to move the character around the screen.

    OK, ok, ok...here we go.

    Because we will need to get the exact position of the div objects, I use the following two functions (In all fairness there are better, faster, more accurate ways to get the position of a div tag, but this has worked for me and is simple enough for my simple mind to grasp.)

    You pass them an object and they give you back the position of the object.


    function getTop(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.top.replace("px",""));
    }

    return 0;
    }

    function getLeft(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.left.replace("px",""));
    }

    return 0;
    }



    A bit boring, nothing to fascinating in those functions. However here is where things get a bit more exciting. The following function will move any unit object to the desired Tile position.

    We pass in the unitID we want to move, and the TILE x and y we want to move to. The function will:
    • Get the unit's and the tile's position
    • Compare the two positions and move the unit closer to the tile by one pixel.
    • At the very end of the function, if we have not reached our destination, we call the same function in 5 milliseconds.



    function moveUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile);
    destY = getTop(tile);
    newX = x;
    newY = y;



    if(x > destX) newX--;
    if(x <> destY) newY--;
    if(y < left =" newX;" top =" newY;">

    Now that moves the unit around, but no one is actually calling this function so



    Full Code:

    <html>
    <style>
    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .unit {
    background:green;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }
    </style>
    <script language=javascript>

    var originX = 0;
    var originY = 0;
    var tileSize = 32;

    function buildMap(width, height)
    {
    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
    document.getElementById("divMap").appendChild(d);
    }
    }

    function tileClicked(x,y)
    {
    //var tile = document.getElementById("tile_" + x + "_" + y)
    //tile.style.background = "yellow"

    moveUnit(1000, x, y);
    }

    function addUnit(unitID, x,y)
    {
    var d = document.createElement("DIV");
    var tile = document.getElementById("tile_" + x + "_" + y)
    d.className="unit";
    d.setAttribute("ID","unit_" + unitID);
    d.style.top = tile.style.top;
    d.style.left = tile.style.left;
    d.style.width = tileSize;
    d.style.height = tileSize;
    document.getElementById("divMap").appendChild(d);
    }

    function moveUnit(unitID, tileDestX, tileDestY)
    {
    var unit = document.getElementById("unit_" + unitID);
    var tile = document.getElementById("tile_" + tileDestX + "_" + tileDestY)
    x = getLeft(unit);
    y = getTop(unit);
    destX = getLeft(tile);
    destY = getTop(tile);
    newX = x;
    newY = y;



    if(x > destX) newX--;
    if(x < destX) newX++;
    if(y > destY) newY--;
    if(y < destY) newY++;

    unit.style.left = newX;
    unit.style.top = newY;

    if(newX != destX || newY != destY)
    {
    setTimeout("moveUnit(" + unitID + "," + tileDestX +"," + tileDestY+")",5);
    }

    }


    function getTop(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.top.replace("px",""));
    }

    return 0;
    }

    function getLeft(obj)
    {
    if(obj)
    {
    return parseInt(obj.style.left.replace("px",""));
    }

    return 0;
    }


    </script>
    <body onload="buildMap(10,10); addUnit(1000,4,4)">

    <div id="divMap"></div>

    </body>
    </html>



    For giggles, I used this quick function to test play it. The function adds a number of units and randomly moves them around the screen. My desktop (Intel 2 Duo 2.2GH with 2GB Ram) can handle about 20 units in firefox, before it gets a bit odd.


    var playSpeed = 3000;
    var numUnits = 0;
    var maxNumUnits = 5;
    function play()
    {
    while(numUnits < i="0;i

    Code: Simple 2D Javascript Map - Part 3

    All right, let's put a character on the board!

    It's not difficult, first we create a function that will add the character for us. So we know that we will need to know the following:
    • A distinct ID for the unit (unitID)
    • The x and y of where to place the unit.


    Things to note:
    • We have to get the tile at X, Y.
    • We set the new div's tile to the Top and Left of the tile
    • We give the div tag a distinct "ID"
    • We give the new div tag a class of "unit"



    function addUnit(unitID, x,y)
    {
    var d = document.createElement("DIV");
    var tile = document.getElementById("tile_" + x + "_" + y)
    d.className="unit";
    d.setAttribute("ID","unit_" + unitID);
    d.style.top = tile.style.top;
    d.style.left = tile.style.left;
    d.style.width = tileSize;
    d.style.height = tileSize;
    document.getElementById("divMap").appendChild(d);
    }


    We've created a new css class "unit" so we need to add the following to our styles:


    .unit {
    background:green;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }


    Finally, we actually add the unit to the map when the body is loading.

    </script>
    <body onload="buildMap(10,10); addUnit(1000,4,4)">


    So the full page, looks like this...


    <html>
    <style>
    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }

    .unit {
    background:green;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }
    </style>
    <script language=javascript>

    var originX = 0;
    var originY = 0;
    var tileSize = 32;

    function buildMap(width, height)
    {
    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
    document.getElementById("divMap").appendChild(d);
    }
    }

    function tileClicked(x,y)
    {
    var tile = document.getElementById("tile_" + x + "_" + y)
    tile.style.background = "yellow"
    }

    function addUnit(unitID, x,y)
    {
    var d = document.createElement("DIV");
    var tile = document.getElementById("tile_" + x + "_" + y)
    d.className="unit";
    d.setAttribute("ID","unit_" + unitID);
    d.style.top = tile.style.top;
    d.style.left = tile.style.left;
    d.style.width = tileSize;
    d.style.height = tileSize;
    document.getElementById("divMap").appendChild(d);
    }

    </script>
    <body onload="buildMap(10,10); addUnit(1000,4,4)">

    <div id="divMap"></div>

    </body>
    </html>

    Code: Simple 2D Javascript Map - Part 2

    So, we've built a map in javascript and displayed it. Quite impressive...or maybe not.

    Now we want to make something happen when the user clicks on a tile. In this example, we will change the background. First we add a simple function which we will call whenever a tile is clicked.

    function tileClicked(x,y)
    {
    var tile = document.getElementById("tile_" + x + "_" + y)
    tile.style.background = "yellow"
    }


    Now, we will attach this function to all the tiles, so within our buildMap() function we add this line of code:

    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")


    That's it...now when you click a tile, it turns yellow. Why don't you try to change it so that the background has an image and the image changes as you click it?

    Full Code:


    <html>
    <style>
    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }
    </style>
    <script language=javascript>

    var originX = 0;
    var originY = 0;
    var tileSize = 32;

    function buildMap(width, height)
    {
    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    d.setAttribute("onclick","tileClicked(" + x + "," + y + ")")
    document.getElementById("divMap").appendChild(d);
    }
    }

    function tileClicked(x,y)
    {
    var tile = document.getElementById("tile_" + x + "_" + y)
    tile.style.background = "yellow"
    }


    </script>
    <body onload="buildMap(10,10)">

    <div id="divMap"></div>

    </body>
    </html>

    Monday, March 29

    Code: Simple 2D Javascript Map

    A friend of mine asked me what is the quickest, simplest way to create a 2d map. Think top down, grid like map.

    Here is 35 lines of javascript code that will do just that. Enjoy...


    <html>
    <style>
    .tile {
    background:#BBB;
    border:1px solid #999;
    position:absolute;
    top:0px;left:0px;
    width:5px;height:5px;
    overflow:hidden
    }
    </style>
    <script language=javascript>

    var originX = 0;
    var originY = 0;
    var tileSize = 32;

    function buildMap(width, height)
    {
    for(x=0;x<width;x++)
    for(y=0;y<height;y++)
    {
    var d = document.createElement("DIV");
    d.className="tile";
    d.setAttribute("ID","tile_" + x + "_" + y);
    d.style.top = originY + (y*tileSize);
    d.style.left = originX + (x*tileSize);
    d.style.width = tileSize;
    d.style.height = tileSize;
    document.getElementById("divMap").appendChild(d);
    }
    }


    </script>
    <body onload="buildMap(10,10)">

    <div id="divMap"></div>

    </body>
    </html>

    Friday, March 19

    Artificial Intelligence - Dreaming and Learning


    So last but most importantly, what does the Ai do when its sensors are detecting nothing?

    It has two options.

    Use Active/Aggressive sensors
    The first is to turn on some active sensors. We can assume that some sensor it has can “roam” or find new views of it’s environment. Let’s say we have a web parsing sensor, it reads HTML and brings back links. This sensor would not be active unless there is nothing else going on. The Ai could decide to activate it. There could be an array of these type sensors.

    Dream
    The second option that it has is to dream. When dreaming the Ai will:
    1. Search it’s Long term memory for a random data variable
    2. Use this data and feed it to a all Evaluators except for “the best”.
    3. Any evaluator that understood the data gets a chance to process it
    4. Any evaluator that understood the data would get passed additional data elements that are “similar” to the original”

    Doing this allows the Brain to evaluate if it’s truly has the best evaluator and sensor collaborated.

    Artificial Intelligence - Memory Management Example


    So, let’s image that its time to bring the Ai Online. We’ve built all the components and we’re ready to go.

    Here’s how the first 1,000 interactions with if the Ai was only attached to a “Textbox” sensor.

    Definitely take a look at the picture as it conveys a lot more but briefly:

    “Hi” comes through the textbox sensor, the Ai stumbles through Evaluators till it hits the Language one, which say “I understand this data”, the Ai says ok and lets the evaluator do its thing.

    The next time the textbox sensor fires off, the Ai gives it to the only Evaluator it knows Language, language handles things smoothly. This takes place 999 times.

    However on interaction 1,000 along comes a math request “3+9”. The language evaluator says…Ummm, no I can’t do anything with this. Again the Ai stumbles around until it hits the Math evaluator, who says, yeah…I can do something with it.

    Now when textbox fires off, the brain will randomly ask Math…Do you understand this stuff…If Math says yes, the Brain lets it handle the text. If the Math says “no”, brain turns to Language and passes stuff off.

    Summary
    This is not the most efficient way and if you notice it never actually pattern matches against what comes in on the textbox sensor.

    However, if a different sensor is setup for math functions this approach would lead to an efficient Ai. Math coming across a speech/text sensor would be like being asked does this spell BLUE. Humans can do it, its just…odd, thus we are more likely to answer incorrectly.

    Artificial Intelligence - Memory Management


    Let’s talk Memory,

    A Brain is going to have to recall things, store numbers, understand relationships and all sorts of stuff that deal with “recall”. This is where the memory module will come into play.

    Memory will consists of 4 pieces. All parts of the memory are available to the Brain and the Evaluators. Memory is not available to sensors and or motors.

    Short Term Memory
    Short term memory is for swift, context based data. It will consist of a Sensor ID, the data, a timestamp, and number of times accessed counter. At first this will be a straight copy of the sensor stack. However it will change over time. The number of items/rows in short term memory will be dictated by the amount of time it takes to search it and retrieve a specific piece of data. For example, if a query against short term memory takes longer than 100 milliseconds, the memory handler will move the 10 least accessed memories to long term memory.

    Long Term Memory
    Long term memory will look just like short term memory. Sensor ID, data and timestamp for when it came in. However Long term memory will have a different requirement, when searching long term memory takes more than 10,000 milliseconds, delete 10 of the least access memories.

    Note: This means that the Ai’s memory will only be as good as it’s architecture. The faster the searching the more memory that the Ai can have in it’s short term memory.

    Action Memory
    Action memory records the chain of events that occurred from the data coming in to the motor response. It’s purpose is to help the Ai choose which evaluator to send sensor data to.

    Every time the Brain sends data to an Evaluator it will check to see if the sensor and evaluator exists in the Action memory:
    If it does not the Brain will insert a new row
    If it does, the Brain will increment the number of attempts


    When an Evaluator receives data, during its processing it will:
    • Increment the understood column for all rows where the same sensor and evaluator are specified
    • If a row does not exist for the motor used, the evaluator will insert a new row with that motor in it.

    The success rate is simply a calculation of attempts/understood.

    Technical Note: The Action Memory table is not normalized (its flattened), this is intentional as the inserts will be few a frequent while the seeks or queries will be much greater. Thus this table needs to support quicker seeks. I will attempt to explain further later.
    Memory Data
    For storing variable or relationships or even more complex “thoughts” there is data memory. It’s just a key, data paring. Which seems too simple. However, I think it would be the responsibility of the Evaluator to make sense of the “dirty” nature of the memory. I must admit that there is most likely a better solution. However keep in mind that this memory bank has to server a variety of functions and Evaluators.

    Summary
    So all of this gives us the memory and storage of data. I would expect that storing this and accessing this would take up about 90% of the storage and processing capacity of our Ai brain.

    Artificial Intelligence - The Brain


    So this picture paints the whole picture, except for the most important part, which is in the next post. But let’s make sure we have it all covered.

    Here’s how it works

    • When the “brain” is ready to start a new tas
    • It will remove the top item from the sensor stack
    • It will determine the best sensor (this is the unexplained important part)
    • The Evaluator will send commands to the motor stack
    • It will also send memory objects and requests to Memory Handler

    This continues till there is nothing to sense. We will talk about what the brain does when there is no data on the sensor, but not right now.

    So, we have a little gray area, but the picture is getting clearer right?

    Let’s continue…

    Friday, March 12

    Artificial Intelligence - Evaluators



    So we discussed how the Ai will sense the world and we have discussed how it will interact with the world. How will it bridge the gap and make intelligent interactions based on what it has sensed?

    Before we can cover that you have to understand that the Ai Brain is actually made up of a number of parts. Some folks would consider each of these parts as Agents or AI themselves. I will leave that debate to others that are wiser than me.

    For my purposes I call them Evaluators. The Ai Brain consists of many of them. Each Evaluator is responsible for performing the following:

    • It takes data in, the data will always be in a rawest form
    • It attempts to understand this data
      • It will understand the data if it knows an motor action that can be given performed based on the input
      • Or it knows a memory object that needs to get created based on this action
      • Or it knows another evaluator that will understand this data
    • If it knows a motor action to perform based on the input, it will place the motor action on the motor stack
    • If it knows a memory object that needs to get created it will create the memory object*
    • If it knows another evaluator that will understand this data it will pass this “suggestion” along. **

    Note that a sensor stack item may be sent to multiple evaluators. Some evaluators will be better at some things then others and usually there is a “best” evaluator for each type of data on the sensor stack. We will talk about this more later.

    Example evaluators:
    • Language evaluator - responsible for holding conversations
    • Math Evaluator – responsible for performing calculations
    • Image Evaluator – responsible for identifying an image
    • Knowledge Evaluator – responsible for identifying relationships between objects

    I would imagine that at some point the Ai brain may create its own evaluators by combining or altering existing evaluators. We will talk on this further as well.

    * See memory creation post (tbd)
    ** See brain evaluator selection post (tbd)

    Artificial Intelligence - Motors


    So, we defined how the Ai will monitor and sense the world, how will it interact with it?

    This happens almost in the reverse of what happens with sensors.

    This time we start with the Motor Stack. The Ai places some data and a motor ID on the stack. As it “thinks” about additional task it keeps adding stuff to the stack.

    Motors will continually do the same thing.
    • Look on the stack for an action with their identifier.
    • Take the data and perform their action.
    • Repeat.
    What can a motor do? Anything. The simplest of motors may be responsible for taking text and putting it in a textbox for a user to see. A more complex motor may take an filename and display the contents of the file to a user. An even more complex motor may take a formula and graph it over time, sort of like your old T1 calculator.

    Wednesday, March 10

    Artificial Intelligence - Sensors


    Sensors

    So without senses we, humans, would not be able to function. Much less be considered “intelligent”.

    In the same fashion our Ai needs a way to sense changes in it’s environment.

    Think of a sensor, as a program that sits outside of the Ai brain. They monitor the environment and then pass data from those changes to the brain. So, the Ai will have a number of these sensors that will monitor the environment. T

    How it works:

    Step 1: Some change takes place within the environment of the Ai. For Example: A text box has “Hi” typed into it.

    Step 2: The sensor detects the change and gathers the data. For Example: “Hi” is saved as data

    Step 3: The sensor sends the data into the Ai. This is where the data crosses into the Ai’s brain.

    Step 4: The Ai, takes the raw data and the sensor ID and puts in on the bottom of the sensor stack. The sensor stack is a “list”/stack of data which the Ai has done nothing with yet.

    Some Points to Ponder:

    Sensor ID: Each sensor must have a unique identifier. This is essential for the Ai as it will learn to do different things with this sensor’s data. Now just because the sensor ID is constant does not mean the sensor has to watch the same point in the environment. In the above example, the sensor could go from textbox to textbox taking in the data.

    Sensor Stack: The sensor stack has all data points from the sensors which the Ai has not processed yet. This is critical as the Ai may let data stack up till it all make sense to it.

    The next post will discuss how the Ai will use the stack to decide on actions.

    Tuesday, March 9

    Artificial Intelligence - Take One

    The next few posts will be about a proposal for an Artificial Intelligence (Ai) system. It’s based on many things I’ve read around the internet as well as my own general ideas on how such a system needs to be made.

    My goal is to detail the system in a few articles and then attempt to build it. If given time, a thing I have precious little of these days.




    This shows the basic concept of the AI. As you can see it’s made up of 4 components. We will talk about each component in depth but from a high level you have:

    Sensors – Track and record changes in the environment. This would be the point at which data enters the Ai’s consciousness. An Example: A sensor may be responsible for tracking a single text box on a given web page.

    The Brain – This is where all the interesting stuff takes place, stay tuned. An Example: The brain may decide that in response to text entered it should display a picture.

    Motors – The brain will issue simple commands which the motors will execute on. Motors will perform actions on the environment. An Example: A motor may be responsible for displaying a picture to a webpage.

    Memory – Pieces of data and how the brain acted upon this data are stored in memory. Later on I will go further in depth with what will happen here. An Example: The word “Hi” might be stored in memory as well as the fact that the brain responded “Hi” back to it.

    Some things to keep in mind:
    This is an all-purpose form of intelligence, it’s not what many would consider a knowledge based system, or built to be superb in a specific category. In fact, I predict that this brain will not be superb at anything, but rather much like the majority of humans, it will be sufficient at being adequately productive.

    My goal is to build an Ai which can function in the same capacity as an average human. Think of the Turing test but including tasks rather than chat.

    My measure of success: If the program can return/perform in such a fashion that I can’t tell the difference between it and a human, I will have succeeded.

    Saturday, January 30

    iPad and the Future of Computing

    I believe that the Apple iPad represents the next step in the future of computing. A trite and often spoken phrase, but let me explain.

    Right now, laptops, phones and pdas are all viewed as tools. When I want to do something "online", I go looking for my computer. The future is when using a computer or getting on the internet becomes as frequent and often as watching TV, listening to the radio or opening my fridge. It needs to become a thing that is a given, always there, always available and everyone has one. The iPad changes this by bring a computer within price range of the all Americans. This is said with the assumption that after the first year of release the price will half, like most other technical products.

    The iPad also lowers the barrier to use. Humans have an odd trait that 80% of the time we will use the tool easiest available or soonest available rather than the best tool for the job. What ever tool has the least barrier to usage, becomes the one we use by choice.

    Today, when I want to get online I have to go "find" and "turn on" a computer. Even if that action is as simple as opening a device and logging in. The iPad takes another step toward changing this. Here is a device that is always on, doesn't have to be "opened" and is more "available" then other internet connected device. (Excluding smart phones). It's light enough and small enough that I can leave it anywhere, my bed, the bathroom, the kitchen, the car...it can just be with me as I roam my life.

    Removing the keyboard as an essential part of the computer experience is a huge step. Apple started it with the iPhone and if they can truly enable keyboard less computing, it will dynamically change the way we use computers.

    A note, I think netbooks set the stage for the iPad but I never felt that they were really the next step, they made computers cheaper but at the cost of quality. A good thing, but not necessarily an advancement in technology.

    Friday, January 29

    A Test in AI

    I've been doing a lot of reading up on AI and I got to thinking...

    Question: Is it possible to "grow" code that acts in an intelligent fashion?

    So, I thought I'd walk a little test and see "what happens". However I have a "goal" that at some point watching these bots interact together should be 'interesting'.

    I started with a map, a bot and a set of actions that the bot can perform.

    Map:
    • 20 x 20 square
    • Going off one side of the map brings the bot to the other side of the map. (much like pacman)
    Available Actions:
    • Move Up one square
    • Move Down
    • Move Left
    • Move Right
    • Look Left returns true if another bot is to the immediate left
    • Look Right
    • Look Up
    • Look Down
    • If(a, b, c)

    • a, b c - can be replaced by any other action except if
    • if a is true then b will be performed
    • if a is not true then c will be performed
    • Fight - Kills any bot within one square
    • Breed - See below
    An example bot:

    (This bot moves in a circle attempts to fight, then breed then it runs south)
    0: Move("E")
    1: Move("N")
    2: Move("S")
    3: Move("W")
    4: Fight()
    5: Breed()
    6: Move("S")
    7: Move("S")
    8: Move("S")
    9: Move("S")


    How they Grow
    Populate the map with 20 bots. Each of them selects 10 random actions from the list above. They then perform the actions in sequence. We are looking for some type of intelligent behavior from these bots.

    Breeding
    Breeding is the key to the bots learning something. Any time a bot attempts to breed the following sequence takes place:
    1. Look for another bot within 1 square
    2. 5 times, take a random code from this bot and replace it with a random code from the other bot.
    3. Find a bot that is dead and has a lower score than either parent bot.
    4. Give the new code to this bot.

    The primary bot, sometimes called father, is the bot that started looking to breed. (Hey, I'm a dude what can I say.)

    The secondary bot, sometimes called the mother, is the bot that was found close by. (Sorry ladies)

    Gross huh? or Cool, depends on how you look at it.

    The other form of breeding could take place after the bot is dead for a given number of turns. When this is the case, the bots code is randomly mixed with random code and the bot is set alive again.


    Scoring

    So, I needed a way to identify "good" behavior. I'm still on the fence if I can call it intelligent behavior. Either way, this is how I scored each bot.
    • +1 for Killing another bot (Survival of the fittest)
    • +1 for Breeding (father)
    • +1 for Help Breeding (mother)
    • +.25 for each tick that the bot stayed alive
    Keep in mind that during breeding a bot can only breed if there is a dead bot of a lesser score on the board. This keeps a "dumb" breeder from taking over the board.

    Other Notes

    Age - Keeps track of the number of times the bot's code was "messed with"

    Kids - Number of successful breeding attempts

    Parents - The last two parent bots of the current bot.

    Bots will block each others path, unless dead.

    When a bot is re-spawn or the child of another bot, they are respawned at a random location on the map.

    What's happening?
    OK, so I ran the simulation with the following parameters:
    • 1,000 iterations (steps)
    • 20 Bots
    • Respawn after 20 seconds
    • +1 for Killing another bot (Survival of the fittest)
    • +1 for Breeding (father)
    • +1 for Help Breeding (mother)
    • +.25 for each tick that the bot stayed alive
    These were the top 3:

    Bot 12: 5 iterations, 18 kills, 1 kid, score: 248

    This bot tried to fight, breed then moved east a little and tried over
    • 0: fight([BOT_ID])
    • 1: look('S', [BOT_ID])
    • 2: fight([BOT_ID])
    • 3: look('S', [BOT_ID])
    • 4: fight([BOT_ID])
    • 5: look('S', [BOT_ID])
    • 6: findMate([BOT_ID])
    • 7: move('E', [BOT_ID])
    • 8: move('E', [BOT_ID])
    • 9: fight([BOT_ID])
    Bot 19: 2 iterations, 10 kills, 4 kids, score: 260
    This bot moved diagonal across the board mating and fighting as it went. Died a lot while I was watching.
    • 0: look('E', [BOT_ID])
    • 1: fight([BOT_ID])
    • 2: move('N', [BOT_ID])
    • 3: findMate([BOT_ID])
    • 4: move('W', [BOT_ID])
    • 5: look('S', [BOT_ID])
    • 6: look('N', [BOT_ID])
    • 7: fight([BOT_ID])
    • 8: move('W', [BOT_ID])
    • 9: look('N', [BOT_ID])
    Note: During this round the bot with the most code changes (13) had the following line of code:
    5: ifOnly(look('S', [BOT_ID]),"move('S', [BOT_ID])","move('W', [BOT_ID])", [BOT_ID])
    6: fight([BOT_ID])

    Intelligence? He looks south if he sees something he moves south and then attacks. Otherwise he moves west.
    Bot 12: 5 iterations, 13 kills, 1 kid, score: 230Very similar to the first test. This bot tried to fight, breed then moved east a little and tried over
    • 0: fight([BOT_ID])
    • 1: findMate([BOT_ID])
    • 2: look('S', [BOT_ID])
    • 3: look('S', [BOT_ID])
    • 4: look('S', [BOT_ID])
    • 5: look('N', [BOT_ID])
    • 6: findMate([BOT_ID])
    • 7: look('N', [BOT_ID])
    • 8: move('E', [BOT_ID])
    • 9: findMate([BOT_ID])
    Bot 15: 4 iterations, 13 kills, 1 kid, score: 249
    Moved a little differently, but overall moved east...a pattern might be emerging.
    • 0: ifOnly(look('E', [BOT_ID]),"findMate([BOT_ID])","look('E', [BOT_ID])", [BOT_ID])
    • 1: move('E', [BOT_ID])
    • 2: fight([BOT_ID])
    • 5: fight([BOT_ID])
    • 6: move('W', [BOT_ID])
    • 7: move('E', [BOT_ID])
    Bot 7: 4 iterations, 27kills, 0 kid, score: 262
    Very efficent use of code, notice how he spawned to kids to compete with him. Thus giving him the high score.

    • 0: fight([BOT_ID])
    • 1: move('N', [BOT_ID])
    • 2: move('S', [BOT_ID])
    • 3: findMate([BOT_ID])
    • 4: ifOnly(move('S', [BOT_ID]),"fight([BOT_ID])","fight([BOT_ID])", [BOT_ID])
    • 5: ifOnly(move('S', [BOT_ID]),"move('E', [BOT_ID])","look('N', [BOT_ID])", [BOT_ID])
    • 6: move('N', [BOT_ID])
    • 7: fight([BOT_ID])
    • 8: look('N', [BOT_ID])
    • 9: move('W', [BOT_ID])

    Followers