Previous Blog Next Blog
Prev/Next Blog
by date

slower day

slower day
Name:J Sears 
Date Posted:Nov 20, 2006
Rating:3.0 out of 5
Public:YES
Comments:YES
RSS Feed:GarageGames Blog feedor Subscribe with .
Profile Page:View profile page for J Sears

Blog post
Well I did not get as much accomplished today as I had hoped. For starters I ended up rewriting my automatic card movement to the suit pile code. And once I had it written up the way I wanted something just wasn't working right, I reread the code a dozen times did find a couple tiny mistakes but they weren't the solution, I started adding echoes in to hunt down the problem, still couldn't figure out what it was and finally echoed out all of the values in an array I was working with through ever step of the function. The solution I finally came up with: I had a large misunderstanding on local vs global variables. I thought local just meant only used in that function. But apparently it also means when you leave that function and recall that function again those values are gone. Good to know. So I switched my array to global values and magically my code worked. That cost me a couple hours.
So after that I did some easy things, I added a timer to my game. That took about 3 minutes and worked perfect on first time around. I then began reading read write functions and how to use them and also researched FreeCell levels or games as most places write them but for ease of confusion I will call them levels. It seems that with the standard freecell game (there's many different variations) 99.999 and on are beatable games when created randomly. One site overly dedicated to the history of freecell showed a study done of the 1 million games on microsofts freecell which were randomly created I think he said 137 are not beatable. This was determined by people who are creating FreeCell solvers. From all the information I got on FreeCell solvers I am in no shape to write one, they are extremely complex and apparently a "perfect" one has not been created yet with all the efforts. If people who went to school for these kinds of things and have years of experience in them can't do it then I'm guessing I can't. There goes my AI in freecell idea. But the good that came of that is giving up on the idea of making sure all my games are winnable so I started on a randomizer to create levels.

The randomizer went together very easy with one snag, I tried to create a for loop that counted down instead of up and torque script seemed to hate that. So after many times of trying to figure out why my randomize function was not randomizing anything I switched that around and bang random. The way I set up a randomizer was to make an array of 52 spots 1 for each card, I entered the ImageData name of my cards as the information and I then had a for loop get a random number take the card in that random number and store it in card. Then I had a seperate value that was essential 51 - %i. that did 2 things set the limit for my random number and keep track of my spot in the array because how I did it was basically a shuffle, get random number take card from that spot and swap it with last spot in array and count down till all cards were moved.

Once I had that working good I created another function to read write the levels. Had a global variable of currentLevel which was for 1 thing. The first number to get written to the file so I can hopefully set up a read later when someone enters a game number to jump to the right spot and get the card order. I also had a variable to turn on and off the shuffler so I could get all the card spots out write to a file and then turn on the shuffler for a new level. I tested it by outputting 3 levels and it worked perfect.
Now my big challenge on this. First I only know of writeline which in my spot is annoying because it starts on next line everytime. since I am using a for loop to get the values out of the array that gives me 52 seperate lines instead of 1 line with all 52 in it. This is something I haven't found a solution to. Now I want to do 2 things. Create a read system that then loads in the level. And create a read system while making the levels to go through the previous levels and make sure it's not a repeat before writing it. These 2 tasks will share a lot of code so when I have one all figured out I will hopefully be close to the other. My over all plan with the levels is to do 2-3 million levels (want to at least be better then microsoft) that all have a game number. Then remove the level creation functions and hopefull have my read functions down and just focus on all the gui aspects.

To do list
read functions
housekeeping of some code (I currently decided that is at least 4 lines of code are shared by 2 or more
functions that I put them in their own function that might be excessive but I like the neatness)
Work on a way of checking if no possible moves remain and let player know game over (all freecells
have this)
Work on allowing player to move a column of successive cards (if you've played freecell you know what
I mean) this will mean adding a function to keep track of open spaces and columns and checking
when a player clicks if the stack is successive so this will be a bit of code
Add right click to see under cards, microsoft has this should be as simple as onRightMouseDown move
card to layer 0 onRightMouseUp move it back to it's old Layer.

that should keep me busy for a while and thanks for the help so far David

Recent Blog Posts
List:01/25/08 - persistance is rewarding
08/28/07 - My thoughts, and my farewell
05/23/07 - some progress on cards
04/23/07 - teaching my computer to play cards
01/03/07 - I'm not dead
12/06/06 - time to learn networking
12/05/06 - back on a decent pace
12/04/06 - back at it

Submit ResourceSubmit your own resources!

Allyn "Mr_Bloodworth" Mcelrath   (Nov 20, 2006 at 21:59 GMT)
Thats a slow day?

David Higgins   (Nov 20, 2006 at 21:59 GMT)   Resource Rating: 3
@J, you could circumvent the WriteLine by creating a dynamic string in your for loop, then at the end of the loop, WriteLine(%string) to the file ... so basically:


%string = '';
for(...)
{
%string = // ...
}
%fileObj.WriteLine(%string);


Also, you may look at the SimSet or SimGroup objects -- for example;


$CARD_TYPE_HEART = 0;
$CARD_TYPE_CLUB = 1;
$CARD_TYPE_DIAMOND = 2;
$CARD_TYPE_SPADE = 3;

// $CARD_VALUE_1 -> $CARD_VALUE_10 can be created, or just assumed Static ;)
// the $CARD_VALUE_J-A is useful in case statements
// to perform specific logic based on those cards, usually 1-10 are not
// special in any way, so there's no need to pre-define them for code readability
$CARD_VALUE_J = 11;
$CARD_VALUE_Q = 12;
$CARD_VALUE_K = 13;
$CARD_VALUE_A = 0; // Ace is first, or last? :)

datablock t2dSceneObjectDatablock(CardDataBlock)
{
size = "256 256";
//imageMap = someValidImageMapContainingYourCardImagesPreSorted
cardFace = $CARD_TYPE_HEART;
cardValue = $CARD_VALUE_A;
};

$cardDeck = new SimSet();

for(%x = 0; %x < 4; %x++)
{
for(%y = 0; %y < 14; %y++)
{
%card = new t2dSceneObject()
{
defaultConfig = CardDataBlock;
cardFace = %x;
cardValue = %y;
frame = %x * %y; // your image map should be sorted to perform this!
};
$cardDeck.add(%card);
}
}

// test script
echo("Test Script One: Ordered");
for(%x = 0; %x < $cardDeck.getCount(); %x++)
{
%card = $cardDeck.getObject(%x);
echo("Card: " @ %card.cardValue @ " -- FACE: " @ %card.cardFace);
}

// now to randomize the card deck
$cardDeckSorter = $cardDeck;
$cardDeck = new SimSet();
while($cardDeckSorter.getCount() > 0)
{
%card = $cardDeckSorter.getObject(getRandom(0, $cardDeckSorter.getCount()-1));
$cardDeck.add(%card);
$cardDeckSorter.remove(%card);
}

// test script
echo("\r\n\r\n");
echo("Test Script Two: Sorted");
for(%x = 0; %x < $cardDeck.getCount(); %x++)
{
%card = $cardDeck.getObject(%x);
echo("Card: " @ %card.cardValue @ " -- FACE: " @ %card.cardFace);
}


The code in that script, was saved to a cardSorter.cs file, and then simply exec()'d in the game.cs and executed -- there are two "test scripts" included, which show the way the card deck was after creation, and how it was after sorting.

The initial code, that create's the deck dynamically, does not need to be called ever again -- the deck can be randomized after being randomized, which would probably make the deck even more random --

The reason I used the SimSet and a datablock, was so that your card "array" could actually contain your actual card as well -- so if you fix up the datablock, and the %card = new t2dSceneObject() {}; block ... you can easily add your card graphic, etc -- otherwise, you can just use the code as is ...

If you don't attach the graphics and what not to the deck, then you can probably remove the datablock reference, and just create new t2dSceneObject's and add the cardFace and cardValue fields to it at creation --

David Higgins   (Nov 20, 2006 at 22:49 GMT)   Resource Rating: 3
@J, after writing that quicky card sorter code, I'm now interested in writing a very simple and basic solitaire or poker game -- would you by chance have any art resources or links to art resources I could use? (I'm a dev, not an artsit ... )

