Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

xelhark

macrumors newbie
Original poster
Jul 16, 2010
7
0
Hi there!

I was working on a Sudoku Generator. While trying different approaches i tried to create a Tree in which every node contains a partial generation, and if it can't go on that node is bounded. Eventually it should find a solution.

The algorithm is not the problem, just take a look at this!


Code:
-(void) solve{
	ConstraintGraph *g = [[ConstraintGraph alloc] initAsSudoku];
	
	SolutionTree *tree = [[SolutionTree alloc] init];

	tree.root->info = (Node*)(g.nodeList->Head->info);
	
	tree.root->info->n = 3;
	NSLog(@"the value is %d", tree.root->info->n);
 * * * *//this prints 'the value is 3'
	[self visitNode:tree.root];
	
}

-(void) visitNode:(solutionTreeNode*)N{
 * * * *//this prints 'the value is 1296' (or another number)
	NSLog(@"he value is %d", N->info->n);
}


The first NSLog prints
Code:
the value is 3

the second one (in visitNode) prints:

Code:
the value is 1456
or other random numbers..

I think the problem happens when i pass the variable, but i couldn't figure it out. Could you please help me? :confused:

Thanks in advance :p
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
Are there any warnings when you compile this? Are all the declarations in scope?

Otherwise it's difficult to guess without seeing the declarations for all the relevant bits. I'll also say it's a bit weird to see the -> operator mixed with Objective-C classes, but legit if you know what you're doing.
 

xelhark

macrumors newbie
Original poster
Jul 16, 2010
7
0
Are there any warnings when you compile this? Are all the declarations in scope?

Nope, no warning, nothing at all..

Otherwise it's difficult to guess without seeing the declarations for all the relevant bits. I'll also say it's a bit weird to see the -> operator mixed with Objective-C classes, but legit if you know what you're doing.
Actually i'm using Objective-C++ which lets me use structs and lists rather than NSMutableArrays (i'm trying to make it as fast as i can), and that's why i'm using -> operator

anyway, i tried to take a better look at it, and it might be some casting problem..

I isolated it here..
Code:
	ConstraintGraph *g = [[ConstraintGraph alloc] initAsSudoku];
	NSLog(@"The value is %d", ((Node*)(g.nodeList->Head->info))->n);

The ConstraintGraph is a graph in which a node is connected to another node if they must have different values. (for example, a node is connected with all of the other nodes in his row, column and 3x3 subgrid)


anyway, the NSLog here prints
'The value is [random number]'

This is the code from the 'initAsSudoku' method.

Code:
-(id) initAsSudoku{
	if ((self = [super init])) {
		Node Nodi[SUDOKUSIZE][SUDOKUSIZE];
		for (int i=0; i<SUDOKUSIZE; i++) {
			for (int j=0; j<SUDOKUSIZE; j++) {
				Nodi[i][j].Adjs = new myList();
				//-----------------HERE I AM INITIALIZING THE n AS 0
				Nodi[i][j].n = 0;
			}
		}	
		
		/*
		 You can skip this part, it just creates the connections
		 */
		for (int i=0; i<SUDOKUSIZE; i++) {
			for (int j=0; j<SUDOKUSIZE; j++) {
				//Adding Constraints...
				//The first SUDOKUSIZE-1 (except itself) are the ones from its subgrid
				for (int k=0; k<SUDOKUSIZE; k++) {
					int x = (((i/sizeX)*sizeX)+(k%3));
					int y = (((j/sizeY)*sizeY)+(k/3));
					if (x!=i || y != j) {
						Nodi[i][j].Adjs->addNodeContaining(&Nodi[x][y]);
					}
				}
				//The others are from its row/column (except the ones in the subgrid)
				for (int k=0; k<SUDOKUSIZE; k++) {
					if (k/sizeX != i/sizeX) {
						Nodi[i][j].Adjs->addNodeContaining(&Nodi[k][j]);
					}
					if (k/sizeY != j/sizeY) {
						Nodi[i][j].Adjs->addNodeContaining(&Nodi[i][k]);
					}
				}
			}
		}
		/*
		 Here all connections are created, i store the nodes in a list then return
		 */
		nodeList = new myList();
		//Adding nodes in the list..
		for (int i=0; i<SUDOKUSIZE; i++) {
			for (int j=0; j<SUDOKUSIZE; j++) {
				nodeList->addNodeContaining(&Nodi[i][j]);
			}
		}
		NSLog(@"The value is %d", ((Node*)(self.nodeList->Head->info))->n);
	}
	return self;
}

The list holds a (void*) as info, that's why i need the cast.

The weird thing is, the NSLog here prints '0' (the right value). Once the code returns to the first method, the VERY SAME instruction prints another value (random)
:eek:
i don't know what to do please help :(
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
Remember that NSLog is a varargs method and it doesn't really know the types of the values passed to it. You can put a typecast in the NSLog to help it with the type, like:

Code:
NSLog(@"The value is %d", (int)((Node*)(g.nodeList->Head->info))->n);
Otherwise what happens with something like

Code:
NSInteger d = (g.nodeList->Head->info)->n;
NSLog(@"The value is %d", d);
 

chown33

Moderator
Staff member
Aug 9, 2009
10,740
8,416
A sea of green
Code:
		/*
		 Here all connections are created, i store the nodes in a list then return
		 */
		[COLOR="Red"]nodeList[/COLOR] = new myList();
		//Adding nodes in the list..
		for (int i=0; i<SUDOKUSIZE; i++) {
			for (int j=0; j<SUDOKUSIZE; j++) {
				nodeList->addNodeContaining(&Nodi[i][j]);
			}
		}
		NSLog(@"The value is %d", ((Node*)([COLOR="Red"]self.nodeList[/COLOR]->Head->info))->n);
	}
	return self;
}

