I'm not sure I'm giving the right name to this, but anyway I have a matrix that essentially contains 1s or 0s. The matrix is a square matrix, its size can be 3x3, 4x4 or 5x5.
By pattern matching, I mean to find some "shapes" in my matrix such as a line, a T or a U, e.g.:
0 1 0
0 1 0
1 1 1
that matrix contains a T, but it also contains 2 lines! Now if the matrix was a 4x4, the shapes don't increase but they can be positioned at more place obviously, e.g.:
0 0 0 0
1 1 1 0
0 0 1 0
1 1 1 0
That matrix would contain a U (no lines though, this is the exception, lines have the size of the matrix).
Naively since the matrix is pretty small I would have tried all possibilities for each shape I'm wiling to support, but it's not very fun. I cannot figure out any algorithm for this though, and not being able to label this operation properly doesn't help ;) Has anyone got any idea how to would do this "efficiently" ? (efficiently may be a bit of an overstatement considering the size of the matrix, but you know what I mean).
There's some ambiguity in your question. For instance, does:
1 1 1
1 1 1
1 1 1
contain 6 lines, a T, a U, and a bunch of other letters of the alphabet? Or are all letters separated? Your initial question implied that letters could be discovered in overlapping fashion, because the T template contains two lines. Thus, a matrix where all elements were 'on' would contain every possible letter/line in every possible position.
Also, I'm assuming you're only concerned about 90 degree rotations and you wouldn't want to try to find 45-degree offset letters when the matrix sizes get large enough to support it.
In terms of ease-of-implementation, the brute-force approach you're talking about (test every position for all four letter rotations) really wins out, I'd say.
Alternatively, you could get pretty fancy by (warning: vague algorithm descriptions ahead!):
1) Walking along the matrix elements until you found a 1. Then essentially flood-fill from that 1 on a stack and keep track of the direction changes. Then have some sort of rotation-invariant lookup that mapped a set of 'on' pixels to found letters.
2) Use some sort of integral-image or box-filter description to take sums of subsections of the matrix. You could then do lookups on the subsections and map the subsection sums to letter/line values.
3) Since the comments have determined that you're only really looking for 4 shapes, a new approach may be worthwhile. You're only examining 4 shapes (line, cross, T, and U) if I'm not mistaken. Each of them can be in 4 orientations. One quick tip is that you can just run the algorithm 4 times but rotate the underlying matrix by 90 degrees. Then you don't have to adjust for rotation in your algorithm. Also note that the cross only needs to be found in one orientation because it looks identical in all 4 orientations and the line is identical in two orientations. Anyway, you could save yourself some work by searching for the 'hardest' things to match first. Let's say I'm looking for an upright 'U' here:
1 0 1
1 0 1
1 1 1
I start in the top left. Rather than checking to make sure that any pixels are 'off' (or 0), I go to the next place I expect to find an 'on' value (or a 1). Let's say that's the pixel below the top left. I check the middle-left pixel, and indeed it's on. Then I check below that. If you develop a simple rule set for each letter, you can quickly abandon the search for it if you don't have the required values turned 'on'. If you then run the same algorithm 4 times and only search for upright values, I'm not sure you'd be able to do much better than this!
The approaches I've mentioned are just ideas. They may be more trouble than they're worth in terms of efficiency gains, though. And who knows, they may not work at all!
Good luck!
I thought I could contribute with what I ended up doing so here it is, following aardvarkk idea. (objective-c code) I wasn't very pedantic with the array size checks because my matrix is necessarily a square matrix. Also sorry if the code is ugly :D
I made a little class structure for the shapes I want to reconize, they have a list of "directions" which are essentially values of an enum.
-(BOOL)findShape:(NSInteger)size directions:(NSArray*)directions{
NSMutableArray* current = [mgs tokens];
for (int rot = 0; rot < 4; rot++) {
for (int i = 0; i < size; i++) {
for(int j = 0; j < size; j++){
NSInteger value = [[[current objectAtIndex:i] objectAtIndex:j] integerValue];
if(value){
BOOL carryOn = [self iterateThroughDirections:directions i:i j:j tokens:current size:size];
if(carryOn){
return YES;
}
}
}
}
current = [self rotate:current];
}
return NO;
}
-(BOOL) iterateThroughDirections:(NSArray*)directions i:(NSInteger)i j:(NSInteger)j tokens:(NSMutableArray*)tokens size:(NSInteger)size{
BOOL carryOn = YES;
for(int k = 0; k < [directions count] && carryOn; k++){
NSNumber* dir = [directions objectAtIndex:k];
NSInteger d = [dir integerValue];
//move in the direction
switch (d) {
case UP:
if(i > 0){
i--;
}else{
carryOn = NO;
}
break;
case DOWN:
if(i < size-1){
i++;
}else{
carryOn = NO;
}
break;
case LEFT:
if(j > 0){
j--;
}else{
carryOn = NO;
}
break;
case RIGHT:
if(j < size-1){
j++;
}else{
carryOn = NO;
}
break;
default:
NSAssert(NO, #"invalid direction");
break;
}
NSInteger v = [[[tokens objectAtIndex:i] objectAtIndex:j] integerValue];
//now that we moved, check if the token is active, if it's not we're done
if(!v){
carryOn = NO;
break;
}
}
return carryOn;
}
-(NSMutableArray*)rotate:(NSMutableArray*)matrix{
NSInteger w = [matrix count];
NSInteger h = [[matrix objectAtIndex:0] count];
NSMutableArray* rotated = [[NSMutableArray arrayWithCapacity:h] retain];
for (int i = 0; i < h; i++) {
[rotated addObject:[NSMutableArray arrayWithCapacity:w]];
}
for(int i = 0; i < h; ++i){
for(int j = 0; j < w; ++j){
[[rotated objectAtIndex:i] addObject:[[matrix objectAtIndex:j] objectAtIndex:h-i-1]];
}
}
return rotated;
}
This seems to be working well for me! Thanks again for the help!
Related
Good morning, i'm trying to generate a sequence of N pairs of numbers, for example 1-0, 2-4, 4-3. These numbers must range between 0 and 8 and the pair must be different for all the numbers.
I don't want that: 1-3 1-3
I found that if a and b are the numbers, (a+b)+(a-b) has to be different for all couples of numbers.
So I manage to do that, but the loop never ends.
Would you please correct my code or write me another one? I need it as soon as possible.
NSNumber*number1;
int risultato;
int riga;
int colonna;
NSMutableArray*array=[NSMutableArray array];
NSMutableArray*righe=[NSMutableArray array];
NSMutableArray*colonne=[NSMutableArray array];
for(int i=0; i<27; i++)
{
riga=arc4random()%9;
colonna=arc4random()%9;
risultato=(riga+colonna)+(riga-colonna);
number1=[NSNumber numberWithInt:risultato];
while([array containsObject:number1])
{
riga=arc4random()%9;
colonna=arc4random()%9;
risultato=(riga+colonna)+(riga-colonna);
number1=[NSNumber numberWithInt:risultato];
}
NSNumber*row=[NSNumber numberWithBool:riga];
NSNumber*column=[NSNumber numberWithInt:colonna];
[righe addObject:row];
[colonne addObject:column];
[array addObject:number1];
}
for(int i=0; i<27; i++)
{
NSNumber*one=[righe objectAtIndex:i];
NSNumber*two=[colonne objectAtIndex:i];
NSLog(#"VALUE1 %ld VALUE2 %ld", [one integerValue], (long)[two integerValue]);
}
edit:
I have two arrays (righe, colonne) and I want them to have 27 elements [0-8].
I want to obtain a sequence like it:
righe: 1 2 4 6 7 8 2 3 4 8 8 7
colonne: 1 3 4 4 2 1 5 2 7 6 5 6
I don't want to have that:
righe: 1 2 4 6 2
colonne: 1 3 5 2 3
Where you see that 2-3 is repeated once. Then I'd like to store these values in a primitive 2d array (array[2][27])
I found that if a and b are the numbers, (a+b)+(a-b) has to be different for all couples of numbers.
This is just 2 * a and is not a valid test.
What you are looking for are pairs of digits between 0 - 8, giving a total of 81 possible combinations.
Consider: Numbers written in base 9 (as opposed to the common bases of 2, 10 or 16) use the digits 0 - 8, and if you express the decimal numbers 0 -> 80 in base 9 you will get 0 -> 88 going through all the combinations of 0 - 8 for each digit.
Given that you can can restate your problem as requiring to generate 27 numbers in the range 0 - 80 decimal, no duplicates, and expressing the resultant numbers in base 9. You can extract the "digits" of your number using integer division (/ 9) and modulus (% 9)
To perform the duplicate test you can simply use an array of 81 boolean values: false - number not used, true - number used. For collisions you can just seek through the array (wrapping around) till you find an unused number.
Then I'd like to store these values in a primitive 2d array (array[2][27])
If that is the case just store the numbers directly into such an array, using NSMutableArray is pointless.
So after that long explanation, the really short code:
int pairs[2][27];
bool used[81]; // for the collision testing
// set used to all false
memset(used, false, sizeof(used));
for(int ix = 0; ix < 27; ix++)
{
// get a random number
int candidate = arc4random_uniform(81);
// make sure we haven't used this one yet
while(used[candidate]) candidate = (candidate + 1) % 81;
// record
pairs[0][ix] = candidate / 9;
pairs[1][ix] = candidate % 9;
// mark as used
used[candidate] = true;
}
HTH
Your assumption about (a+b)+(a-b) is incorrect: this formula effectively equals 2*a, which is obviously not what you want. I suggest storing the numbers in a CGPoint struct and checking in a do...while loop if you already have the newly generated tuple in your array:
// this array will contain objects of type NSValue,
// since you can not store CGPoint structs in NSMutableArray directly
NSMutableArray* array = [NSMutableArray array];
for(int i=0; i<27; i++) {
// declare a new CGPoint struct
CGPoint newPoint;
do {
// generate values for the CGPoint x and y fields
newPoint = CGPointMake(arc4random_uniform(9), arc4random_uniform(9));
} while([array indexOfObjectPassingTest:^BOOL(NSValue* _Nonnull pointValue, NSUInteger idx, BOOL * _Nonnull stop) {
// here we retrieve CGPoint structs from the array one by one
CGPoint point = [pointValue CGPointValue];
// and check if one of them equals to our new point
return CGPointEqualToPoint(point, newPoint);
}] != NSNotFound);
// previous while loop would regenerate CGPoint structs until
// we have no match in the array, so now we are sure that
// newPoint has unique values, and we can store it in the array
[array addObject:[NSValue valueWithCGPoint:newPoint]];
}
for(int i=0; i<27; i++)
{
NSValue* value = array[i];
// array contains NSValue objects, so we must convert them
// back to CGPoint structs
CGPoint point = [value CGPointValue];
NSInteger one = point.x;
NSInteger two = point.y;
NSLog(#"VALUE1 %ld VALUE2 %ld", one, two);
}
First of all I must admit that it is my assignment. But I am not asking anyone to solve it but I am working hard to solve it and need help with my algorithm.
I have an array of weights that is assigned to leftSide and rightSide of a scale. I need to balance the weights in right side and left side using the weights in the array.
I have the following code but it does not cover all the situations:
-(BOOL) isBalanced
{
_weights = [NSMutableArray arrayWithArray:#[#3,#4,#2,#1,#5,#6,#4]];
self.leftSide = [[_weights objectAtIndex:arc4random() % 7] integerValue]; // random weight
self.rightSide = [[_weights objectAtIndex:arc4random() % 7] integerValue]; // random weight
if(self.leftSide == self.rightSide) return YES; // already balanced
if(self.leftSide > self.rightSide)
{
// add weights on right side
int difference = self.leftSide - self.rightSide;
int index = [_weights indexOfObject:[NSNumber numberWithInt:difference]];
self.rightSide += [[_weights objectAtIndex:index] integerValue];
NSLog(#"%d",index);
}
else
{
int difference = self.rightSide - self.leftSide;
int index = [_weights indexOfObject:[NSNumber numberWithInt:difference]];
self.leftSide += [[_weights objectAtIndex:index] integerValue];
NSLog(#"%d",index);
}
return self.leftSide == self.rightSide;
}
UPDATE:
To simplify! I have a number 6 and now I need to search inside an array of ints if any of the numbers can be added together to get 6. Example:
1,2,3,5,4
In the above array I can take 1+2+3 which makes 6. I can also take 4+2 which is 6. The question is how do I find those individual numbers that can sum up to the number 6.
Right now I have a NSMutableArray that holds 3 sprite objects. I need to be able to see if another sprite not in the Array shares the same position as any of the sprites in the array.
I tried doing this:
CCSprite *sect;
if (i > maxHealth) {
for (int j = 0; j < i; j++) {
sect = [tail objectAtIndex:j];
}
if (CGRectContainsPoint(sect.boundingBox, playerPos)) {
NSLog(#"On top");
return;
}
But it does't work. I think it's trying to see if it intersects all of them at once.
Your if is outside the for loop. It is only going to test one object; the last one accessed in the loop.
I want to write a really simple prime app. But i am having some problems with the code below it should generate primes from 0 to 99. But instead it just shows 99.
One problem is that only the last number is displayed. But the other one is that the prime "check" doesn't work. How can I fix those problems.
for (i=0; i<100; i++) {
for (n=2; n<i; n++) {
if (i%n == 0) break;
else primetext.text = [NSString stringWithFormat:#"%i, ", i];
}
}
There were a number of problems, I'll try to explain them
The problem with prime checking was that you had the if-else statement inside of the for loop that iterated through the numbers to check. So if your number wasn't divisible by ANY of the numbers you check it would be registered as prime. It would also be registered n times, where n is the number of times it was found to not be divisible.
All even numbers are not prime (aside from 2), so you can do i+=2 to double your speed
You only need to check up to the square root of a number to see if it's prime.
1 isn't a prime so you don't need to include it (especially because it can make your logic more complex).
You were reassigning the string instead of adding a component to it
You were using %i instead of %d. This can sometimes cause weird errors.
Here is your method revised with these points in mind.
int maxNum = 100;
primetext.text = #"2 "; //Start knowing that 2 is the lowest prime (avoid evaluating evens)
for (i=3; i<=maxNum; i+=2) //Start at 3 and add 2 (avoid 1 and 2 as well as even numbers)
{
bool isPrime = YES; //Assume that i is prime
for (n=2; n<sqrt(i); n++) //Divide by every number up to square root
{
if (i%n == 0) //If evenly divisible by n, not a prime
{
isPrime = NO;
break; //Don't need to check any more factors, so break
}
}
if (isPrime) //If isPrime was never set to NO, i is prime
{
NSString *temp = [NSString stringWithFormat:#"%d ", i];
primetext.text = [primetext.text stringByAppendingString:temp];
}
}
Hope this helps.
You should append the number to primetext.text instead of assigning. Right now it's being reassigned on every iteration.
I am supposed to make an app that generates fully complete Sudoku puzzles. I can get the first row to generate properly with the following code, but, no matter what I do, I cannot get the next rows to work right. They all generate the right way in that I get the numbers 1-9 in a random order, but I cannot get it to make a workable Sudoku puzzle.
Code:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:8];
for (int integerA = 0; integerA < 10; integerA ++) {
[array addObject:[NSNumber numberWithInt:integerA]];
//NSLog(#"%i", (integerA + 1));
}
for (int x = 8; x >= 0; x --) {
[array exchangeObjectAtIndex:(arc4random() % (x + 1)) withObjectAtIndex:x];
section[x][0] = ([[array objectAtIndex:x] intValue] + 1);
for (int y = 8; y >= 0; y --) {
if (0) {
}
}
}
That part works. If I try to make another array and generate the "y" values for each "x" value, it goes all weird. Without numerous conditional statements, is there an efficient way to generate a fully solved Sudoku puzzle?
The "weird results":
2 0 1 | 2 3 3 | 5 2 2
7 0 3 | 2 1 5 | 1 4 4
2 0 1 | 0 3 4 | 6 7 3
- - - - - - - - - -
8 4 0 | 1 3 6 | 5 2 7
5 0 4 | 3 2 1 | 1 1 1
7 0 0 | 3 1 4 | 6 5 1
- - - - - - - - - -
2 7 0 | 5 6 3 | 4 1 8
7 6 1 | 1 3 2 | 5 0 5
0 1 1 | 2 3 5 | 0 1 5
The problem of find a correct Sudoku scheme is a very common homework and it has many different solutions.
I will not provide you the code, but let me give you some suggestions: as you certainly know, the aim is to generate a scheme that has non-repeating numbers in row, column and square.
This is, more basically, the problem of generating random non-repeating numbers.
The web is full of solutions for this problem, just a couple of examples here and here.
Now that we are able to generate non-repeating numbers, the problem is to fill the table.
There are many possible approaches: obviously you cannot avoid to check (in some way) that the current number appears only once per row, column, square.
The first solution that comes in my mind is a recursive procedure (let's call it int fill(int row)):
In a do-while loop (I'll explain later why) do this operations:
generate an array of random (this is to avoid that the algorithm generates always the same scheme) non-repeating numbers (from 1 to 9)
this is a possible candidate to become the row-esim row of your scheme. Of course, most of the case you will not be such lucky to have your row ready, so you have to check some conditions:
for each number in your array check if it's the first time it appears in column and in the square (you do not need to check in the row since you built an array of non-repeating numbers).
I will not explain further how to check since it's almost trivial.
If yes, copy it in your scheme and move it at the end of your array. This way, at the beginning of your array, you will always have non-used numbers.
If no, skip it and try the next one.
Be careful: you must keep the reference of the number of used numbers, otherwise you may use two times the same number in one row.
However, this way it is possible to arrive in a situation in which no number seems to fit your table. In this case, simply return 0
If, instead, you inserted all 9 numbers in the current row, call int chk = fill(row+1). Of course you must not call the recursive step if you reached the final row (row==9). In this case simply return 1.
chk will store the return value of the recursive step.
If chk==0 it means that the algorithm was not able to find a suitable row for the next level. In this case simply restart the initial do-while loop.
Otherwise the recursive step was successful, so you can return 1.
However, this is only a possible solutions. There are many others possible algorithms/variations. It's up to you to increase performance and do some optimization.
For sudoku generates we need to check only three - four step
Get row filled numbers array => rawArray.
Get Column filled numbers array => columnArray.
Get current cell's 3x3 grid array => cellArray.
Create array of 1-9 number (numberArray) and Remove numbers of above three array (rawArray , columnArray , cellArray)
finalArray = (numberArray) - (rawArray , columnArray , cellArray)
get random number from finalArray
and placed it to current cell
if any conflicted repeat step 1-5
bellow is code how to generate random sudoku
#import "ViewController.h"
#interface ViewController (){
NSMutableArray *field;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self genrateSudoku];
}
-(void)genrateSudoku{
[self fillEmptyGrid];
#autoreleasepool {
int n = 3;
BOOL flag=NO;
for (int i = 0; i < n*n; i++) {
for (int j = 0; j < n*n; j++){
if ([field[i][j] isEqualToString:#"_"]) {
if (![self fileValue:i and:j]) {
flag=YES;
break;
}
}else{
continue;
}
}
if (flag) {
break;
}
}
if (flag) {
[self genrateSudoku];
}else{
NSLog(#"field fill =%#",field);
}
}
}
-(void)fillEmptyGrid{
int n = 3;
field=[[NSMutableArray alloc]init];
for (int i = 0; i < n*n; i++) {
NSMutableArray *a=[[NSMutableArray alloc]init];
[field addObject:a];
for (int j = 0; j < n*n; j++){
[field[i] addObject:[NSString stringWithFormat:#"_"]];
}
}
}
-(BOOL)fileValue:(int)i and:(int)j{
NSMutableArray *rawArray=field[i];
NSMutableArray *cellArray=[self boxArray:i and:j];
NSMutableArray *columnArray=[self colArray:i and:j];
NSString *value =[self getRandomCol:columnArray rowA:rawArray box:cellArray];
if (value==nil) {
return NO;
}else{
field[i][j]=value;
return YES;
}
}
-(NSMutableArray *)boxArray:(int)i and:(int)j {
int x= (i<3)?0:((i<6)?3:6);
int y=(j<3)?0:((j<6)?3:6);
NSMutableArray *ar=[[NSMutableArray alloc]init];
for (int a=x; a<x+3; a++) {
for (int b=y; b<y+3; b++) {
[ar addObject:field[a][b]];
}
}
return ar;
}
-(NSMutableArray *)colArray:(int)i and:(int)j{
NSMutableArray *ar=[[NSMutableArray alloc]init];
for (int b=0; b<9; b++) {
[ar addObject:field[b][j]];
}
return ar;
}
-(NSString *)getRandomCol:(NSMutableArray *)col rowA:(NSMutableArray *)row box:(NSMutableArray *)box{
NSMutableArray *array=[[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9", nil];
[array removeObjectsInArray:row];
[array removeObjectsInArray:box];
[array removeObjectsInArray:col];
if (array.count>0) {
int x=arc4random()%array.count;
return array[x];
}
else{
return nil;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end