David Higgins   (Nov 20, 2006 at 23:13 GMT)   Resource Rating: 3
UPDATE: Found a set of pre-made card images in one of the art resources I downloaded previously --

J Sears   (Nov 20, 2006 at 23:19 GMT)
@allyn ya I was making so much progress the previous days yesterday felt slow with the wall I hit for a while trying to figure things out, today is going very similar

@david I got cards from http://www.jfitz.com/cards/ but they're all individual cards so you'd have to combine them all if you want to make it easier that way, I've just been dealing with them seperated for now

I did end up using the string method (figured it out before I came back on to check this) worked out good I got the randomizer writing and check the previous lines all set up and let the machine go. It created I think 37000 unique games in 20 minutes before TGB crashed, the way I had it set up must have been leaving too much in memory, so I'll just add more games later. I seem to have the read file working fine too but here's my problem I'm using this


%card =  new t2dSceneObject() {
scenegraph = t2dScene.SceneGraph;
imageMap = "n11";
frame = "0";
canSaveDynamicFields = "1";
position = "0 0";
Layer = %cardLayer;
MountInheritAttributes = "0";
cardValue = "1";
cardSuit = "1";
cardColor = "1";
};
%card.mount(%cardMount,0,0.5,0,false,false,false,false);


to try and load each image and mount it to it's correct spot but it makes the object gives it an object number but when it goes to mount says error object is not in scene and I can't for the life of me figure out the problem

oh and for my game list file I didn't exec it in I just did OpenForRead and then since each game number is on a seperate line I just do %temp=%file.readline() and then keep a counter and when that counter hits the level number I have %level=%temp. Not sure if that's the best way to do it but seems to do ok