First, you need to post the datatypes: struct definitions, class headers, properties, etc. We can't tell what anything is except by guessing from context. There isn't enough context to determine what's really happening.

Second, assuming that nodeList is both an ivar and a property, you are accessing the property in two different ways (red hilited code). This may be a problem if your property is defined as retain, but you don't consistently use the property accessors.

So my guess is that you somehow have a variable being deleted or dealloc'ed, yet you still have a reference to it, but without seeing more of the data types and properties, it's just a guess.


In general, the debugging strategy to use is Bracketing. You set a breakpoint before or at the initFunction. You inspect the variables. You set another breakpoint at the end of the function. Inspect variables again. Set a third breakpoint right before the printing that doesn't work. Inspect variables yet again, and then single-step only if they're correct.

If all the variables (and the memory they point to) is always correct, and the print works, then expand the range bracketed by the breakpoints. If the 2nd or 3rd breakpoint shows incorrect variables (or memory), then move the breakpoint earlier or later, so there are always 2 breakpoints bracketing a suspected section of code. You will eventually find the statement that's wrong as you move the breakpoint past it.

You can move the 1st breakpoint later, as you find that a bracketed section of code is correct. The 1st breakpoint establishes your "known good" state. The other 2 move as you search for the point at which it goes bad.
 

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
Nope, no warning, nothing at all..


Actually i'm using Objective-C++ which lets me use structs and lists rather than NSMutableArrays (i'm trying to make it as fast as i can), and that's why i'm using -> operator

Are you kidding? Do you know how powerful the iPhone is when compared to the small differences in speed between C++ and Obj-C messaging?

Smells like premature optimization to me.
 

xelhark

macrumors newbie
Original poster
Jul 16, 2010
7
0
First, you need to post the datatypes: struct definitions, class headers, properties, etc. We can't tell what anything is except by guessing from context. There isn't enough context to determine what's really happening.

Second, assuming that nodeList is both an ivar and a property, you are accessing the property in two different ways (red hilited code). This may be a problem if your property is defined as retain, but you don't consistently use the property accessors.

So my guess is that you somehow have a variable being deleted or dealloc'ed, yet you still have a reference to it, but without seeing more of the data types and properties, it's just a guess.


In general, the debugging strategy to use is Bracketing. You set a breakpoint before or at the initFunction. You inspect the variables. You set another breakpoint at the end of the function. Inspect variables again. Set a third breakpoint right before the printing that doesn't work. Inspect variables yet again, and then single-step only if they're correct.

If all the variables (and the memory they point to) is always correct, and the print works, then expand the range bracketed by the breakpoints. If the 2nd or 3rd breakpoint shows incorrect variables (or memory), then move the breakpoint earlier or later, so there are always 2 breakpoints bracketing a suspected section of code. You will eventually find the statement that's wrong as you move the breakpoint past it.

You can move the 1st breakpoint later, as you find that a bracketed section of code is correct. The 1st breakpoint establishes your "known good" state. The other 2 move as you search for the point at which it goes bad.

Uhm... You're right, i didn't think of it, i'll check it out and let you know.. Thanks a lot ;)



Are you kidding? Do you know how powerful the iPhone is when compared to the small differences in speed between C++ and Obj-C messaging?

Smells like premature optimization to me.
Actually, i once tried using a NSMutableArray for things like that, and it came up being really really slow compared to this kind of lists, but maybe there were other things slowing it down.. I'm not sure, and i'm pretty new to Objective-C and iPhone programming, so if you think it's faster to use NSMutableArrays instead of lists i'd be glad to accept your advice :)
 

xelhark

macrumors newbie
Original poster
Jul 16, 2010
7
0
GREEEEEEEEAT!! :D

thanks a lot chown33, you spotted the precise problem!

The problem was, i was allocating the nodes in the stack and not in the heap, so even if i saved them in the "nodeList" they were being deleted as soon as the function returned.

This was the problem:
Code:
		Node Nodi[SUDOKUSIZE][SUDOKUSIZE]; //<--- STACK ALLOCATION!
		for (int i=0; i<SUDOKUSIZE; i++) {
			for (int j=0; j<SUDOKUSIZE; j++) {
				Nodi[i][j].Adjs = new myList();
				Nodi[i][j].n = 0;
			}
		}

And this is how i solved it:

Code:
		Node **Nodi = (Node**)malloc(SUDOKUSIZE * sizeof(Node*)); //<-- HEAP ALLOCATION
		for (int i=0; i<SUDOKUSIZE; i++) {
			Nodi[i] = (Node*)malloc(SUDOKUSIZE * sizeof(Node)); //Other Heap allocation
			for (int j=0; j<SUDOKUSIZE; j++) {
				Nodi[i][j].Adjs = new myList();
				Nodi[i][j].n = 0;
			}
		}

Thanks to you all guys, you're amazing :D:D:D:D
 

chown33

Moderator
Staff member
Aug 9, 2009
10,740
8,416
A sea of green
Actually, i once tried using a NSMutableArray for things like that, and it came up being really really slow compared to this kind of lists, but maybe there were other things slowing it down.. I'm not sure, and i'm pretty new to Objective-C and iPhone programming, so if you think it's faster to use NSMutableArrays instead of lists i'd be glad to accept your advice :)

You haven't shown any data types. No one can tell whether NSMutableArray is good, when they haven't seen the structure of the data.

And you should realize that Objective-C is a true superset of C. Anything you can do in C, you can also do in Objective-C. This means you can use C arrays, including ones allocated by malloc() or calloc(). You can also use macros.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.