Showing posts with label Dozen Days of Tiles. Show all posts
Showing posts with label Dozen Days of Tiles. Show all posts
Sunday, December 4, 2011
DDTe4 Hours 16 to 18 Optimization
After creating the game, it became clear to me that there are more efficient ways of implementing the game other than using a grid like I did but as I have a short time-limit on the creation of the game, these faster implementations are out of the question. Still, there is some time left for doing an optimization pass. One problem that a lot of programmers have is the desire to prematurely optimize code. While the desire to write efficient code is a good desire, spending a large amount of time on a piece of code that has minimal impact on the performance of the final product is not a good way of spending your time. This is why tools like the profiler that is included in FireBug is such a great feature. The profiler tracks how many times and how much time is spent in every function that is executed while the profiler is running. This lets you know what parts of your program is taking the most time.
In the case of the life game, the code that spent the most time executing due to the huge number of times it was called was the getCell function. The problem with this function is that it needs to support calls outside of the proper bounds in order to properly support the borders. That said, the bounds should only be out by 1 in any given direction which means that if the grid size was slightly bigger and the border was computed along the edges every iteration then we could greatly simplify the getCell function.
To handle this change, the grid size was increased by 2 in both directions, with 1,1 being the top corner internally, though externally 0,0 will be the coordinate passed to get the data. This may not be intuitive, but the downside to optimization is that it can make the code a bit more complicated. The getCell function, on the other hand, becomes a very simple single line of code: return this.grid[y+1][x+1];
This means that if -1 is passed, it goes to the extra bottom or left row and passing the size of the grid as a coordinate will get the extra bottom or right row. To properly fill these rows, the setBorder function has been enhanced. It will fill the border rows and columns with the appropriate data. To make sure the data is correct, it is called at the start of every iteration. To finish up my first optimization pass, the countNeighbors and countCancer functions were quickly optimized by unrolling the loops and replacing the call to getCell with directly obtained cell data as a single line of code is easy to inline.
In JavaScript, there are no explicit types for variables. Variables get converted into whatever type is needed for the current operation. The problem is that this does not always work as planned leading to some real interesting bugs that would not appear in typed languages. In my case, I was using a value from a combo box. The value was a number, but because it is from an html control it's value is stored as a string. When it was passed to my function, 2 gets added to it. The problem is that JavaScript did not convert the string into a number then add two to it, but instead it converted the number into a string and appended it to the string. This resulted in "32" + 2 = "322" which is way off. I solved this bug by flooring the input value forcing it into a number, but finding the bug was a huge problem due to the fact that the code seemed correct (and in a typed language would have been correct). Thank you FireBug.
After fixing the bug and running the profiler again, the getCell, countNeighbors and countCancer drastically dropped in execution time. This optimization pass improved the speed of the simulation quite a bit. The game is quite fun to play with though I am sure there are many features people may want. I can't really think of any features that can be implemented in the few hours left within the allotted development time. For that reason, I am considering the game done. Still, if there is enough interest and suggestions, an enhanced version is something that I would certainly consider working on.
Sunday, November 27, 2011
DDTe4 Hours 13 to 15 - Cancer
This is the third (the first two parts were released last week) of a four part article covering the creation of my implementation of Conway's Game of Life. This week I am adding Cancer to the game.
I am not really sure why I decided to add cancer to the game of life. Perhaps it is my strange way of mourning over the loss of my mother or perhaps all the research into cancer that inspired me to create my own version of Conway's Game of Life was still in the back of my mind when I realized that I still had plenty of time to work on the project and add new features.
In the real world there are a number of causes for cancer but ultimately it comes down to either mutation or cell damage. I am limiting the simulation to only one of the two causes for cancer. For simulation purposes, mutation happens with newly formed cells. These are the ones that appear when an empty cell is surrounded by three (and only 3) living cells. Cell Damage is what happens to aging cells so is applied to any cell that is over 10 generations old. The mutation or damage is determined purely through randomness with an odds variable indicating how likely the cancer starting is. The odds value is a floating point number between 0 and 1 just like the numbers provided by the random number generator making the check simple as it is just seeing if the random number is less than the odds.
The problem with using random numbers in a simulation is that it makes it impossible to re-create the cancer. This problem can be solved by the fact that the random numbers are not random but are instead pseudo-random and the sequence of random numbers is repeatable if the original seed number is known. JavaScript doesn't let you seed the random number generator, so to do this you would have to find or write your own random number generator. For such a short time limit on this project, however, that is not realistic so cancer in this simulation will be unpredictable like it is in the real world.
This leads to the problem of how to deal with the growth of the cancer. There are three growth modes in the game. The mode you want real cancer growing in is benign which is simply no growth. Spreading mode is a slower growing form of cancer in which cells that are about to die but that are next to cancer will become cancerous. Growing mode is the evil mode where the cancer will grow into any dead cells next to it.
My initial tests had the simulation treating cancer cells as if they were dead cells. This was the ideal way from a coding perspective to implement the cancer as no drastic changes to the core simulation engine were needed. However, when I watched the cancer progress it just did not have the correct feel. It simply did not seem to grow properly. I altered the code to treat cancer as being alive and ran the simulation again. The results were almost exactly what I was looking for. I simply loved the results of both spreading modes.
From a performance perspective, there was a bit of a hit from the cancer, but not an overly dramatic hit until the cancer started to grow. The hit from the growing cancer is simply the drawing problem that was discussed in the previous article. Too many cells on the screen causes the rendering code to constantly change the drawing color and the HTML 5 canvas has an extremely inefficient way of setting colors.
Having the growth of cancer slow down the simulation is not that big of a concern, but with at least one more hour that I would like to put into this project spending some time speeding up the overall simulation would be a worthwhile endeavor.
I am not really sure why I decided to add cancer to the game of life. Perhaps it is my strange way of mourning over the loss of my mother or perhaps all the research into cancer that inspired me to create my own version of Conway's Game of Life was still in the back of my mind when I realized that I still had plenty of time to work on the project and add new features.
In the real world there are a number of causes for cancer but ultimately it comes down to either mutation or cell damage. I am limiting the simulation to only one of the two causes for cancer. For simulation purposes, mutation happens with newly formed cells. These are the ones that appear when an empty cell is surrounded by three (and only 3) living cells. Cell Damage is what happens to aging cells so is applied to any cell that is over 10 generations old. The mutation or damage is determined purely through randomness with an odds variable indicating how likely the cancer starting is. The odds value is a floating point number between 0 and 1 just like the numbers provided by the random number generator making the check simple as it is just seeing if the random number is less than the odds.
The problem with using random numbers in a simulation is that it makes it impossible to re-create the cancer. This problem can be solved by the fact that the random numbers are not random but are instead pseudo-random and the sequence of random numbers is repeatable if the original seed number is known. JavaScript doesn't let you seed the random number generator, so to do this you would have to find or write your own random number generator. For such a short time limit on this project, however, that is not realistic so cancer in this simulation will be unpredictable like it is in the real world.
This leads to the problem of how to deal with the growth of the cancer. There are three growth modes in the game. The mode you want real cancer growing in is benign which is simply no growth. Spreading mode is a slower growing form of cancer in which cells that are about to die but that are next to cancer will become cancerous. Growing mode is the evil mode where the cancer will grow into any dead cells next to it.
My initial tests had the simulation treating cancer cells as if they were dead cells. This was the ideal way from a coding perspective to implement the cancer as no drastic changes to the core simulation engine were needed. However, when I watched the cancer progress it just did not have the correct feel. It simply did not seem to grow properly. I altered the code to treat cancer as being alive and ran the simulation again. The results were almost exactly what I was looking for. I simply loved the results of both spreading modes.
From a performance perspective, there was a bit of a hit from the cancer, but not an overly dramatic hit until the cancer started to grow. The hit from the growing cancer is simply the drawing problem that was discussed in the previous article. Too many cells on the screen causes the rendering code to constantly change the drawing color and the HTML 5 canvas has an extremely inefficient way of setting colors.
Having the growth of cancer slow down the simulation is not that big of a concern, but with at least one more hour that I would like to put into this project spending some time speeding up the overall simulation would be a worthwhile endeavor.
Sunday, November 20, 2011
DDTe4 Hours 1 to 6 - The Basics of Life
When my mother went to the hospital and discovered that she had cancer, I spent some time researching the subject. Perhaps not as much time as I would have normally spent when researching a topic that strikes my interest, but enough to discover what a truly evil disease it is. Essentially, cancer is when a cell not only decides it does not want to die (I can’t blame it for that), but then starts reproducing replacing otherwise health cells. Thinking of the reproduction of cells got me thinking of Conway’s Game of Life. This is a zero player game as the game essentially follows a number of simple rules. The fun comes from setting up the world and watching it evolve.
There are a lot of features that I would like my implementation of life to support, and will implement as many features as I can within the 16-24 hours of development time allocated to this project, but the first step is to get the simulation running.
The first thing that has to be taken into account with life is the grid. I wanted to have a flexible size of grid but the key question of dealing with the grid is that in theory, the grid is suppose to be infinite. This is not necessarily realistic so the issue becomes how to deal with borders. I decided to support three different types of borders. Always dead, Always alive, and wrap-around.
The border issue makes the getCell function that I wrote for grabbing a cell a bit complicated as it has to see if the desired cell is within the bounds. If not, it then has to figure out how to deal with it, with wrap-around being a bit complex as it has to convert the passed coordinates into valid coordinates. All this condition testing has me concerned about performance, but I figure if it proves to be an issue I can do some optimization later.
Iterations of the game use the existing grid to spawn the new grid so the LifeGrid class actually creates two grids. The current grid and the old grid. Because the getCell function which I am using uses the current grid, the new grid is created in the old grid space and then the two grids are swapped. For each tile in the grid, the number of alive tiles surrounding it are counted. The rules of life are then applied and we know what the cell is going to be in the next iteration. The rules are fairly simple:
1 - If there are less than two neighbors, a living cell dies of loneliness.
2 - If there are more than three neighbors, a living cell dies of over-crowding.
3 - If there are exactly three cells, an empty (dead) cell becomes a living cell (newborn).
Because of some of the features that I know I will want in the future are dependant on knowing the age of the cell, the age is adjusted as well for each iteration. The LifeGridViewer right now simply draws the cells in red for dead and green for alive. This will change soon, however.
DDTe4 Hours 7 to 12 - Controlling Life
With the game functional, the next step is to implement controls that allow the user to modify the game. While the controls that I implemented could have been completed quicker, I found myself spending a lot longer testing the game then was absolutely necessary as there is just something fascinating about watching the simulation.
Before it is possible to watch a simulation, the simulation must first be animated. In the case of Life, this is simply a matter of displaying consecutive iterations automatically. In browsers, there are two ways of handling the timing. You can set an interval which calls a function after at least the specified time interval has expired. This happens repeatedly until the interval is stopped. For a bit more control, there are timeouts, which work just like intervals except they only call the function once.
To control the animation, a small set of controls are needed. For this game I opted to use html controls that appear below the game display. This is largely due to the fact that the controls are more for options and the real joy comes from watching the display. For the animation, a combo-box is used to allow for different playback speeds, the play button which will become a pause button when clicked, and a single step button for those people who want to analyze the progress of the simulation.
Once the animation was working and tested, adding more control over the colors became my next challenge. I wanted the ability to see the aging of the cells but also wanted the more traditional monochromatic style of display. To allow for these, I decided to use a color set approach where an array of colors are used to determine what is shown for different ages and states for the cells. By setting all the ages to the same color you can create a monochromatic style display. I created a large number of color sets so players should be able to find a color scheme they like.
With a more colorful display finished, controls over the size of the display and whether or not to show borders were added. As different sized grids were already implemented in the core game classes, this was very simple to implement. However, when the simulation was ran at a higher resolution, the speed slowdown was quite significant. Running the firebug profiling tool showed the problem was with the display code.
This had me confused as the display of the simulation is remarkably simple as all it is doing is drawing a large number of rectangles. These should be drawn exceedingly fast. As I looked over the code to see if I did anything stupid, it dawned on me that the color was changing for every rectangle. This shouldn't be a big issue, and with most graphics API's it would not be a problem. However, the Canvas API uses the DOM color model which is string based. This means that for every color change, the string gets converted into a number. The overhead for all this string processing is very high.
At this point, I was banging my head trying to figure out a way of speeding things up without resorting to the lower level canvas ImageData API. While this API gives you access to the raw color data, it would be a lot of work to implement. Then it dawned on me that most frames consist mostly of long-dead cells. Instead of drawing every cell, I really only need to draw the living and recently killed cells. By blanking the display and drawing only the living cells, the speed of the simulation increased dramatically.
The final feature that I knew I must have before I could consider this project releasable would be the ability to manually add cells to the display. This was handled by simply converting the mouse click to a tile coordinate and setting that tile to alive.
With this done, the project is in a releasable state, but I still have at least four hours to invest into this project so the question is what to work on next? More optimization would be nice to speed things up a bit more, but for some reason the idea of adding cancer came to my mind.
Sunday, November 13, 2011
DDTe3 Final Thoughts
This was a really interesting episode to create, as the huge number of articles covering it’s creation clearly shows. Game-play wise, however, I am not as sure. While the individual games are enjoyable for a short-term play, I am not entirely sure there is a long-term play value to the games. To solve this problem, I plan on having a future puzzle gallery project which will let players select the picture to play with whichever game they are interested in. I would also like to add new features such as options to control how the grid is shown, and to give randomly generated images. Additional features such as game timers and move counters may also be added. I am really sure how long it will be before this enhanced version will be created (nor do I know how many releases it will take to get to the final version of the puzzle gallery game) but it is certainly something I will be working on.
Will I do another challenge like this again in the future? As the amount of time I have to devote to the Blazing Games site is being reduced in favour of larger scale games, such a challenge does make some sense. I think, however, if I do such a challenge again it would probably be done slightly different. What I think I would do is create a single game in a 16-24 hour period with as many bells and whistles as can be created within the time limit and then the following episode would add as many variations of the base game as can be created in a 24 hour development period. This would give me both the quality that I would like while also giving me a large number of releases. I would probably switch to a weekly release schedule while all the sub-episodes were released. If there were eight variants like there was for this release it would still result in a couple months for only a 24 hour work period which could be handy if a bigger project is heading into some type of crunch time.
Eight games in 24 hours is still quite impressive. A large reason that such a feat is possible has to do with how much software development tools and environments have improved. I suppose I would be able to develop a couple of games in under 24 hours using basic back when the Commodore 64 was my computer. Assembly language I would be lucky to finish a single game and then only if I was able to rely on code from earlier assembly language projects.
When you get right down to it, JavaScript is the basic of our time, with C++ being the modern equivalent to assembly language. While it is possible to still write in assembly language, the time requirements of writing in assembly language are simply not worth the speed and size benefits that it brings. I still think that it is worth learning assembly language if only to understand what the compiler is actually doing.
Sunday, November 6, 2011
DDTe3 Hours 22 to 23 - A Distorted Game
Sorry for missing last week, but I was condo-sitting for my aunt. This is a continuation of my series of articles about the creation of the multi-game Dozen Days of Tiles episode 3 where I tried to create as many games as I could in 24 hours. This part concludes the development of the final (and my personal favorite) game in the episode.
In earlier games created this episode, the game data (model) was separate from the display (view) with the interaction between the two handled by the game (controller). Having three separate classes allowed for a lot more reuse as the model class was used in all seven of the other games and there were only two view classes shared by the seven games. As time is running out and there will not be any other games based of of the radically different model that this game uses for arranging the tiles, I am combining the controller and the model into a single game class. The entire game code is so small that it really doesn’t matter and if fact creating multiple classes to do things properly is overkill. In fact, despite trying to cut back on the amount of code I post and instead try to focus more on the much more important theory, I am going to post all of the code in the game class.
The constructor stores the image and splitting information. It then sets up the root tile, which is the size of the whole puzzle and contains the whole image. This tile is what gets broken apart to form the final puzzle. An array to hold all the puzzle pieces is created and we call the routine to scramble the board. Since this routine is only ever called once, it could have been placed in the constructor but to make the code a bit more readable (as if such a small program has that problem) it is in a separate function.
PuzzleGallery.DistortionPuzzleGame = function(id, w, h, img, clip, splits)
{
this.supr = new BGLayers.Layer(id, clip.width, clip.height);
BGLayers.inheritProperties(this, this.supr);
this.split = splits;
this.image = img;
this.clip = clip;
this.rootTile = new PuzzleGallery.DistortionTile(id, img, clip, clip.width, clip.height, 10);
this.rootTile.setTileListener(this);
this.tileList = new Array();
this.tileList.push(this.rootTile);
this.selectedTile = null;
this.addChild(this.rootTile, new BGLayers.Rectangle(0,0,w,h));
this.scramble();
}
The heart of the game is handling clicking on tiles. This is very simple as all we do is see if a tile has been clicked on already. If it has not been, the tile gets marked as the selected tile and it’s highlight is turned on. If there is a selected tile then we swap the clipping region of both the tiles and un-highlight the selected tile then we clear the selected tile variable so a new selection can be made. That is all the logic needed to handle the game.
PuzzleGallery.DistortionPuzzleGame.prototype.onTileClick = function(t)
{
if (this.selectedTile == null) {
this.selectedTile = t;
this.selectedTile.setHighlighted(true);
} else {
t.swapClips(this.selectedTile);
this.selectedTile.setHighlighted(false);
this.selectedTile = null;
}
this.addDirty(null);
}
The heart of the game is the scrambling as it also breaks apart the picture. The number of splits passed to the constructor is what controls the number of split passes that the scrambler goes through. In theory, each split doubles the number of tiles in the game, but as there are occasionally tiles that are too small to split further, this is not always the case. One the clips that make up the final puzzle are ready, we loop through the list of pieces and let it know that the true clipping region is it’s current clipping region. Finally, we swap the pieces around. The number of swaps is the split size times the number of tiles to make sure that the puzzle is not straightforward swapping of tiles.
PuzzleGallery.DistortionPuzzleGame.prototype.scramble = function()
{
// breaking up picture
var child, cntr, listLen, cntrList;// = this.rootTile.split();
for (cntr = 0; cntr < this.split; ++cntr) {
listLen = this.tileList.length;
for (cntrList = 0; cntrList < listLen; ++cntrList) {
child = this.tileList[cntrList].split();
if (child != null)
this.tileList.push(child);
}
}
// marking correct clips
listLen = this.tileList.length;
for (cntrList = 0; cntrList < listLen; ++cntrList) {
this.tileList[cntrList].setTrueClip();
}
// scrambling puzzle
var swap;
for (cntr = 0; cntr < this.split; ++cntr) {
for (cntrList = 0; cntrList < listLen; ++cntrList) {
swap = Math.floor(Math.random() * listLen)
this.tileList[cntrList].swapClips(this.tileList[swap]);
}
}
}
That is the entire game and with about half an hour left is where we end this episode. But that may not be the end of the puzzle gallery. Next week I will have one final article on the topic of this game where I discuss possible future plans.
Sunday, October 23, 2011
DDTe3 Hours 19 to 21 A distorted Tile
The distortion puzzle is a game I had created before but have never released on Blazing Games. The idea is that the game is made up of a broken up images where the boxes that make up the image are varying sizes. The part of the image that is shown in each tile is scaled to the size of the tile making for a distorted version of the image. While the game is essentially the original picture puzzle game, the effect of the distortion makes the game much more challenging than a regular picture puzzle game.
The key problem with this game is that the game board is no longer a grid. This means that the tiles will need to be handled differently then the other grid-based games. Likewise, the display is not as simple as the image being displayed in the tile may be distorted. This means that it is a good idea to create a special tile for dealing with the tiles in the distortion puzzle.
Having a hex tile that handled borders was much more convenient then the approach used with the grid games, so I decided to take this approach with the distortionTile. As the rendering and management of the tile is pretty much the same as the hex tile except for the shape I will not go into much detail about that aspect of this class. The focus instead will be on the two key aspects of this class. These are the clip and splitting.
The clip is kind of complex as there are two clips that make up this tile. The first clip is the true clip which is set once all the splitting has been done. If the current clip is the same as the true clip than the tile is in the correct place. The current clip is what gets swapped and is used to determine what is drawn.
Splitting tiles is a special situation as it is what is used to generate the puzzle for the game. To prevent too small of tiles, there are restrictions on how big a tile has to be in order to be split. The split is always done along the longest side, though in hind-site this is probably unnecessary and even more distorted puzzles could be generated by removing this restriction. The split line is then randomly generated but will always be somewhere within the 60% of the middle of the side. The rational for doing this is to prevent super-slim slices within the puzzle as those are hard for the player to deal with both in figuring out what is in the slice and in clicking on the slice.
PuzzleGallery.DistortionTile.prototype.split = function()
{
var child;
var temp;
var tempRect = new BGLayers.Rectangle(this._logicalPosition);
var childRect = new BGLayers.Rectangle(this._logicalPosition);
var childClip = new BGLayers.Rectangle(this._clip);
if (Math.max(this._clip.width, this._clip.height) < (this.thickness*5))
return null;
temp = Math.random() * .6 + .2;
if (this._clip.width >= this._clip.height) {
this._clip.width = Math.floor(temp * this._clip.width);
tempRect.width = Math.floor(temp * tempRect.width);
childRect.x += tempRect.width;
++childRect.x;
childRect.width -= tempRect.width;
childClip.x += this._clip.width;
childClip.width -= this._clip.width;
} else {
this._clip.height = Math.floor(temp * this._clip.height);
tempRect.height = Math.floor(temp * tempRect.height);
childRect.y += tempRect.height;
++childRect.y;
childRect.height -= tempRect.height;
childClip.y += this._clip.height;
childClip.height -= this._clip.height;
}
this.adjustPosition(tempRect);
child = new PuzzleGallery.DistortionTile(this.id, this._image, childClip, childRect.width, childRect.height, this.thickness);
child.setTileListener(this.listener);
this.parent.addChild(child, childRect);
return child;
}
This leaves us with two things that need to be done to have a full game. We need the actual game manager and we need a class to display the puzzle. Both those will be discussed next time.
The key problem with this game is that the game board is no longer a grid. This means that the tiles will need to be handled differently then the other grid-based games. Likewise, the display is not as simple as the image being displayed in the tile may be distorted. This means that it is a good idea to create a special tile for dealing with the tiles in the distortion puzzle.
Having a hex tile that handled borders was much more convenient then the approach used with the grid games, so I decided to take this approach with the distortionTile. As the rendering and management of the tile is pretty much the same as the hex tile except for the shape I will not go into much detail about that aspect of this class. The focus instead will be on the two key aspects of this class. These are the clip and splitting.
The clip is kind of complex as there are two clips that make up this tile. The first clip is the true clip which is set once all the splitting has been done. If the current clip is the same as the true clip than the tile is in the correct place. The current clip is what gets swapped and is used to determine what is drawn.
Splitting tiles is a special situation as it is what is used to generate the puzzle for the game. To prevent too small of tiles, there are restrictions on how big a tile has to be in order to be split. The split is always done along the longest side, though in hind-site this is probably unnecessary and even more distorted puzzles could be generated by removing this restriction. The split line is then randomly generated but will always be somewhere within the 60% of the middle of the side. The rational for doing this is to prevent super-slim slices within the puzzle as those are hard for the player to deal with both in figuring out what is in the slice and in clicking on the slice.
PuzzleGallery.DistortionTile.prototype.split = function()
{
var child;
var temp;
var tempRect = new BGLayers.Rectangle(this._logicalPosition);
var childRect = new BGLayers.Rectangle(this._logicalPosition);
var childClip = new BGLayers.Rectangle(this._clip);
if (Math.max(this._clip.width, this._clip.height) < (this.thickness*5))
return null;
temp = Math.random() * .6 + .2;
if (this._clip.width >= this._clip.height) {
this._clip.width = Math.floor(temp * this._clip.width);
tempRect.width = Math.floor(temp * tempRect.width);
childRect.x += tempRect.width;
++childRect.x;
childRect.width -= tempRect.width;
childClip.x += this._clip.width;
childClip.width -= this._clip.width;
} else {
this._clip.height = Math.floor(temp * this._clip.height);
tempRect.height = Math.floor(temp * tempRect.height);
childRect.y += tempRect.height;
++childRect.y;
childRect.height -= tempRect.height;
childClip.y += this._clip.height;
childClip.height -= this._clip.height;
}
this.adjustPosition(tempRect);
child = new PuzzleGallery.DistortionTile(this.id, this._image, childClip, childRect.width, childRect.height, this.thickness);
child.setTileListener(this.listener);
this.parent.addChild(child, childRect);
return child;
}
This leaves us with two things that need to be done to have a full game. We need the actual game manager and we need a class to display the puzzle. Both those will be discussed next time.
Sunday, October 16, 2011
DDTe3 Hour 18 - Hex Sliding Puzzle
I have decided to switch back to posting my entries here on Sunday evenings. I was actually thinking of dropping this blog and just posting to Google+, but figured that this has a bit more permanence then G+ posts do. This article continues my series on Dozen Days of Tiles episode 3, where I created 8 games in 24 hours. This entry covers the creation of my hex sliding puzzle.
Originally, I was not thinking about doing a hex-based sliding puzzle as realistically you can not slide hexes as they form a really nicely locked pattern. Puzzle games do not necessarily have to reflect reality, so after thinking about it for a while, I figured that this would be an interesting game to develop. After playing the finished version of the game, I am quite glad that I did as it is actually a really fun variation of the sliding puzzle.
The hard part to creating this game is in dealing with the sliding. A hex grid can be thought of as a three-axis system, but that is only partially true. While the Z axis does exist, it is dependent on the X axis and the Y axis. This means that manipulating the Z axis means that you are actually changing the X and Y axis. This got me thinking that if I just move along both the X and Y axis at the same time, things should work. Here is the new version of the sliding code.
PuzzleGallery.HexSlidingPuzzleGame.prototype.moveSlider = function(p)
{
var tempX,tempY;
var hp = new PuzzleGallery.HexPoint();
hp.setPointFromGrid(p.x, p.y);
while ((this.slider.x != hp.x) || (this.slider.y != hp.y)) {
tempX = this.slider.getGridX();
tempY = this.slider.getGridY();
if (this.slider.x > hp.x) {
this.slider.translateX(-1);
} else if (this.slider.x < hp.x) {
this.slider.translateX(1);
}
if (this.slider.y > hp.y) {
this.slider.translateY(-1);
} else if (this.slider.y < hp.y) {
this.slider.translateY(1);
}
this.puzzle.swapPuzzlePieces(tempX, tempY, this.slider.getGridX(), this.slider.getGridY());
};
this.view.update();
}
When trying to see if this method works, sliding along the proper axis works fine but if a shift is not axis-aligned, the results were a bit strange. The quick solution to this problem is to simply limit sliding to axis-aligned slides, which is what the game is going to do anyways. I do not like stop-gap solutions but prefer when possible to know why things are not working. This problem actually was simple enough to figure out, as the strange results come from moves that are positive or negative along both the X and Y axis. Movement along the proper Z axis always results in opposite mathematical operations being applied to X and Y.
While I could probably special case the sliding of positive or negative X/Y combos, I really wanted to get this game finished in under an hour so I would have more time for the next game as it is a fairly complex game. As I would not be able to rely on sliding to random points as I did with the original sliding puzzle, my quick and dirty solution was to simply increase the amount of random slides five-fold calling the sliding through the axis-checking onTileClicked method.
The next (and as it turned out final) game in this series is still not the rotation puzzle but something never released on the Blazing Games site. The development on that game will start being covered next week.
Originally, I was not thinking about doing a hex-based sliding puzzle as realistically you can not slide hexes as they form a really nicely locked pattern. Puzzle games do not necessarily have to reflect reality, so after thinking about it for a while, I figured that this would be an interesting game to develop. After playing the finished version of the game, I am quite glad that I did as it is actually a really fun variation of the sliding puzzle.
The hard part to creating this game is in dealing with the sliding. A hex grid can be thought of as a three-axis system, but that is only partially true. While the Z axis does exist, it is dependent on the X axis and the Y axis. This means that manipulating the Z axis means that you are actually changing the X and Y axis. This got me thinking that if I just move along both the X and Y axis at the same time, things should work. Here is the new version of the sliding code.
PuzzleGallery.HexSlidingPuzzleGame.prototype.moveSlider = function(p)
{
var tempX,tempY;
var hp = new PuzzleGallery.HexPoint();
hp.setPointFromGrid(p.x, p.y);
while ((this.slider.x != hp.x) || (this.slider.y != hp.y)) {
tempX = this.slider.getGridX();
tempY = this.slider.getGridY();
if (this.slider.x > hp.x) {
this.slider.translateX(-1);
} else if (this.slider.x < hp.x) {
this.slider.translateX(1);
}
if (this.slider.y > hp.y) {
this.slider.translateY(-1);
} else if (this.slider.y < hp.y) {
this.slider.translateY(1);
}
this.puzzle.swapPuzzlePieces(tempX, tempY, this.slider.getGridX(), this.slider.getGridY());
};
this.view.update();
}
When trying to see if this method works, sliding along the proper axis works fine but if a shift is not axis-aligned, the results were a bit strange. The quick solution to this problem is to simply limit sliding to axis-aligned slides, which is what the game is going to do anyways. I do not like stop-gap solutions but prefer when possible to know why things are not working. This problem actually was simple enough to figure out, as the strange results come from moves that are positive or negative along both the X and Y axis. Movement along the proper Z axis always results in opposite mathematical operations being applied to X and Y.
While I could probably special case the sliding of positive or negative X/Y combos, I really wanted to get this game finished in under an hour so I would have more time for the next game as it is a fairly complex game. As I would not be able to rely on sliding to random points as I did with the original sliding puzzle, my quick and dirty solution was to simply increase the amount of random slides five-fold calling the sliding through the axis-checking onTileClicked method.
The next (and as it turned out final) game in this series is still not the rotation puzzle but something never released on the Blazing Games site. The development on that game will start being covered next week.
Friday, October 7, 2011
DDTe3 Hour 17 - Hex Spin Puzzle
This is a continuation of my series on the creation of Dozen Days of Tiles episode 3 games on the Blazing Games site. While the other episodes in the Dozen Days series were about the creation of a game in under 24 hours, this episode is a challenge to see how many simple games can be created in under 24 hours. While this article covers the creation of the hex spin game, it is heavily dependent on the material covered in previous posts.
The next game to create this “day” is the hex-based variation of the spin puzzle. Because of the nature of the hex grid, the spin is a fairly natural operation. The spin, when looked at from a hex map perspective as figure 1 shows, is a very simple operation. Of course, using the grid coordinates that we are storing the hex in would make doing this procedure very tricky to code but by using the hex coordinate system that was discussed in an earlier article this can be a very easy piece of code to write.
Converting between the two coordinate systems is easy enough to do and could be done right in the spinning code, I have a third hex game in mind so it might be better off to put the conversion and translation of hex coordinates into it’s own class, which I called HexPoint. This class has methods for converting between the two coordinate systems as well as for translating (moving) the hex point along the x, y and z axis. The z axis is tied to the other two so manipulating the z axis actually adjusts both the x and y axis as the following code snippet shows.
PuzzleGallery.HexPoint.prototype.translateZ = function(adj)
{
this.y = this.y + adj;
this.x = this.x - adj;
}
The HexSpinPuzzle game is essentially the SpinPuzzle game but with a hex grid so the only code that really needs to be written to create this game is a spin methods. Because I am “borrowing” code from SpinPuzzle which itself was borrowed from TwistPuzzle, the method to perform the spin action is called performTwist. While the logic behind the spin is the same as with the two grid games, the implementation is a bit more complex due to the need to work with two different coordinate systems. While at first glance the code may seem complex, it is remarkably simple and took very little time to write. Essentially, all we are doing is defining a pair of hex coordinates which represent the tiles that are to be manipulated. We start by finding the coordinates of the starting point. I am using the y-1 hex coordinate, though any hex that circles the hex tile that was clicked on could have been chosen for the starting point. As with the regular twist and spin puzzles, we need to save this to a temporary variable as this tile is going to be replaced. The coordinate is saved in a second HexPoint and the original point is translated to the position of the tile that will be shifted into the original point. Becuse of the point chosen to start at, the order of the translations are x+1, y+1, z+1, x-1, and y-1. The final z-1 translation would take us back to the start so instead of doing that translation we instead use the temp value. After each translation, the tile at that location is copied to the previous position.
PuzzleGallery.HexSpinPuzzleGame.prototype.performTwist = function(p)
{
var hp1 = new PuzzleGallery.HexPoint();
var hp2 = new PuzzleGallery.HexPoint();
hp1.setPointFromGrid(p.x, p.y);
hp1.translateY(-1);
hp2.moveTo(hp1.x, hp1.y);
var temp = this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY());
hp1.translateX(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateZ(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateX(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
// hp1.translateZ(-1);
this.puzzle.setPuzzlePiece(hp2.getGridX(), hp2.getGridY(), temp);
this.view.update();
}
With this done the game is ready. The next hex game should be fairly simple to write and will probably leave me with enough time to create an eighth game.
The next game to create this “day” is the hex-based variation of the spin puzzle. Because of the nature of the hex grid, the spin is a fairly natural operation. The spin, when looked at from a hex map perspective as figure 1 shows, is a very simple operation. Of course, using the grid coordinates that we are storing the hex in would make doing this procedure very tricky to code but by using the hex coordinate system that was discussed in an earlier article this can be a very easy piece of code to write.
![]() |
figure 1 - Hex Spin |
Converting between the two coordinate systems is easy enough to do and could be done right in the spinning code, I have a third hex game in mind so it might be better off to put the conversion and translation of hex coordinates into it’s own class, which I called HexPoint. This class has methods for converting between the two coordinate systems as well as for translating (moving) the hex point along the x, y and z axis. The z axis is tied to the other two so manipulating the z axis actually adjusts both the x and y axis as the following code snippet shows.
PuzzleGallery.HexPoint.prototype.translateZ = function(adj)
{
this.y = this.y + adj;
this.x = this.x - adj;
}
The HexSpinPuzzle game is essentially the SpinPuzzle game but with a hex grid so the only code that really needs to be written to create this game is a spin methods. Because I am “borrowing” code from SpinPuzzle which itself was borrowed from TwistPuzzle, the method to perform the spin action is called performTwist. While the logic behind the spin is the same as with the two grid games, the implementation is a bit more complex due to the need to work with two different coordinate systems. While at first glance the code may seem complex, it is remarkably simple and took very little time to write. Essentially, all we are doing is defining a pair of hex coordinates which represent the tiles that are to be manipulated. We start by finding the coordinates of the starting point. I am using the y-1 hex coordinate, though any hex that circles the hex tile that was clicked on could have been chosen for the starting point. As with the regular twist and spin puzzles, we need to save this to a temporary variable as this tile is going to be replaced. The coordinate is saved in a second HexPoint and the original point is translated to the position of the tile that will be shifted into the original point. Becuse of the point chosen to start at, the order of the translations are x+1, y+1, z+1, x-1, and y-1. The final z-1 translation would take us back to the start so instead of doing that translation we instead use the temp value. After each translation, the tile at that location is copied to the previous position.
PuzzleGallery.HexSpinPuzzleGame.prototype.performTwist = function(p)
{
var hp1 = new PuzzleGallery.HexPoint();
var hp2 = new PuzzleGallery.HexPoint();
hp1.setPointFromGrid(p.x, p.y);
hp1.translateY(-1);
hp2.moveTo(hp1.x, hp1.y);
var temp = this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY());
hp1.translateX(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateZ(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateX(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
// hp1.translateZ(-1);
this.puzzle.setPuzzlePiece(hp2.getGridX(), hp2.getGridY(), temp);
this.view.update();
}
With this done the game is ready. The next hex game should be fairly simple to write and will probably leave me with enough time to create an eighth game.
Thursday, September 29, 2011
DDTe3 Hour 15 - 16 Hex Puzzle Game
My series of posts on the creation of Dozen Days of Tiles episode 3 (Puzzle Gallery) continues with the creation of the hex puzzle game. This builds on the theory and code from the last couple of posts so please read those first.
With the HexTile class complete, the next step is to actually display the puzzle. The display of a hex grid is a bit more complicated then displaying a regular tile grid. If you draw a rectangle on a piece of hex graph paper, you will notice that you will be clipping half a hex on each end. This means that the width of a hex-tile is equivalent to the width of the display divided by the half a hex more than the number of desired tiles in the row. The height of a hex -tile is even more confusing to calculate. Because the rows of hexes overlap, the height of a row is essentially less than the height of a tile. When determining the tile height, it is best to think of each row (except the last) being ¾ of the height of a tile.
var halfWidth = Math.floor(clip.width / (puzzle.puzzleWidth * 2 + 1));
var quarterHeight = Math.floor(clip.height / (puzzle.puzzleHeight * 3 + 1));
this.tileWidth = halfWidth * 2;
this.tileHeight = quarterHeight * 4;
Laying out the tiles is pretty much the same as laying out a grid, except that every other row is offset by half a tile. Unlike the grid based games, the border is kind of important here as bits of the image are cut out by the irregular shape of the board. The border is drawn the same as it was in the original BasePuzzleView class except that the top and bottom extend a quarter of a tile into the board and the left and right borders extend half a tile into the board.
With the puzzle drawing properly, we now have the problem that the board is drawn in it’s solved state. Moving the hex tiles around is a bit trickier and I was about to write code to calculate the placement of a hex when I realized that I would be looping through them all anyway. By using the Puzzle value to determine which hex goes in which screen location, the update code was only marginally different from the original update code.
The final challenge, which I cheated on, is the click handling. Instead of properly determining which hex was clicked on, I assumed that most people are going to be clicking near the middle of a hex anyway so went with the much simpler bounding box. I may do proper checks later but for now the method is good enough.
With the click support added, creating the first puzzle was simply a matter of copying the original PicturePuzzle Class and changing BasePuzzleView to HexPuzzleView where necessary. With this done, the first hex based puzzle is done and it is time to start on the next one.
With the HexTile class complete, the next step is to actually display the puzzle. The display of a hex grid is a bit more complicated then displaying a regular tile grid. If you draw a rectangle on a piece of hex graph paper, you will notice that you will be clipping half a hex on each end. This means that the width of a hex-tile is equivalent to the width of the display divided by the half a hex more than the number of desired tiles in the row. The height of a hex -tile is even more confusing to calculate. Because the rows of hexes overlap, the height of a row is essentially less than the height of a tile. When determining the tile height, it is best to think of each row (except the last) being ¾ of the height of a tile.
![]() | |
figure 1 - Hex Clip |
var halfWidth = Math.floor(clip.width / (puzzle.puzzleWidth * 2 + 1));
var quarterHeight = Math.floor(clip.height / (puzzle.puzzleHeight * 3 + 1));
this.tileWidth = halfWidth * 2;
this.tileHeight = quarterHeight * 4;
Laying out the tiles is pretty much the same as laying out a grid, except that every other row is offset by half a tile. Unlike the grid based games, the border is kind of important here as bits of the image are cut out by the irregular shape of the board. The border is drawn the same as it was in the original BasePuzzleView class except that the top and bottom extend a quarter of a tile into the board and the left and right borders extend half a tile into the board.
With the puzzle drawing properly, we now have the problem that the board is drawn in it’s solved state. Moving the hex tiles around is a bit trickier and I was about to write code to calculate the placement of a hex when I realized that I would be looping through them all anyway. By using the Puzzle value to determine which hex goes in which screen location, the update code was only marginally different from the original update code.
The final challenge, which I cheated on, is the click handling. Instead of properly determining which hex was clicked on, I assumed that most people are going to be clicking near the middle of a hex anyway so went with the much simpler bounding box. I may do proper checks later but for now the method is good enough.
With the click support added, creating the first puzzle was simply a matter of copying the original PicturePuzzle Class and changing BasePuzzleView to HexPuzzleView where necessary. With this done, the first hex based puzzle is done and it is time to start on the next one.
Friday, September 23, 2011
DDTe3 Hour 12 - 14 Hex Tile
This is a continuation of my series of articles on the creation of Dozen Days of Tiles episode 3. In this part, we continue developing the hex code by creating a hex-shaped image clipping tile.
As I don’t already have any existing classes for drawing masked shapes, a new class is going to need to be created for drawing the hex tile. This new class works very similarly to the existing ImageLayer class, but with a bit more drawing complexity. Overridding the ImageLayer class does not make sense as the drawing code is going to have to be replaced.
Clipping in the HTML5 canvas is a bit tricky. The important thing to remember about clipping is that you MUST save the state of the canvas before setting a clipping region and restore the state of the canvas once you are done. The canvas does not let you create a new clipping region larger than the existing region. Each successive clip results in a ever-shrinking drawable region. I personally would have used a additive/subtractive model for building a clipping layer, but that is not what we currently have to work with.
Drawing the hex tile then consists of saving the canvas state, creating a hex path (outPath) for the tile, clipping the canvas using the path, drawing the tile as a rectangle, then restoring the canvas state. As I was doing all this drawing work anyway, I started thinking that perhaps I should combine the drawing of the hex with the drawing of the highlight/border. Adding the setup/management methods of the TileBorder class to the HexTile class was simple as these classes for just set up variables. The hard part would be drawing them, and this was actually not overly difficult.
My first thought was to use a clipping approach as was done with the drawing of the image. This thought only lasted a few second as I quickly realized that instead of drawing a transparent rectangle over a clipping path, I could just draw a transparent color using the path. By creating the inner bounds of the border, I would also have the path needed for drawing the highlight color. With inner and outer hexes, it is possible to create the border path. As explained in the previous post, the border has to reverse the order of the inner path points as the winding order of the lines in the path determine the fill area. With the outer and inner hex path, this is very simple to do.
for (var cntr = 0; cntr < 7; ++cntr) {
this.borderPath[cntr] = this.outPath[cntr];
this.borderPath[13-cntr] = this.inPath[cntr];
}
this.borderPath[14] = this.outPath[6];
The next step then is to create a hex view. That, along with the first hex game, is what we will be looking at next.
As I don’t already have any existing classes for drawing masked shapes, a new class is going to need to be created for drawing the hex tile. This new class works very similarly to the existing ImageLayer class, but with a bit more drawing complexity. Overridding the ImageLayer class does not make sense as the drawing code is going to have to be replaced.
Clipping in the HTML5 canvas is a bit tricky. The important thing to remember about clipping is that you MUST save the state of the canvas before setting a clipping region and restore the state of the canvas once you are done. The canvas does not let you create a new clipping region larger than the existing region. Each successive clip results in a ever-shrinking drawable region. I personally would have used a additive/subtractive model for building a clipping layer, but that is not what we currently have to work with.
Drawing the hex tile then consists of saving the canvas state, creating a hex path (outPath) for the tile, clipping the canvas using the path, drawing the tile as a rectangle, then restoring the canvas state. As I was doing all this drawing work anyway, I started thinking that perhaps I should combine the drawing of the hex with the drawing of the highlight/border. Adding the setup/management methods of the TileBorder class to the HexTile class was simple as these classes for just set up variables. The hard part would be drawing them, and this was actually not overly difficult.
My first thought was to use a clipping approach as was done with the drawing of the image. This thought only lasted a few second as I quickly realized that instead of drawing a transparent rectangle over a clipping path, I could just draw a transparent color using the path. By creating the inner bounds of the border, I would also have the path needed for drawing the highlight color. With inner and outer hexes, it is possible to create the border path. As explained in the previous post, the border has to reverse the order of the inner path points as the winding order of the lines in the path determine the fill area. With the outer and inner hex path, this is very simple to do.
for (var cntr = 0; cntr < 7; ++cntr) {
this.borderPath[cntr] = this.outPath[cntr];
this.borderPath[13-cntr] = this.inPath[cntr];
}
this.borderPath[14] = this.outPath[6];
The next step then is to create a hex view. That, along with the first hex game, is what we will be looking at next.
Thursday, September 15, 2011
DDTe3 Hours 11 Drawing Hexes
In order to manipulate hex-shaped images, masks are going to have to be used. In canvas parlance, clipping regions are the proper term. Clipping is one of the ugliest parts of the canvas API, as it uses a shrinking region logic. You have to save the canvas state before setting up the region, set up the region, do the clipping based drawing, then restore the state of the canvas. Thankfully clipping is powerful enough to allow paths to be used to create a clipping region. This means that if we can create a simple hex-drawing function, that hex can be used as a clipping shape for creating hex-shaped puzzle pieces.
Actually, instead of drawing a hex, creating an array of points is more useful, especially when it comes time to creating the border. The hex, when you look at it, really only has a small number of important numbers that need to be calculated. Figure 1 shows the special points that are needed to create the hex and listing 1 shows the function used for creating the array of points.
function buildHexPath(rect, pathlist)
{
var path = pathlist;
// make sure path list of points contains proper number of points
if (path == null)
path = new Array();
while (path.length < 7)
path.push(new BGLayers.Point());
while (path.length > 7)
path.pop();
var halfx = rect.x + rect.width / 2;
var x2 = rect.x + rect.width;
var y1a = rect.y + rect.height / 4;
var y1b = rect.y + 3 * rect.height / 4;
var y2 = rect.y + rect.height;
path[0].x = rect.x;
path[0].y = y1a;
path[1].x = halfx;
path[1].y = rect.y;
path[2].x = x2;
path[2].y = y1a;
path[3].x = x2;
path[3].y = y1b;
path[4].x = halfx;
path[4].y = y2;
path[5].x = rect.x;
path[5].y = y1b;
path[6].x = rect.x;
path[6].y = y1a;
return path;
}
The hex can now be drawn, but to create a border we need a pair of hexes. My first attempt to create a border hex was to create an inner hex and an outer hex and join the two together. This did not work as expected. If you look at figure 2, the first hex is the normal hex. The second hex is suppose to be the border. My immediate reaction was that the fill method didn’t support complex polygons. This isn’t that surprising of a limitation so I quickly wrote my plan B implementation.
The third hex in this figure was created by drawing each segment of the hex separately. This was done in a similar way to the first attempt at creating a border. A outer hex and an inner hex are created and then the points are looped through and combined to create six separate polygons.
function drawHexBorder(ctx, rect, pct)
{
var outpath = buildHexPath(rect, null);
var wadj = rect.width * pct;
var hadj = rect.height * pct;
var inpath = buildHexPath(new BGLayers.Rectangle(rect.x+wadj, rect.y+hadj, rect.width - wadj-wadj, rect.height - hadj-hadj),null);
for(var cntr = 0; cntr < 6; ++cntr) {
ctx.beginPath();
ctx.moveTo(outpath[cntr].x,outpath[cntr].y);
ctx.lineTo(outpath[cntr+1].x,outpath[cntr+1].y);
ctx.lineTo(inpath[cntr+1].x,inpath[cntr+1].y);
ctx.lineTo(inpath[cntr].x,inpath[cntr].y);
ctx.lineTo(outpath[cntr].x,outpath[cntr].y);
ctx.closePath();
ctx.fill();
}
}
Once this was done I decided to spend a little bit of time researching how the cavas fill was suppose to work as I was positive that I had seen some drawings that had holes in it. After a few minutes of research (about the same amount of time it took me to write plan-b) I finally stumbled upon the winding rule for filling. It appears that the direction of the edge lines are used as part of determining of the points that are filled. While I have played with a number of fill algorithms, I have never actually implemented a winding algorithm but it does mean that by reversing the order of the points in the inner hexagon, the fill should work properly. This would allow the drawing of the border as a single drawing operation which should be more efficient.
Actually, instead of drawing a hex, creating an array of points is more useful, especially when it comes time to creating the border. The hex, when you look at it, really only has a small number of important numbers that need to be calculated. Figure 1 shows the special points that are needed to create the hex and listing 1 shows the function used for creating the array of points.
![]() |
figure 1 |
function buildHexPath(rect, pathlist)
{
var path = pathlist;
// make sure path list of points contains proper number of points
if (path == null)
path = new Array();
while (path.length < 7)
path.push(new BGLayers.Point());
while (path.length > 7)
path.pop();
var halfx = rect.x + rect.width / 2;
var x2 = rect.x + rect.width;
var y1a = rect.y + rect.height / 4;
var y1b = rect.y + 3 * rect.height / 4;
var y2 = rect.y + rect.height;
path[0].x = rect.x;
path[0].y = y1a;
path[1].x = halfx;
path[1].y = rect.y;
path[2].x = x2;
path[2].y = y1a;
path[3].x = x2;
path[3].y = y1b;
path[4].x = halfx;
path[4].y = y2;
path[5].x = rect.x;
path[5].y = y1b;
path[6].x = rect.x;
path[6].y = y1a;
return path;
}
The hex can now be drawn, but to create a border we need a pair of hexes. My first attempt to create a border hex was to create an inner hex and an outer hex and join the two together. This did not work as expected. If you look at figure 2, the first hex is the normal hex. The second hex is suppose to be the border. My immediate reaction was that the fill method didn’t support complex polygons. This isn’t that surprising of a limitation so I quickly wrote my plan B implementation.
![]() |
figure 2 |
The third hex in this figure was created by drawing each segment of the hex separately. This was done in a similar way to the first attempt at creating a border. A outer hex and an inner hex are created and then the points are looped through and combined to create six separate polygons.
function drawHexBorder(ctx, rect, pct)
{
var outpath = buildHexPath(rect, null);
var wadj = rect.width * pct;
var hadj = rect.height * pct;
var inpath = buildHexPath(new BGLayers.Rectangle(rect.x+wadj, rect.y+hadj, rect.width - wadj-wadj, rect.height - hadj-hadj),null);
for(var cntr = 0; cntr < 6; ++cntr) {
ctx.beginPath();
ctx.moveTo(outpath[cntr].x,outpath[cntr].y);
ctx.lineTo(outpath[cntr+1].x,outpath[cntr+1].y);
ctx.lineTo(inpath[cntr+1].x,inpath[cntr+1].y);
ctx.lineTo(inpath[cntr].x,inpath[cntr].y);
ctx.lineTo(outpath[cntr].x,outpath[cntr].y);
ctx.closePath();
ctx.fill();
}
}
Once this was done I decided to spend a little bit of time researching how the cavas fill was suppose to work as I was positive that I had seen some drawings that had holes in it. After a few minutes of research (about the same amount of time it took me to write plan-b) I finally stumbled upon the winding rule for filling. It appears that the direction of the edge lines are used as part of determining of the points that are filled. While I have played with a number of fill algorithms, I have never actually implemented a winding algorithm but it does mean that by reversing the order of the points in the inner hexagon, the fill should work properly. This would allow the drawing of the border as a single drawing operation which should be more efficient.
Thursday, September 1, 2011
DDTe3 Hour 10 - Spin Puzzle
The spin puzzle is similar to the twist puzzle except that the tiles surrounding the tile clicked on are the ones that move counterclockwise. As with the previous puzzle, this one was very quick to implement. In fact, this game was finished in under half an hour!
The spinning mechanism is very similar to the twist mechanism but more so. To make it easer to get my coordinates straight, I took a piece of paper and created a 3x3 grid and wrote the offsets in the grid as the following table demonstrates.
Instead of the 4 way swap that was implemented for the twist puzzle, this game will use a 8 way swap.
PuzzleGallery.SpinPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x-1, p.y-1);
this.puzzle.setPuzzlePiece(p.x-1, p.y-1, this.puzzle.getPuzzlePiece(p.x, p.y-1));
this.puzzle.setPuzzlePiece(p.x, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y-1));
this.puzzle.setPuzzlePiece(p.x+1, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y+1));
this.puzzle.setPuzzlePiece(p.x-1, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y));
this.puzzle.setPuzzlePiece(p.x-1, p.y, temp);
this.view.update();
}
Finally, the click had to make sure the position clicked on can spin and the scrambling method had to be adjusted to insure the coordinates are valid. With those simple changes, another game has been completed. My next game in this challenge will be a bit more complex as it will not only require a new view class be created, but also a new coordinate system though surprisingly the BasePuzzleModel will remain unchanged!
The spinning mechanism is very similar to the twist mechanism but more so. To make it easer to get my coordinates straight, I took a piece of paper and created a 3x3 grid and wrote the offsets in the grid as the following table demonstrates.
-1,-1 | 0,-1 | 1,-1 |
-1,0 | * | 1,0 |
-1,1 | 0,1 | 1,1 |
Instead of the 4 way swap that was implemented for the twist puzzle, this game will use a 8 way swap.
PuzzleGallery.SpinPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x-1, p.y-1);
this.puzzle.setPuzzlePiece(p.x-1, p.y-1, this.puzzle.getPuzzlePiece(p.x, p.y-1));
this.puzzle.setPuzzlePiece(p.x, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y-1));
this.puzzle.setPuzzlePiece(p.x+1, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y+1));
this.puzzle.setPuzzlePiece(p.x-1, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y));
this.puzzle.setPuzzlePiece(p.x-1, p.y, temp);
this.view.update();
}
Finally, the click had to make sure the position clicked on can spin and the scrambling method had to be adjusted to insure the coordinates are valid. With those simple changes, another game has been completed. My next game in this challenge will be a bit more complex as it will not only require a new view class be created, but also a new coordinate system though surprisingly the BasePuzzleModel will remain unchanged!
Thursday, August 25, 2011
DDTe3 Hour 9 Twist puzzle
While it has been a while since the last post in this series due to a family tragedy, I am now back to posting weekly and am continuing my series of articles on the creation of Dozen Days of Tiles episode 3. This is a game in a day challenge in which instead of developing a game in under 24 hours (development time) I am instead seeing how many games can be created in 24 hours of development time. Today the creation of the twist puzzle is covered.
The twist puzzle takes a 2x2 block of tiles and rotates them counter-clockwise. The only new game mechanic revolves around the rotation of tiles, which can be handled using existing BasePuzzleModel classes. There are no changes needed to the view class making this is a very quick project.
The game mechanic that needs to be implemented is a performTwist method. This could be done using three swaps as outlined in the following pseudo-code:
swap x,y with x+1,y
swap x+1,y with x+1,y+1
swap x+1,y+1 with x,y+1
However this results in six tile moves. Because I already knew which game I was going to develop right after this one was finished, I decided to use a more efficient four-way swap as the next game in the series would be better able to utilize this code. Having long-term plans is always nice, even if they don't come to fruition they are giving you a path to follow.
PuzzleGallery.TwistPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x, p.y);
this.puzzle.setPuzzlePiece(p.x, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, temp);
this.view.update();
}
This still leaves the problem that tiles along the right and bottom edges are not valid to click on so the onTileClick callback method has to be slightly changed.
PuzzleGallery.TwistPuzzleGame.prototype.onTileClick = function(p)
{
if (( p.x < (this.puzzle.puzzleWidth-1)) && (p.y < (this.puzzle.puzzleHeight-1)))
this.performTwist(p);
}
The game scrambling likewise needs to be changed. As with the sliding puzzle game, a scramble method that randomly selects a valid tile and performs a twist on that tile is all that was needed.
PuzzleGallery.TwistPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * (w-1));
p.y = Math.floor(Math.random() * (h-1));
this.performTwist(p);
}
}
While I try to focus on writing about the theory behind the code and try only to show the relevant bits of code, almost all the code that I wrote is in this article. Still, finishing a game in well under an hour (though I am still counting the time as an hour to simplify my time-keeping) is great.
The twist puzzle takes a 2x2 block of tiles and rotates them counter-clockwise. The only new game mechanic revolves around the rotation of tiles, which can be handled using existing BasePuzzleModel classes. There are no changes needed to the view class making this is a very quick project.
The game mechanic that needs to be implemented is a performTwist method. This could be done using three swaps as outlined in the following pseudo-code:
swap x,y with x+1,y
swap x+1,y with x+1,y+1
swap x+1,y+1 with x,y+1
However this results in six tile moves. Because I already knew which game I was going to develop right after this one was finished, I decided to use a more efficient four-way swap as the next game in the series would be better able to utilize this code. Having long-term plans is always nice, even if they don't come to fruition they are giving you a path to follow.
PuzzleGallery.TwistPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x, p.y);
this.puzzle.setPuzzlePiece(p.x, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, temp);
this.view.update();
}
This still leaves the problem that tiles along the right and bottom edges are not valid to click on so the onTileClick callback method has to be slightly changed.
PuzzleGallery.TwistPuzzleGame.prototype.onTileClick = function(p)
{
if (( p.x < (this.puzzle.puzzleWidth-1)) && (p.y < (this.puzzle.puzzleHeight-1)))
this.performTwist(p);
}
The game scrambling likewise needs to be changed. As with the sliding puzzle game, a scramble method that randomly selects a valid tile and performs a twist on that tile is all that was needed.
PuzzleGallery.TwistPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * (w-1));
p.y = Math.floor(Math.random() * (h-1));
this.performTwist(p);
}
}
While I try to focus on writing about the theory behind the code and try only to show the relevant bits of code, almost all the code that I wrote is in this article. Still, finishing a game in well under an hour (though I am still counting the time as an hour to simplify my time-keeping) is great.
Friday, July 29, 2011
DDTe3 Hour 8 - Sliding Puzzle
My mother went from improving to a very rapid decline and passed away July 29th at 1:05AM. She meant the world to me and will be greatly missed. While I posted a game on BlazingGames.com this week as the game ready to post, I will be taking a few week break from posting new material. I am many weeks ahead on this blog for material so may still post the weekly articles here but I can not guarantee this. Here is the continuation of my How Many Games can I Develop in 24 hours challenge.
Creating the Sliding Puzzle game is fairly straightforward as the only real game mechanic that needs to be implemented is the slider. The slider is simply the bottom right-most tile set to be highlighted with the highlight color being near-opaque. The reason for making it near-opaque instead of fully-opaque is that I felt the game would be better if you knew what part of the image the slider represented but it had to be dark enough that it was obviously the slider. Creating the slider, then, required very little code.
this.slider = new BGLayers.Point(tw-1, th-1);
this.view.setTileHighlight(tw-1, th-1, true);
this.view.setColors("rgb(100,0,100)", "green", "red", .5, .9);
With the slider on the board, the only other major game-play mechanic became moving the slider around. I decided that the best way to implement the movement of the slider would be to simply take a point that represents where the slider is to be moved to and then move the slider horizontally until it is at the proper x location and then vertically until it is at the proper y location.
PuzzleGallery.SlidingPuzzleGame.prototype.moveSlider = function(p)
{
this.view.setTileHighlight(this.slider.x, this.slider.y, false);
while (this.slider.x < p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x+1, this.slider.y);
++this.slider.x;
};
while (this.slider.x > p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x-1, this.slider.y);
--this.slider.x;
};
while (this.slider.y < p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y+1);
++this.slider.y;
};
while (this.slider.y > p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y-1);
--this.slider.y;
};
this.view.setTileHighlight(this.slider.x, this.slider.y, true);
this.view.update();
}
This made implementing the mouse very easy as you simply call the moveSlider function with the point passed by the onTileClick call that BasePuzzleView makes when a tile is clicked. While having both horizontal and vertical movement at once was nice, after playing the game I worried that it might be too confusing to the player so altered the onTileClick function to only allow the slider to move when the move was only horizontal or vertical.
The other thing I was worried about is that the scrambling of the puzzle was not based on the game-play mechanic. While I am positive that this shouldn’t matter and that any scrambled puzzle should be solvable, I decided not to take any chances and wrote my own Sliding Puzzle Game scrambling function. This simply moves the slider around by randomly selecting points on the puzzle and calling the moveSlider function using that point.
PuzzleGallery.SlidingPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * w);
p.y = Math.floor(Math.random() * h);
this.moveSlider(p);
}
}
And with that done, we have finished a second game. For the third game, however, I am not going to go with the rotation puzzle but have a different sort of twist in mind.
Creating the Sliding Puzzle game is fairly straightforward as the only real game mechanic that needs to be implemented is the slider. The slider is simply the bottom right-most tile set to be highlighted with the highlight color being near-opaque. The reason for making it near-opaque instead of fully-opaque is that I felt the game would be better if you knew what part of the image the slider represented but it had to be dark enough that it was obviously the slider. Creating the slider, then, required very little code.
this.slider = new BGLayers.Point(tw-1, th-1);
this.view.setTileHighlight(tw-1, th-1, true);
this.view.setColors("rgb(100,0,100)", "green", "red", .5, .9);
With the slider on the board, the only other major game-play mechanic became moving the slider around. I decided that the best way to implement the movement of the slider would be to simply take a point that represents where the slider is to be moved to and then move the slider horizontally until it is at the proper x location and then vertically until it is at the proper y location.
PuzzleGallery.SlidingPuzzleGame.prototype.moveSlider = function(p)
{
this.view.setTileHighlight(this.slider.x, this.slider.y, false);
while (this.slider.x < p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x+1, this.slider.y);
++this.slider.x;
};
while (this.slider.x > p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x-1, this.slider.y);
--this.slider.x;
};
while (this.slider.y < p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y+1);
++this.slider.y;
};
while (this.slider.y > p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y-1);
--this.slider.y;
};
this.view.setTileHighlight(this.slider.x, this.slider.y, true);
this.view.update();
}
This made implementing the mouse very easy as you simply call the moveSlider function with the point passed by the onTileClick call that BasePuzzleView makes when a tile is clicked. While having both horizontal and vertical movement at once was nice, after playing the game I worried that it might be too confusing to the player so altered the onTileClick function to only allow the slider to move when the move was only horizontal or vertical.
The other thing I was worried about is that the scrambling of the puzzle was not based on the game-play mechanic. While I am positive that this shouldn’t matter and that any scrambled puzzle should be solvable, I decided not to take any chances and wrote my own Sliding Puzzle Game scrambling function. This simply moves the slider around by randomly selecting points on the puzzle and calling the moveSlider function using that point.
PuzzleGallery.SlidingPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * w);
p.y = Math.floor(Math.random() * h);
this.moveSlider(p);
}
}
And with that done, we have finished a second game. For the third game, however, I am not going to go with the rotation puzzle but have a different sort of twist in mind.
Thursday, July 21, 2011
DDTe3 Hour 7 - Making a Slider
As mentioned last post, to make it easier to remember to post, I am going to post the blog at the same time I update Blazing Games. This week I am continuing my series of articles on the creation of Dozen Days of Tiles episode 3 which is an as many games as I can develop in under 24 hours of development time challenge. So far the picture puzzle game has been created so development on a sliding puzzle has just started.
After finishing the first game, most of the work is now present that additional games should be able to be created quickly. The second game that I have in mind is a sliding puzzle. To get the functionality needed to create the game, a slider has to be moved around the game board. This can be handled by swapping pieces so no additional features need to be added to the base puzzle model. However, there needs to be a visible slider on the screen so some extensions will need to be added to the base model view class.
While thinking about how to actually add the tile, my first thought was to simply make the highlight as the tile. As clicking on a tile will cause the slider to move, no highlight is needed for this game so all the work is already done. The only downside to this approach is that it would require a more-solid highlight but since I want to add the ability to change the border and highlight colors anyway, the slider would be essentially free. Another route that I could have taken would be to simply add an ability to grab a tiles display position so I could simply add a sprite over-top of the board.
To allow the tile border and highlight colors to be changed, a setColors function was added to the TileBorder class. The class uses both colors and alpha values as I had decided when creating the HighlightBlock class to keep the alpha value separate from the color. My thoughts at the time were that it allows for alpha effects to be implemented much easier and has the side benifit that normal color labels (such as red or blue) can then be used rather than requiring the use of the rgba() function to specify colors.
Finally, in the BaseModelView class, a set colors class was added which simply calls the setColor class for every border in the view.
PuzzleGallery.BasePuzzleView.prototype.setColors = function(col, ccol, ecol, ba, ha)
{
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h;
for (var indx = 0; indx < n; ++indx) {
this.tileBorders[indx].setColors(col, ccol, ecol, ba, ha);
}
this.addDirty(null);
}
We now have everything needed to create a slider so the next step is to create a sliding puzzle game.
After finishing the first game, most of the work is now present that additional games should be able to be created quickly. The second game that I have in mind is a sliding puzzle. To get the functionality needed to create the game, a slider has to be moved around the game board. This can be handled by swapping pieces so no additional features need to be added to the base puzzle model. However, there needs to be a visible slider on the screen so some extensions will need to be added to the base model view class.
While thinking about how to actually add the tile, my first thought was to simply make the highlight as the tile. As clicking on a tile will cause the slider to move, no highlight is needed for this game so all the work is already done. The only downside to this approach is that it would require a more-solid highlight but since I want to add the ability to change the border and highlight colors anyway, the slider would be essentially free. Another route that I could have taken would be to simply add an ability to grab a tiles display position so I could simply add a sprite over-top of the board.
To allow the tile border and highlight colors to be changed, a setColors function was added to the TileBorder class. The class uses both colors and alpha values as I had decided when creating the HighlightBlock class to keep the alpha value separate from the color. My thoughts at the time were that it allows for alpha effects to be implemented much easier and has the side benifit that normal color labels (such as red or blue) can then be used rather than requiring the use of the rgba() function to specify colors.
Finally, in the BaseModelView class, a set colors class was added which simply calls the setColor class for every border in the view.
PuzzleGallery.BasePuzzleView.prototype.setColors = function(col, ccol, ecol, ba, ha)
{
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h;
for (var indx = 0; indx < n; ++indx) {
this.tileBorders[indx].setColors(col, ccol, ecol, ba, ha);
}
this.addDirty(null);
}
We now have everything needed to create a slider so the next step is to create a sliding puzzle game.
Sunday, July 17, 2011
DDTe3 Hours 5 to 6 The Picture Puzzle Game
My mother is still in the hospital, which is at least part of the reason I missed posting this last week. I am thinking about updating this blog the same time that I update the Blazing Games site, but kind of want to keep them separate to emphasis the fact that they are separate things. The few people who actually read this probably already realize this and combining the posting dates may make things easier so don't be surprised if the blog starts being updated late Thursday nights (PST). This is continuing the development of Dozen Days of Tiles episode 3 which is a how many games can I develop in 24 hours challenge instead of the usual developing a game in under 24 hours challenge.
With the puzzle displaying, we are most of the way to a playable picture puzzle game. The only issue remaining that must be solved is input. The mouse input is handled by the BasePuzzleView class by calling a listener function. As this listener function can be set by any of the games, it is not game dependent. Instead, the function that gets called is what holds the game-play logic.
The information that the game needs to know is what tile was selected. There are a number of ways this information can be passed, but the most universally useful way is simply to indicate the row and column that was selected as any other information can be derived from that knowledge. Determining this is a bit more problematic as BGLayers passes real mouse positions not logical ones. This conversion from real to logical coordinates is something that BGLayers probably should have functions to handle but it does not. Still, this is very easy to calculate as it is essentially just a scaling calculation.
var rp = this.findRealPosition();
var lx = (x - rp.x) * (this._logicalSize.width / rp.width);
var ly = (y - rp.y) * (this._logicalSize.height / rp.height);
var p = new BGLayers.Point(Math.floor((lx - this.tileLeft) / this.tileWidth),
Math.floor((ly - this.tileTop) / this.tileHeight));
The game logic to handle the click simply stores the first tile clicked on as the selector and the second click swaps the two tiles. At this point we have a playable game but three problems immediately come to mind. First, there is no visible way of knowing what tile was selected. Second, it isn't always obvious where the tiles are. Third, there is no indication about which tiles are correct or not. The second and third problems can be solved by adding a border that has an optional hint capability. But instead of just having a border, why not add a highlight feature to the border as well and get a hat-trick. For those of you not familiar with Hockey, a hat-trick is when a player scores three goals in a single game.
The TileBorder class simply consists of the four borders and the highlight. The class holds 3 colors one highlight color, one correct color and one incorrect color. The correctness is handled by a setCorrect(b) function that sets the border colors to the correct color if passed true and to the error color if passed false. The highlight is set to the highlight color and is initially invisible but can be turned on (or off again) by calling the setHighlight function.
In my first attempt of implementing this, the borders were just layer classes but I discovered that the rgba colors were not working. This was obviously because the layers by default are solid. Unfortunately, setting them to transparent has the side effect of not drawing the background color making them invisible. This makes sense as the layers are placeholders that draw a background color if necessary and if the layer isn't solid then no background is needed. A new class, the HightlightBlock, was quickly created to draw a solid block. Instead of using rgba colors for transparency, I instead opted for a separate alpha channel. While not utilized yet, it opens the possibility of alternating the transparency without having to worry about the color.
The tile borders are then added to the BasePuzzleView class after the tiles are created so that the borders will always be above the tiles. The update method then adds a single line to it's update loop:
this.tileBorders[indx].setCorrect(tile == indx);
This line sets the correctness color of the border. With that we have a fully playable game. One game down and at least another 3 to go.
With the puzzle displaying, we are most of the way to a playable picture puzzle game. The only issue remaining that must be solved is input. The mouse input is handled by the BasePuzzleView class by calling a listener function. As this listener function can be set by any of the games, it is not game dependent. Instead, the function that gets called is what holds the game-play logic.
The information that the game needs to know is what tile was selected. There are a number of ways this information can be passed, but the most universally useful way is simply to indicate the row and column that was selected as any other information can be derived from that knowledge. Determining this is a bit more problematic as BGLayers passes real mouse positions not logical ones. This conversion from real to logical coordinates is something that BGLayers probably should have functions to handle but it does not. Still, this is very easy to calculate as it is essentially just a scaling calculation.
var rp = this.findRealPosition();
var lx = (x - rp.x) * (this._logicalSize.width / rp.width);
var ly = (y - rp.y) * (this._logicalSize.height / rp.height);
var p = new BGLayers.Point(Math.floor((lx - this.tileLeft) / this.tileWidth),
Math.floor((ly - this.tileTop) / this.tileHeight));
The game logic to handle the click simply stores the first tile clicked on as the selector and the second click swaps the two tiles. At this point we have a playable game but three problems immediately come to mind. First, there is no visible way of knowing what tile was selected. Second, it isn't always obvious where the tiles are. Third, there is no indication about which tiles are correct or not. The second and third problems can be solved by adding a border that has an optional hint capability. But instead of just having a border, why not add a highlight feature to the border as well and get a hat-trick. For those of you not familiar with Hockey, a hat-trick is when a player scores three goals in a single game.
The TileBorder class simply consists of the four borders and the highlight. The class holds 3 colors one highlight color, one correct color and one incorrect color. The correctness is handled by a setCorrect(b) function that sets the border colors to the correct color if passed true and to the error color if passed false. The highlight is set to the highlight color and is initially invisible but can be turned on (or off again) by calling the setHighlight function.
In my first attempt of implementing this, the borders were just layer classes but I discovered that the rgba colors were not working. This was obviously because the layers by default are solid. Unfortunately, setting them to transparent has the side effect of not drawing the background color making them invisible. This makes sense as the layers are placeholders that draw a background color if necessary and if the layer isn't solid then no background is needed. A new class, the HightlightBlock, was quickly created to draw a solid block. Instead of using rgba colors for transparency, I instead opted for a separate alpha channel. While not utilized yet, it opens the possibility of alternating the transparency without having to worry about the color.
The tile borders are then added to the BasePuzzleView class after the tiles are created so that the borders will always be above the tiles. The update method then adds a single line to it's update loop:
this.tileBorders[indx].setCorrect(tile == indx);
This line sets the correctness color of the border. With that we have a fully playable game. One game down and at least another 3 to go.
Monday, July 4, 2011
DDTe3 Hours 2 to 4 Drawing the Puzzle
As my Mother is still in the hospital, I am quite thankful that I have been writing my development articles as the games were written so I am months ahead of schedule when it comes to material that is ready to post. If only I could remember to post things on time :). This series was interrupted by a couple of weeks to celebrate the release of Duke Nukem Forever and to take a brief look at my ImageAtlas library but now we continue by developing the core classes that will allow me to create a lot of games really quickly.
The BasePuzzleView class has the job of displaying the puzzle. This puzzle is drawn from an image that is passed into this class. To make the game as flexible as possible, I want to be able to use only part of an image. This makes it easier to work with images that only have a partially usable portion. More important, at least in my situation, it makes it possible to maintain the proper aspect ratio for an image that is a different size than the canvas the game is going to be played in. While it is certainly possible to make the canvas a proportional size to the image being used, I like to keep my canvas a constant size. As my BGLayers library already has a rectangle class, it is simple enough to pass in a clipping region. Finally, we need the model class being displayed. With this information we have the constructor for our class.
When I started to write this class, two ways of implementing it came immediately to my mind. One way would be to have the class do all the bitmap manipulation itself when drawing. The other would be to have the class made up of a bunch of child ImageLayers that hold all the pieces of the puzzle. The first method removes a lot of overhead from having a lot of layers on the display list at a cost of a very difficult rendering process. While more efficient, speed probably is not going to be an issue whatsoever with any of the games that make up this project, so the easier to implement child path is the one I decided to go with.
The first step I then went on to implement was determining if borders were necessary. My old-school thinking was that tiles should be integers which means that it is possible for there to be borders. I was not thinking that the view is a layer that uses logical coordinates and is going to be scaled and that partial pixels are already handled by BGLayers. This is a weird lack of thinking as I am taking advantage of how BGLayers uses logical coordinates by setting the size of the layer to the size of the clipping region. Still, this is a fairly simple problem to solve. The tile size is determined by dividing width and height of the clipped image by the number of columns and rows of the puzzle. This is rounded down so the borders width is simply the width of the image clip minus the width of the tiles multiplied by the number of columns in the puzzle. Likewise the height of the borders is simply the height of the image clip minus the hight of the tiles multiplied by the number of rows in the puzzle.
The size of the individual borders is half the size of the border. If the border is an odd size, one border needs to be a pixel bigger than the other border for whatever orientation the border represents (top/bottom or left/right). The easiest way of doing this is to make the first border the total size of the borders divided by two rounded down and the other border being equal to the size of both the borders minus the size of the first border. This way of dealing with splitting odd integers is a handy trick to remember if you have to deal with integers a lot. Using integers was something that use to be important to graphics programming (when floating point numbers were thought to be evil due to how slow non-hardware accelerated floating point was) but is not so much the case anymore.
Once the borders have been created, it is very easy to lay out the tiles as the following code segment clearly shows.
indx = 0;
for (cntrR = 0; cntrR < puzzle.puzzleHeight; ++cntrR) {
for (cntrC = 0; cntrC < puzzle.puzzleWidth; ++cntrC) {
this.tiles[indx] = new BGLayers.ImageLayer("tile"+indx, img);
rect = new BGLayers.Rectangle(left + this.tileWidth * cntrC,
top + this.tileHeight * cntrR,
this.tileWidth, this.tileHeight);
this.tiles[indx].setClip(rect);
this.addChild(this.tiles[indx], rect);
++indx;
}
}
The only problem is that the tiles are laid out in the proper order, not in the order reflected in the current state of the puzzle data. This problem had me stumped for a second or two, but then I realized that all I needed to do was move the tiles to the position they are supposed to be in. As this is something that happens every time the puzzle data changes, an update function was created to deal with this task.
PuzzleGallery.BasePuzzleView.prototype.update = function()
{
var cntrR, cntrC, indx, tile;
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
indx = 0;
for (cntrR = 0; cntrR < h; ++cntrR) {
for (cntrC = 0; cntrC < w; ++cntrC) {
tile = this.puzzle.getPuzzlePiece(cntrC, cntrR);
this.tiles[tile].moveTo( this.tileLeft + cntrC * this.tileWidth,
this.tileTop + cntrR * this.tileHeight);
this.tileBorders[indx].setCorrect(tile == indx);
++indx;
}
}
this.addDirty(null);
}
The best part is that to make the tiles animate to their new position, I can simply create an animateTo function within the BGLayers library and have all the work done for me. I don't know if I will have time to do this within the 24 hours alloted to this project, but it is certainly something that I want to add to the BGLayers library eventually.
Now that we have the puzzle being displayable, we need to get on with creating a game. That, as you have already guessed, will be covered next week.
The BasePuzzleView class has the job of displaying the puzzle. This puzzle is drawn from an image that is passed into this class. To make the game as flexible as possible, I want to be able to use only part of an image. This makes it easier to work with images that only have a partially usable portion. More important, at least in my situation, it makes it possible to maintain the proper aspect ratio for an image that is a different size than the canvas the game is going to be played in. While it is certainly possible to make the canvas a proportional size to the image being used, I like to keep my canvas a constant size. As my BGLayers library already has a rectangle class, it is simple enough to pass in a clipping region. Finally, we need the model class being displayed. With this information we have the constructor for our class.
When I started to write this class, two ways of implementing it came immediately to my mind. One way would be to have the class do all the bitmap manipulation itself when drawing. The other would be to have the class made up of a bunch of child ImageLayers that hold all the pieces of the puzzle. The first method removes a lot of overhead from having a lot of layers on the display list at a cost of a very difficult rendering process. While more efficient, speed probably is not going to be an issue whatsoever with any of the games that make up this project, so the easier to implement child path is the one I decided to go with.
The first step I then went on to implement was determining if borders were necessary. My old-school thinking was that tiles should be integers which means that it is possible for there to be borders. I was not thinking that the view is a layer that uses logical coordinates and is going to be scaled and that partial pixels are already handled by BGLayers. This is a weird lack of thinking as I am taking advantage of how BGLayers uses logical coordinates by setting the size of the layer to the size of the clipping region. Still, this is a fairly simple problem to solve. The tile size is determined by dividing width and height of the clipped image by the number of columns and rows of the puzzle. This is rounded down so the borders width is simply the width of the image clip minus the width of the tiles multiplied by the number of columns in the puzzle. Likewise the height of the borders is simply the height of the image clip minus the hight of the tiles multiplied by the number of rows in the puzzle.
The size of the individual borders is half the size of the border. If the border is an odd size, one border needs to be a pixel bigger than the other border for whatever orientation the border represents (top/bottom or left/right). The easiest way of doing this is to make the first border the total size of the borders divided by two rounded down and the other border being equal to the size of both the borders minus the size of the first border. This way of dealing with splitting odd integers is a handy trick to remember if you have to deal with integers a lot. Using integers was something that use to be important to graphics programming (when floating point numbers were thought to be evil due to how slow non-hardware accelerated floating point was) but is not so much the case anymore.
Once the borders have been created, it is very easy to lay out the tiles as the following code segment clearly shows.
indx = 0;
for (cntrR = 0; cntrR < puzzle.puzzleHeight; ++cntrR) {
for (cntrC = 0; cntrC < puzzle.puzzleWidth; ++cntrC) {
this.tiles[indx] = new BGLayers.ImageLayer("tile"+indx, img);
rect = new BGLayers.Rectangle(left + this.tileWidth * cntrC,
top + this.tileHeight * cntrR,
this.tileWidth, this.tileHeight);
this.tiles[indx].setClip(rect);
this.addChild(this.tiles[indx], rect);
++indx;
}
}
The only problem is that the tiles are laid out in the proper order, not in the order reflected in the current state of the puzzle data. This problem had me stumped for a second or two, but then I realized that all I needed to do was move the tiles to the position they are supposed to be in. As this is something that happens every time the puzzle data changes, an update function was created to deal with this task.
PuzzleGallery.BasePuzzleView.prototype.update = function()
{
var cntrR, cntrC, indx, tile;
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
indx = 0;
for (cntrR = 0; cntrR < h; ++cntrR) {
for (cntrC = 0; cntrC < w; ++cntrC) {
tile = this.puzzle.getPuzzlePiece(cntrC, cntrR);
this.tiles[tile].moveTo( this.tileLeft + cntrC * this.tileWidth,
this.tileTop + cntrR * this.tileHeight);
this.tileBorders[indx].setCorrect(tile == indx);
++indx;
}
}
this.addDirty(null);
}
The best part is that to make the tiles animate to their new position, I can simply create an animateTo function within the BGLayers library and have all the work done for me. I don't know if I will have time to do this within the 24 hours alloted to this project, but it is certainly something that I want to add to the BGLayers library eventually.
Now that we have the puzzle being displayable, we need to get on with creating a game. That, as you have already guessed, will be covered next week.
Sunday, June 12, 2011
DDTe3 Hour 1 Planning and the Puzzle Model
For the third episode of Dozen Days of Tiles, my series where I develop games with a particular theme in under 24 hours of development time, I decided to twist the concept of developing a game in a day and instead trying to develop as many games as I can within the 24 hours. I know that while the work is done in 24 hours, because the work is spread out over multiple days, it is not the same as if I did the work in a single day. Having done the Dozen Days of Dice series as game in a day stints, I know that after twelve hours of coding the mind starts working against you. That said, finding a solid day to work on something is increasingly more difficult and can be easily interrupted even if such a rare block of time can be found. I also want to document my experience in the form of these blog posts. I do not count the time I spend writing these posts towards the 24 hours but I am trying to write the posts shortly after I put in a programming stint so the thought process at the time is preserved.
Part of the reason for the desire to create multiple games for this episode is directly related to the return of a weekly format for Blazing Games. While the weekly format is more iterative than it has been in the past, allowing for games to evolve into more complex games over time, I still prefer having a buffer of material so that if a larger third-party project interrupts my site work, the schedule will not need to be adjusted.
Creating multiple games in a 24 hour period leaves the question what set of games are tile related, and have similar enough game mechanics that the work on one can be utilized in allowing the related games to be created. At the same time, I am looking at some of the older games on the Blazing Games site and am trying to figure out what should be done with them. The Flash games can be enhanced as Flash is going to be around for a while yet. The Java games, sadly, are in a more precarious position so consideration should be made towards porting them to HTML5. Looking at some of the Java games that I have done, I noticed my picture puzzle series of games. These are simple enough games that I don't need to port the games at all but can instead re-write them from scratch without loosing that much time. In fact, with all the knowledge that I have gained over the years, I should be able to get the core picture puzzle game functional very quickly.
With the game in mind, it is time to start on the project. While having a client-model-view architecture is probably a bit of overkill for this series, it doesn't hurt so I will start by creating the model. This class is being called BasePuzzleModel in the project.
The model creates a two-dimensional array to hold the grid. In JavaScript, 2D arrays are created by making an array of arrays. The model could have also simply created a single array the size of the width times the height of the grid and mathematically determined the position of the tile. I chose to go with the the two-dimensional approach because that way the internal structure of the grid more closely matches the problem being solved. Still, as the tiles are then assigned linear values to represent their proper position, in hindsight going with a single dimensional array would have been easier and just as logical. As I write this, I am only 6 hours into the project and could change things but as the internal structure of the model is theoretically hidden from the classes that use it there would be no point changing it.
As briefly explained in the paragraph above, each tile is assigned an index value that is linear based on the row and column. The index is equal to the row * the width of the puzzle plus the column. By having the linear sequence of tile values, it is possible to easily determine if the puzzle is correct by simply seeing if the tiles are in order. Some simple convenience functions were created for manipulating the puzzle and within an hour we have the model up and running. The functions added were getPuzzlePiece(x,y), setPuzzlePiece(x,y, n), swapPuzzlePieces(x1,y1,x2,y2), scrambleBoard() and checkWin(). These are all fairly straightforward so I won’t delve into the details of these.
The next phase is to turn the model into something visible. The obvious class for this job would be something called the BasePuzzleView, which we will look at next week.
Part of the reason for the desire to create multiple games for this episode is directly related to the return of a weekly format for Blazing Games. While the weekly format is more iterative than it has been in the past, allowing for games to evolve into more complex games over time, I still prefer having a buffer of material so that if a larger third-party project interrupts my site work, the schedule will not need to be adjusted.
Creating multiple games in a 24 hour period leaves the question what set of games are tile related, and have similar enough game mechanics that the work on one can be utilized in allowing the related games to be created. At the same time, I am looking at some of the older games on the Blazing Games site and am trying to figure out what should be done with them. The Flash games can be enhanced as Flash is going to be around for a while yet. The Java games, sadly, are in a more precarious position so consideration should be made towards porting them to HTML5. Looking at some of the Java games that I have done, I noticed my picture puzzle series of games. These are simple enough games that I don't need to port the games at all but can instead re-write them from scratch without loosing that much time. In fact, with all the knowledge that I have gained over the years, I should be able to get the core picture puzzle game functional very quickly.
With the game in mind, it is time to start on the project. While having a client-model-view architecture is probably a bit of overkill for this series, it doesn't hurt so I will start by creating the model. This class is being called BasePuzzleModel in the project.
The model creates a two-dimensional array to hold the grid. In JavaScript, 2D arrays are created by making an array of arrays. The model could have also simply created a single array the size of the width times the height of the grid and mathematically determined the position of the tile. I chose to go with the the two-dimensional approach because that way the internal structure of the grid more closely matches the problem being solved. Still, as the tiles are then assigned linear values to represent their proper position, in hindsight going with a single dimensional array would have been easier and just as logical. As I write this, I am only 6 hours into the project and could change things but as the internal structure of the model is theoretically hidden from the classes that use it there would be no point changing it.
As briefly explained in the paragraph above, each tile is assigned an index value that is linear based on the row and column. The index is equal to the row * the width of the puzzle plus the column. By having the linear sequence of tile values, it is possible to easily determine if the puzzle is correct by simply seeing if the tiles are in order. Some simple convenience functions were created for manipulating the puzzle and within an hour we have the model up and running. The functions added were getPuzzlePiece(x,y), setPuzzlePiece(x,y, n), swapPuzzlePieces(x1,y1,x2,y2), scrambleBoard() and checkWin(). These are all fairly straightforward so I won’t delve into the details of these.
The next phase is to turn the model into something visible. The obvious class for this job would be something called the BasePuzzleView, which we will look at next week.
Sunday, June 5, 2011
DDTe2 hours 16 to 17 Infinite Loop Bug
This is the final installment of my making of Dozen Days of Tiles episode 2. At this point in time, the game has been created but a showstopper bug has been discovered.
Finding bugs is never nice, but the very nature of programming makes bugs pretty much an inevitable thing. Bugs are often the result of a very minor mistake, such as was the case with this bug. Thankfully, with tools such as FireBug available, finding the cause of the bug was very easy. By being able to stop the program while it was in an infinite loop allowed me to take a look at the puzzle data at the time the infinite loop was happening which is where I discovered that the puzzle generation would occasionally result in a puzzle that had invalid data in it.
The solution to this problem was to add a sanity check to the fifth phase of the puzzle generation. Instead of simply returning the finished puzzle, phase 5 added the following puzzle verification checking code:
var cntrRow, cntrCol;
done = true; // assume valid until proven otherwise
for (cntrRow = 1; cntrRow < 10; ++cntrRow)
for (cntrCol = 1; cntrCol < 10; ++cntrCol)
if (this._model.getValue(cntrRow, cntrCol) == 0)
done = false;
if ( ! done )
this._phase = 1;
Problem solved. Many programmers would consider their job done. Good programmers, and those who want to become good programmers, know that there is still a bug in the code. This is when a serious look at the puzzle generation phases happens. I like to try and work through what the code is doing to find puzzles, though certainly walking through the code using breakpoints and stepping over/through statements will work.
As I worked through the code in my head, the problem hit me like a flying brick. What a dumb mistake! Setting the phase back to 1 when there is an error is fine, but for some reason, I also set it to the next phase if the row is valid. The next phase change should not happen until after all three rows in the phase have been successfully completed. When I wrote the code I was thinking that I was at the end of the generation, not just the end of the loop. A simple mistake, but that is all it takes.
What was happening was that the first or second row would not be able to generate a valid combination that would work with the puzzle. The loop would continue and if the last row was able to generate a valid combination then the next phase would be triggered. The real bug fix, then, is to take the next phase setting out of the row loop (which it shouldn’t have been in to begin with) and only go to the next phase if the phase has not been set to 1. Likewise, because there may be more iterations in the row loop, when the puzzle is invalid, the row loop should be broken out of.
The problem solved means that the project is finished. For the next episode, I am considering putting a twist on the game in a day challenge. Instead of developing a game in under 24 hours (development time not real time) I am going to instead see how many games I can create in under 24 hours.
Finding bugs is never nice, but the very nature of programming makes bugs pretty much an inevitable thing. Bugs are often the result of a very minor mistake, such as was the case with this bug. Thankfully, with tools such as FireBug available, finding the cause of the bug was very easy. By being able to stop the program while it was in an infinite loop allowed me to take a look at the puzzle data at the time the infinite loop was happening which is where I discovered that the puzzle generation would occasionally result in a puzzle that had invalid data in it.
The solution to this problem was to add a sanity check to the fifth phase of the puzzle generation. Instead of simply returning the finished puzzle, phase 5 added the following puzzle verification checking code:
var cntrRow, cntrCol;
done = true; // assume valid until proven otherwise
for (cntrRow = 1; cntrRow < 10; ++cntrRow)
for (cntrCol = 1; cntrCol < 10; ++cntrCol)
if (this._model.getValue(cntrRow, cntrCol) == 0)
done = false;
if ( ! done )
this._phase = 1;
Problem solved. Many programmers would consider their job done. Good programmers, and those who want to become good programmers, know that there is still a bug in the code. This is when a serious look at the puzzle generation phases happens. I like to try and work through what the code is doing to find puzzles, though certainly walking through the code using breakpoints and stepping over/through statements will work.
As I worked through the code in my head, the problem hit me like a flying brick. What a dumb mistake! Setting the phase back to 1 when there is an error is fine, but for some reason, I also set it to the next phase if the row is valid. The next phase change should not happen until after all three rows in the phase have been successfully completed. When I wrote the code I was thinking that I was at the end of the generation, not just the end of the loop. A simple mistake, but that is all it takes.
What was happening was that the first or second row would not be able to generate a valid combination that would work with the puzzle. The loop would continue and if the last row was able to generate a valid combination then the next phase would be triggered. The real bug fix, then, is to take the next phase setting out of the row loop (which it shouldn’t have been in to begin with) and only go to the next phase if the phase has not been set to 1. Likewise, because there may be more iterations in the row loop, when the puzzle is invalid, the row loop should be broken out of.
The problem solved means that the project is finished. For the next episode, I am considering putting a twist on the game in a day challenge. Instead of developing a game in under 24 hours (development time not real time) I am going to instead see how many games I can create in under 24 hours.
Sunday, May 29, 2011
DDTe2 hours 14 to 15 Fine Tuning
This is the second to last article for my series on the creation of Dozen Days of Tiles episode 2: Sudoku Generator. Earlier posts covered the creation and hiding of the puzzle. The final game is on Blazing Games and is located at http://blazinggames.com/table/dozenDays/tiles/sudokuGen.php.
To support multiple puzzles with the Sudoku Player, the URL has a data parameter that contains 81 characters that represent the puzzle data. The .php page has code that converts the letters into the initial board data statements that the player uses. This coding uses letters to represent the numbers with the letters being in a random order to make it really difficult for a human to look at the URL and figure out the solution to the puzzle. To generate this encoding, I wrote a simple function to convert the grid into a 81 character encoded string.
SudokuGen.ENCODE = "JBLAKIRNEFPSMCOGDTQH";
SudokuGen.Model.prototype.getEncoded = function()
{
var encode = "";
var value, cntrRow, cntrCol;
for (cntrRow = 1; cntrRow < 10; ++cntrRow)
for (cntrCol = 1; cntrCol < 10; ++cntrCol) {
value = this.tileGrid[cntrRow][cntrCol];
if (this.lockGrid[cntrRow][cntrCol] == true)
value += 10;
encode += SudokuGen.ENCODE.substr(value, 1);
}
return encode;
}
Just being able to use the player isn’t quite enough. I also want to make the puzzles printable so that they can be printed out on paper to be solved. As the puzzle really is just nested tables, this can be done entirely with the HTML table tags. This requires working with the awful DOM classes, but really is fairly simple. Essentially, the puzzle is a 3x3 table with each table in the puzzle being a 3x3 table that contains the group data.
function writePuzzle(model)
{
var puzzle = document.getElementById('puzzle');
var cntrRow, cntrCol, cntrGroup, cntrSec;
var groupTable, temp, grow, gcell;
// top three groups
for (cntrSec = 0; cntrSec < 3; ++cntrSec) {
prow = puzzle.insertRow(cntrSec);
for (cntrGroup = 0; cntrGroup < 3; ++cntrGroup) {
pcell = prow.insertCell(cntrGroup);
groupTable = document.createElement("table");
groupTable.border = "1";
groupTable.cellPadding = "5";
for (var cntrRow = 0; cntrRow < 3; ++cntrRow) {
grow = groupTable.insertRow(cntrRow);
for (var cntrCol = 0; cntrCol < 3; ++cntrCol) {
gcell = grow.insertCell(cntrCol);
temp = model.getPuzzleValue(cntrRow+cntrSec*3+1, cntrCol+cntrGroup*3+1);
if (temp > 10)
gcell.innerHTML = "" + (temp - 10);
else
gcell.innerHTML += " ";
}
}
pcell.appendChild(groupTable);
}
}
var msg = document.getElementById('waitText');
msg.innerHTML = ""+ playerMessage + "";
}
As generating the puzzle can take some time, my final touch was a please wait message which is animated as the generation passes happen. When the generation is done, this gets replaced by the Sudoku Player URL.
Of course, this is the point when I discover a game-stopper bug. It seems that occasionally the puzzle generation locks up. If you have been following along with this series of articles, you already know that the problem was my next phase being prematurely set allowing an occasional invalid game to be treated as a valid puzzle. This was a very easy bug to fix but a bit harder to figure out. In fact, I had a working fix in a matter of minutes but it took me a couple of hours to actually figure out what the real problem was. That story will be told next week.
To support multiple puzzles with the Sudoku Player, the URL has a data parameter that contains 81 characters that represent the puzzle data. The .php page has code that converts the letters into the initial board data statements that the player uses. This coding uses letters to represent the numbers with the letters being in a random order to make it really difficult for a human to look at the URL and figure out the solution to the puzzle. To generate this encoding, I wrote a simple function to convert the grid into a 81 character encoded string.
SudokuGen.ENCODE = "JBLAKIRNEFPSMCOGDTQH";
SudokuGen.Model.prototype.getEncoded = function()
{
var encode = "";
var value, cntrRow, cntrCol;
for (cntrRow = 1; cntrRow < 10; ++cntrRow)
for (cntrCol = 1; cntrCol < 10; ++cntrCol) {
value = this.tileGrid[cntrRow][cntrCol];
if (this.lockGrid[cntrRow][cntrCol] == true)
value += 10;
encode += SudokuGen.ENCODE.substr(value, 1);
}
return encode;
}
Just being able to use the player isn’t quite enough. I also want to make the puzzles printable so that they can be printed out on paper to be solved. As the puzzle really is just nested tables, this can be done entirely with the HTML table tags. This requires working with the awful DOM classes, but really is fairly simple. Essentially, the puzzle is a 3x3 table with each table in the puzzle being a 3x3 table that contains the group data.
function writePuzzle(model)
{
var puzzle = document.getElementById('puzzle');
var cntrRow, cntrCol, cntrGroup, cntrSec;
var groupTable, temp, grow, gcell;
// top three groups
for (cntrSec = 0; cntrSec < 3; ++cntrSec) {
prow = puzzle.insertRow(cntrSec);
for (cntrGroup = 0; cntrGroup < 3; ++cntrGroup) {
pcell = prow.insertCell(cntrGroup);
groupTable = document.createElement("table");
groupTable.border = "1";
groupTable.cellPadding = "5";
for (var cntrRow = 0; cntrRow < 3; ++cntrRow) {
grow = groupTable.insertRow(cntrRow);
for (var cntrCol = 0; cntrCol < 3; ++cntrCol) {
gcell = grow.insertCell(cntrCol);
temp = model.getPuzzleValue(cntrRow+cntrSec*3+1, cntrCol+cntrGroup*3+1);
if (temp > 10)
gcell.innerHTML = "" + (temp - 10);
else
gcell.innerHTML += " ";
}
}
pcell.appendChild(groupTable);
}
}
var msg = document.getElementById('waitText');
msg.innerHTML = ""+ playerMessage + "";
}
As generating the puzzle can take some time, my final touch was a please wait message which is animated as the generation passes happen. When the generation is done, this gets replaced by the Sudoku Player URL.
Of course, this is the point when I discover a game-stopper bug. It seems that occasionally the puzzle generation locks up. If you have been following along with this series of articles, you already know that the problem was my next phase being prematurely set allowing an occasional invalid game to be treated as a valid puzzle. This was a very easy bug to fix but a bit harder to figure out. In fact, I had a working fix in a matter of minutes but it took me a couple of hours to actually figure out what the real problem was. That story will be told next week.
Subscribe to:
Posts (Atom)