J Sears   (Nov 20, 2006 at 23:22 GMT)
And it would all be easier if I didn't need specified game levels but FreeCell players prefer that so they can compare how they did on different games, another card game I have working out in my mind while I finish up this one will be much easier in that aspect. And I think I may have finally thought of a way to get these cards setup right but will still look forward to see if youc an spot what's wrong in my code if my new idea doesn't wotk.

David Higgins   (Nov 21, 2006 at 00:56 GMT)   Resource Rating: 3
change 't2dScene.SceneGraph' to 'sceneWindow2D.getSceneGraph()' -- you'll notice in either main.cs or game.cs that the sceneWindow2D object is created and is a t2dSceneWindow object, which contains a scenegraph --

as for the file stuff, not really sure -- I can look into the file objects in TGB and see what some alternatives are -- most file objects in other langauges have some form of 'seek' ability, which would be dramatically better then reading each line until you get to the one you want -- especially if you randomly generate 1,000,000 games -- just imagine waiting for 999,999 to load ;)

David Higgins   (Nov 21, 2006 at 01:11 GMT)   Resource Rating: 3
@J -- just looked at the FileObject and the Console File IO functionality and neither seem to have a seek ability -- perhaps there's a C++ mod resource that adds this, or perhaps someone could write one.

J, are you a Pro or Indie licensee?

J Sears   (Nov 21, 2006 at 01:49 GMT)
Indie, didn't want to mess with source code yet. I went a different approach and it all works except for some reason the cards don't show up but when I stop the program the TGB now shows all the cards stacked in the right spots right order right layers. It is very confusing.


$levelNumber=50;
function createLevel()
{
%file= new FileObject();
%file.OpenForRead("~/data/levels/levels.cs");
for(%i=0;%i<$levelNumber;%i++)
%level=%file.readline();

//set array values to 0
for(%i=0;%i<8;%i++)
{
%columns[%i]=%i;
}

%objCount = t2dScene.getSceneObjectCount();
%objList = t2dScene.getSceneObjectList();
%columnCounter = 1;

//setup the starting 8 column markers, after those the cards themselves will be used
for(%i=0;%i<%objCount;%i++)
{
%obj= getWord(%objList, %i);
if(%obj.isColumn == %columnCounter)
{
%spot = %columnCounter - 1;
%columns[%spot] = %obj;
echo("this is the obj that should be in there now", %obj);
%columnCounter++;
echo(%columns[%spot], "this is the object in the column starting spot");
}
if(%columnCounter==9)
%i=%objCount;
}
%columnCounter = 0;
%layerCounter = 15;
%number = getWordCount(%level);
//let's mount those cards
for(%i=0;%i<%number;%i++)
{

for(%j=0;%j<%objCount;%j++)
{
%obj = getWord(%objList, %j);
%currentWord = getWord(%level, %i);
if(%obj.imageMap $= %currentWord)
{
%obj.Layer = %layerCounter;
%mountPoint = %columns[%columnCounter];
echo(%mountPoint, "this should be the same objects as above");
%obj.mount(%mountPoint,0,0.5,0,false,false,false,false);
%columns[%columnCounter]=%obj;
%columnCounter++;
if(%columnCounter==8)
{
%layerCounter--;
%columnCounter=0;
}
%j=%objCount;
}

}
}
}


I keep looking over it and just can't figure out why it would mount all the objects in the right spot and they're all layers 15 and up where the background is layer 31, and the background shows up. Never thought I'd pull that off. And all the objects are checked visible in the game builder.

Ya a seek would be good but for this operation a quick receive line loop shouldn't cause too much slow down, a more major game maybe.

J Sears   (Nov 21, 2006 at 02:02 GMT)
had to reorganize the way things got called in game.cs, solutions always come once I walk away for a bit.

David Higgins   (Nov 21, 2006 at 02:40 GMT)   Resource Rating: 3
@J, I always find the solution to the problem to come to me when I'm making myself food -- go figure, eh?

Scrambling some eggs and all of a sudden it's like "Ohhhhh ...." -- sucks when you run over to the computer to try it out and forget the foods still cooking :)

J Sears   (Nov 21, 2006 at 03:52 GMT)
I have done that before though not with coding yet, but I'm sure it will come. Normally it happens if I have a pizza in the oven.

Tank Dork   (Nov 22, 2006 at 08:01 GMT)
J. I have been failthfully following your progress. Your logs have helped me tremendously. I have been slowly working on converting an old card game I invented years ago and wrote in C++ over to a graphical version on TGB. I get easily confussed with what torque script is trying to do sometimes and your play by play (and David's posts!) have turned on the proverbial lightbulb several times.

You and David might consider posting some of your finds as resources or a tutorial for the basics of starting a card game in TGB (the match game is only one.. and it is not alot of help). I plan on doing this when I get mine working but you guys are light years ahead of me it seems.

David Higgins   (Nov 22, 2006 at 12:38 GMT)   Resource Rating: 3
@Tank, shhh -- don't spoil the surprise just yet :)

You must be a member and be logged in to either append comments or rate this resource.