I would like to generate the sample points that can randomly fill/cover a space (like in the attached image). I think they have a method called "Quasi-random" that can generate such sample points. However, it's a little bit far from my knowledge. Can someone make suggestions or help me find a library that can be do this? Or suggest how to start writing such a program?
In the image, 256 sample points are applied on the given space, placed at random positions to cover the whole given space.
Update:
I just try to use some code from Halton Quasi-random Sequence and compare with the result of pseudo-random which is post by friend below. The result of Halton's method is more better in my opinion. I would like to share some result as below;
The code which I wrote is
#include "halton.hpp"
#include "opencv2/opencv.hpp"
int main()
{
int m_dim_num = 2;
int m_n = 50;
int m_seed[2], m_leap[2], m_base[2];
double m_r[100];
for (int i = 0; i < m_dim_num; i++)
{
m_seed[i] = 0;
m_leap[i] = 1;
m_base[i] = 2+i;
}
cv::Mat out(100, 100, CV_8UC1);
i4_to_halton_sequence( m_dim_num, m_n, 0, m_seed, m_leap, m_base, m_r);
int displaced = 100;
for (int i = 0; i < 100; i=i+2)
{
cv::circle(out, cv::Point2d((m_r[i])*displaced, (m_r[i+1])*displaced), 1, cv::Scalar(0, 255, 0), 1, 8, 0);
}
cv::imshow("test", out);
cv::waitKey(0);
return 0;
}
As I little bit familiar with OpenCV, I wrote this code by plot on the matrix of OpenCV (Mat). The "i4_to_halton_sequence()" is the function from the library that I mentioned above.
The result is not better, but might be use in somehow for my work. Someone have another idea?
I am going to give an answer that will seem half-assed. However, this topic has been studied extensively in the literature, so I will just refer you to some summaries from Wikipedia and other places online.
What you want is also called low-discrepancy sequence (or quasi-random, as you pointed out). You can read more about it here: http://en.wikipedia.org/wiki/Low-discrepancy_sequence. It's useful for a number of things, which includes numerical integration and, more recently, simulating retinal ganglion mosaic.
There are many ways to generate low-discrepancy sequences (or pseudo quasi random sequences :p). Some of these are in ACM Collected Algorithms (http://www.netlib.org/toms/index.html).
The most common of which, I think, is called Sobol sequence (algorithm 659 from the ACM thing). You can get some details on this here: http://en.wikipedia.org/wiki/Sobol_sequence
For the most part, unless you are really into it, that stuff looks pretty scary. For quick result, I would use GNU's GSL (GNU Scientific Library): http://www.gnu.org/software/gsl/
This library includes code to generate quasi-random sequences (http://www.gnu.org/software/gsl/manual/html_node/Quasi_002dRandom-Sequences.html) including Sobol sequence (http://www.gnu.org/software/gsl/manual/html_node/Quasi_002drandom-number-generator-examples.html).
If you're still stuck, I can paste some code here, but you're better off digging into GSL.
Well here's another way to do quasi-random that covers the entire space.
Since you have 256 points to use, you can start by plotting those points as a 16x16 grid.
Then apply some function that give some random offset to each point (say 0 to ±2 to the points' x and y coordinates).
You could create equidistant points (all points have same distance to their neighbors) and then, in a second step, move each point randomly a bit so that they appear 'random'.
The second idea I have is:
1. Start with one area.
2. Create a random point P rand about the 'middle' of your area.
3. Divide the area into 4 areas by that point. P is the upper right corner of the lower left subarea, the upper left corner of the lower right area and so on.
4. Repeat steps 2..4 for all 4 sub areas. Of course, not forever, but until you're satisfied.
This algorithms ensures that each 'hole' (i.e. the new sub area) is filled with a point.
Update: Your initial area should be twice as large as your area, because of step (2). This ensures having points at the edges and corners as well.
This is called a "low discrepancy sequence". The linked Wikipage explains how you can generate them.
But I suspect you already knew this, as your image is very similar to the 2,3 Halton sequence example from Wikipedia
You just need library rand() function:
#include <stdlib.h>
#include <time.h>
unsigned int N = 256; //number of points
int RANGE_X = 100; //x range to put sample points in
int RANGE_Y = 100;
void PutSamplePoint(int x, int y)
{
//some your code putting sample point on field
}
int main()
{
srand((unsigned)time(0)); //initialize random generator - uses current time as seed
for(unsigned int i = 0; i < N; i++)
{
int x = rand() % RANGE_X; //returns random value in range [0, RANGE_X)
int y = rand() % RANGE_Y;
PutSamplePoint(x, y);
}
return 0;
}
Related
I am trying to fill a vector with a specific distribution of nonuniform screen points. These points represent some x and y position on the screen. At some point I am going to draw all of these points on the screen, which should be unevenly distributed at the center. Basically, the frequency of points should increase as you get closer to the center, where one side of the screen is a reflection of the other (can "Mirror over the center of the screen")
I was thinking about using some sort of formula (like y=cos(x) between -pi/2 and pi/2) where the resulting y would equal the frequency of the points in that area of the screen (where -pi/2 would be the leftmost side of the screen, vice versa), but I got stuck on how I would even be able to apply something like this when creating points to put onto the vector. Note: There is a specific number of points that must be generated
If the above hypothesis is not able to work, maybe a cheaty way of achieving this would be to constantly reduce some step size between each point, but I don't know how I would be able to ensure that the specific number of points reach the center.
Ex.
// this is a member function inside a class PointList
// where we fill a member variable list(vector) with nonuniform data
void PointList::FillListNonUniform(const int numPoints, const int numPerPoint)
{
double step = 2;
double decelerator = 0.01;
// Do half the screen then duplicate and reverse the sign
// so both sides of the screen mirror eachother
for (int i = 0; i < numPoints / 2; i++)
{
Eigen::Vector2d newData(step, 0);
for (int j = 0; j < numPerPoint; j++)
{
list.push_back(newData);
}
decelerator += 0.01f;
step -= 0.05f + decelerator;
}
// Do whatever I need to, to mirror the points ...
}
Literally any help would be a appreciated. I have briefly looked into std::normal_distribution, but it appears to me that it relies on randomness, so I am unsure if this would be a good option for what I am trying to do.
You can use something called rejection sampling. The idea is that you have some function of some parameters (in your case 2 parameters x, y), which represents the probability density function. In your 2D case, you can then generate an x, y pair along with a variable representing the probability p. If the probability density function is larger at the coordinates (i.e. f(x, y) > p), the sample is added, otherwise a new pair is generated. You can implement this like:
#include <functional>
#include <vector>
#include <utility>
#include <random>
std::vector<std::pair<double,double>> getDist(int num){
std::random_device rd{};
std::mt19937 gen{rd()};
auto pdf = [] (double x, double y) {
return /* Some probability density function */;
};
std::vector<std::pair<double,double>> ret;
double x,y,p;
while(ret.size() <= num){
x = (double)gen()/SOME_CONST_FOR_X;
y = (double)gen()/SOME_CONST_FOR_Y;
p = (double)gen()/SOME_CONST_FOR_P;
if(pdf(x,y) > p) ret.push_back({x,y});
}
return ret;
}
This is a very crude draft but should give and idea as to how this might work.
An other option (if you want normal distribution), would be std::normal_distribution. The example from the reference page can be adapted so:
#include <random>
#include <vector>
#include <utility>
std::vector<std::pair<double,double>> getDist(int num){
std::random_device rd{};
std::mt19937 gen{rd()};
std::normal_distribution<> d_x{x_center,x_std};
std::normal_distribution<> d_y{y_center,y_std};
while(ret.size() <= num){
ret.push_back({d_x(gen),d_y(gen)});
}
}
There are various ways to approach this, depending on the exact distribution you want. Generally speaking, if you have a distribution function f(x) that gives you the probability of a point at a specific distance to the center, then you can integrate it to get the cumulative distribution function F(x). If the CDF can be inverted, you can use the inverse CDF to map a uniform random variable to distances from the center, such that you get the desired distribution. But not all functions are easily inverted.
Another option would be to fake it a little bit: for example, make a loop that goes from 0 to the maximum distance from the center, and then for each distance you use the probability function to get the expected number of points at that distance. Then just add exactly that many points at randomly chosen angles. This is quite fast and the result might just be good enough.
Rejection sampling as mentioned by Lala5th is another option, giving you the desired distribution, but potentially taking a long time if large areas of the screen have a very low probability. A way to ensure it finishes in bounded time is to not loop until you have num points added, but to loop over every pixel, and add the coordinates of that pixel if pdf(x,y) > p. The drawback of that is that you won't get exactly num points.
In my program, I am downscaling an image of 500px or larger to an extreme level of approx 16px-32px. The source image is user-specified so I do not have control over its size. As you can imagine, few pixel interpolations hold up and inevitably the result is heavily aliased.
I've tried bilinear, bicubic and square average sampling. The square average sampling actually provides the most decent results but the smaller it gets, the larger the sampling radius has to be. As a result, it gets quite slow - slower than the other interpolation methods.
I have also tried an adaptive square average sampling so that the smaller it gets the greater the sampling radius, while the closer it is to its original size, the smaller the sampling radius. However, it produces problems and I am not convinced this is the best approach.
So the question is: What is the recommended type of pixel interpolation that is fast and works well on such extreme levels of downscaling?
I do not wish to use a library so I will need something that I can code by hand and isn't too complex. I am working in C++ with VS 2012.
Here's some example code I've tried as requested (hopefully without errors from my pseudo-code cut and paste). This performs a 7x7 average downscale and although it's a better result than bilinear or bicubic interpolation, it also takes quite a hit:
// Sizing control
ctl(0): "Resize",Range=(0,800),Val=100
// Variables
float fracx,fracy;
int Xnew,Ynew,p,q,Calc;
int x,y,p1,q1,i,j;
//New image dimensions
Xnew=image->width*ctl(0)/100;
Ynew=image->height*ctl(0)/100;
for (y=0; y<image->height; y++){ // rows
for (x=0; x<image->width; x++){ // columns
p1=(int)x*image->width/Xnew;
q1=(int)y*image->height/Ynew;
for (z=0; z<3; z++){ // channels
for (i=-3;i<=3;i++) {
for (j=-3;j<=3;j++) {
Calc += (int)(src(p1-i,q1-j,z));
} //j
} //i
Calc /= 49;
pset(x, y, z, Calc);
} // channels
} // columns
} // rows
Thanks!
The first point is to use pointers to your data. Never use indexes at every pixel. When you write: src(p1-i,q1-j,z) or pset(x, y, z, Calc) how much computation is being made? Use pointers to data and manipulate those.
Second: your algorithm is wrong. You don't want an average filter, but you want to make a grid on your source image and for every grid cell compute the average and put it in the corresponding pixel of the output image.
The specific solution should be tailored to your data representation, but it could be something like this:
std::vector<uint32_t> accum(Xnew);
std::vector<uint32_t> count(Xnew);
uint32_t *paccum, *pcount;
uint8_t* pin = /*pointer to input data*/;
uint8_t* pout = /*pointer to output data*/;
for (int dr = 0, sr = 0, w = image->width, h = image->height; sr < h; ++dr) {
memset(paccum = accum.data(), 0, Xnew*4);
memset(pcount = count.data(), 0, Xnew*4);
while (sr * Ynew / h == dr) {
paccum = accum.data();
pcount = count.data();
for (int dc = 0, sc = 0; sc < w; ++sc) {
*paccum += *i;
*pcount += 1;
++pin;
if (sc * Xnew / w > dc) {
++dc;
++paccum;
++pcount;
}
}
sr++;
}
std::transform(begin(accum), end(accum), begin(count), pout, std::divides<uint32_t>());
pout += Xnew;
}
This was written using my own library (still in development) and it seems to work, but later I changed the variables names in order to make it simpler here, so I don't guarantee anything!
The idea is to have a local buffer of 32 bit ints which can hold the partial sum of all pixels in the rows which fall in a row of the output image. Then you divide by the cell count and save the output to the final image.
The first thing you should do is to set up a performance evaluation system to measure how much any change impacts on the performance.
As said precedently, you should not use indexes but pointers for (probably) a substantial
speed up & not simply average as a basic averaging of pixels is basically a blur filter.
I would highly advise you to rework your code to be using "kernels". This is the matrix representing the ratio of each pixel used. That way, you will be able to test different strategies and optimize quality.
Example of kernels:
https://en.wikipedia.org/wiki/Kernel_(image_processing)
Upsampling/downsampling kernel:
http://www.johncostella.com/magic/
Note, from the code it seems you apply a 3x3 kernel but initially done on a 7x7 kernel. The equivalent 3x3 kernel as posted would be:
[1 1 1]
[1 1 1] * 1/9
[1 1 1]
I want to pixelate an image stored in a 1d array, although i am not sure how to do it, this is what i have comeup with so far...
the value of pixelation is currently 3 for testing purposes.
currently it just creates a section of randomly coloured pixels along the left third of the image, if i increase the value of pixelation the amount of random coloured pixels decreases and vice versa, so what am i doing wrong?
I have also already implemented the rotation, reading of the image and saving of a new image this is just a separate function which i need assistance with.
picture pixelate( const std::string& file_name, picture& tempImage, int& pixelation /* TODO: OTHER PARAMETERS HERE */)
{
picture pixelated = tempImage;
RGB tempPixel;
tempPixel.r = 0;
tempPixel.g = 0;
tempPixel.b = 0;
int counter = 0;
int numtimesrun = 0;
for (int x = 1; x<tempImage.width; x+=pixelation)
{
for (int y = 1; y<tempImage.height; y+=pixelation)
{
//RGB tempcol;
//tempcol for pixelate
for (int i = 1; i<pixelation; i++)
{
for (int j = 1; j<pixelation; j++)
{
tempPixel.r +=tempImage.pixel[counter+pixelation*numtimesrun].colour.r;
tempPixel.g +=tempImage.pixel[counter+pixelation*numtimesrun].colour.g;
tempPixel.b +=tempImage.pixel[counter+pixelation*numtimesrun].colour.b;
counter++;
//read colour
}
}
for (int k = 1; k<pixelation; k++)
{
for (int l = 1; l<pixelation; l++)
{
pixelated.pixel[numtimesrun].colour.r = tempPixel.r/pixelation;
pixelated.pixel[numtimesrun].colour.g = tempPixel.g/pixelation;
pixelated.pixel[numtimesrun].colour.b = tempPixel.b/pixelation;
//set colour
}
}
counter = 0;
numtimesrun++;
}
cout << x << endl;
}
cout << "Image successfully pixelated." << endl;
return pixelated;
}
I'm not too sure what you really want to do with your code, but I can see a few problems.
For one, you use for() loops with variables starting at 1. That's certainly wrong. Arrays in C/C++ start at 0.
The other main problem I can see is the pixelation parameter. You use it to increase x and y without knowing (at least in that function) whether it is a multiple of width and height. If not, you will definitively be missing pixels on the right edge and at the bottom (which edges will depend on the orientation, of course). Again, it very much depends on what you're trying to achieve.
Also the i and j loops start at the position defined by counter and numtimesrun which means that the last line you want to hit is not tempImage.width or tempImage.height. With that you are rather likely to have many overflows. Actually that would also explain the problems you see on the edges. (see update below)
Another potential problem, cannot tell for sure without seeing the structure declaration, but this sum using tempPixel.c += <value> may overflow. If the RGB components are defined as unsigned char (rather common) then you will definitively get overflows. So your average sum is broken if that's the fact. If that structure uses floats, then you're good.
Note also that your average is wrong. You are adding source data for pixelation x pixalation and your average is calculated as sum / pixelation. So you get a total which is pixalation times larger. You probably wanted sum / (pixelation * pixelation).
Your first loop with i and j computes a sum. The math is most certainly wrong. The counter + pixelation * numtimesrun expression will start reading at the second line, it seems. However, you are reading i * j values. That being said, it may be what you are trying to do (i.e. a moving average) in which case it could be optimized but I'll leave that out for now.
Update
If I understand what you are doing, a representation would be something like a filter. There is a picture of a 3x3:
.+. *
+*+ =>
.+.
What is on the left is what you are reading. This means the source needs to be at least 3x3. What I show on the right is the result. As we can see, the result needs to be 1x1. From what I see in your code you do not take that in account at all. (the varied characters represent varied weights, in your case all weights are 1.0).
You have two ways to handle that problem:
The resulting image has a size of width - pixelation * 2 + 1 by height - pixelation * 2 + 1; in this case you keep one result and do not care about the edges...
You rewrite the code to handle edges. This means you use less source data to compute the resulting edges. Another way is to compute the edge cases and save that in several output pixels (i.e. duplicate the pixels on the edges).
Update 2
Hmmm... looking at your code again, it seems that you compute the average of the 3x3 and save it in the 3x3:
.+. ***
+*+ => ***
.+. ***
Then the problem is different. The numtimesrun is wrong. In your k and l loops you save the pixels pixelation * pixelation in the SAME pixel and that advanced by one each time... so you are doing what I shown in my first update, but it looks like you were trying to do what is shown in my 2nd update.
The numtimesrun could be increased by pixelation each time:
numtimesrun += pixelation;
However, that's not enough to fix your k and l loops. There you probably need to calculate the correct destination. Maybe something like this (also requires a reset of the counter before the loop):
counter = 0;
... for loops ...
pixelated.pixel[counter+pixelation*numtimesrun].colour.r = ...;
... (take care of g and b)
++counter;
Yet again, I cannot tell for sure what you are trying to do, so I do not know why you'd want to copy the same pixel pixelation x pixelation times. But that explains why you get data only at the left (or top) of the image (very much depends on the orientation, one side for sure. And if that's 1/3rd then pixelation is probably 3.)
WARNING: if you implement the save properly, you'll experience crashes if you do not take care of the overflows mentioned earlier.
Update 3
As explained by Mark in the comment below, you have an array representing a 2d image. In that case, your counter variable is completely wrong since this is 100% linear whereas the 2d image is not. The 2nd line is width further away. At this point, you read the first 3 pixels at the top-left, then the next 3 pixels on the same, and finally the next 3 pixels still on the same line. Of course, it could be that your image is thus defined and these pixels are really one after another, although it is not very likely...
Mark's answer is concise and gives you the information necessary to access the correct pixels. However, you will still be hit by the overflow and possibly the fact that the width and height parameters are not a multiple of pixelation...
I don't do a lot of C++, but here's a pixelate function I wrote for Processing. It takes an argument of the width/height of the pixels you want to create.
void pixelateImage(int pxSize) {
// use ratio of height/width...
float ratio;
if (width < height) {
ratio = height/width;
}
else {
ratio = width/height;
}
// ... to set pixel height
int pxH = int(pxSize * ratio);
noStroke();
for (int x=0; x<width; x+=pxSize) {
for (int y=0; y<height; y+=pxH) {
fill(p.get(x, y));
rect(x, y, pxSize, pxH);
}
}
}
Without the built-in rect() function you'd have to write pixel-by-pixel using another two for loops:
for (int px=0; px<pxSize; px++) {
for (int py=0; py<pxH; py++) {
pixelated.pixel[py * tempImage.width + px].colour.r = tempPixel.r;
pixelated.pixel[py * tempImage.width + px].colour.g = tempPixel.g;
pixelated.pixel[py * tempImage.width + px].colour.b = tempPixel.b;
}
}
Generally when accessing an image stored in a 1D buffer, each row of the image will be stored as consecutive pixels and the next row will follow immediately after. The way to address into such a buffer is:
image[y*width+x]
For your purposes you want both inner loops to generate coordinates that go from the top and left of the pixelation square to the bottom right.
I am working on an openGL project and my rand function is not giving me a big enough random range.
I am tasked with writing a diamond program to where one diamond is centered on the screen and 5 are randomly placed elsewhere on the screen. What is happening is my center diamond is where it is supposed to be and the other five are bunching with a small range of random left of center. I have included the function that draws the diamonds.
void myDisplay(void)
{
srand(time(0));
GLintPoint CenterPoint;
int const size = 20;
CenterPoint.x = screenWidth / 2;
CenterPoint.y = screenHeight / 2;
glClear(GL_COLOR_BUFFER_BIT);
drawDiamond(CenterPoint, size);
for (int i = 0; i < 5; i++)
{
GLfloat x = rand() % 50 + 10;
GLfloat y = rand() % 200 + 100;
GLfloat size = rand() % 100;
GLintPoint diam = {x,y};
drawDiamond(diam, size);
}
If more code is needed, please let me know and I will edit. Does anyone have any ideas on how I can correct this? I have "toyed" with the numbers of the rand() function and really doesn't seem to do much. They still seem to bunch just at different points on the screen. I appreciate the help. Just in case anyone needs to know, I am creating this in VS2012.
This has no business being in this function:
srand(time(0));
This should be called once at the beginning of your program (a good place is just inside main()); and most-certainly not in your display routine. Once the seed is set, you should never do it again for your process unless you want to repeat a prior sequence (which by the looks of it, you don't).
That said, I would strongly advise using the functionality in <random> that comes with your C++11 standard library. With it you can establish distributions (ex: uniform_int_distribution<>) that will do much of your modulo work for you, and correctly account for the problems such things can encounter (Andon pointed out one regarding likeliness of certain numbers based on the modulus).
Spend some time with <random>. Its worth it. An example that uses the three ranges you're using:
#include <iostream>
#include <random>
using namespace std;
int main()
{
std::random_device rd;
std::default_random_engine rng(rd());
// our distributions.
std::uniform_int_distribution<> dist1(50,60);
std::uniform_int_distribution<> dist2(200,300);
std::uniform_int_distribution<> dist3(0,100);
for (int i=0;i<10;++i)
std::cout << dist1(rng) << ',' << dist2(rng) << ',' << dist3(rng) << std::endl;
return EXIT_SUCCESS;
}
Output (obviously varies).
58,292,70
56,233,41
57,273,98
52,204,8
50,284,43
51,292,48
53,220,42
54,281,64
50,290,51
53,220,7
Yeah, it really is just that simple. Like I said, that library is this cat's pajamas. There are many more things it offers, including random normal distributions, different engine backends, etc. I highly encourage you to check into it.
As WhozCraig mentioned, seeding your random number generator with the time every time you call myDisplay (...) is a bad idea. This is because time (NULL) has a granularity of 1 second, and in real-time graphics you usually draw your scene more than one time per-second. Thus, you are repeating the same sequence of random numbers every time you call myDisplay (...) when less than 1 second has elapsed.
Also, using modulo arithmetic on a call to rand (...) adversely affects the quality of the returned values. This is because it changes the probability distribution for numbers occurring. The preferred technique should be to cast rand (...) to float and then divide by RAND_MAX, and then multiply this result by your desired range.
GLfloat x = rand() % 50 + 10; /* <-- Bad! */
/* Consider this instead */
GLfloat x = (GLfloat)rand () / RAND_MAX * 50.0f + 10.0f;
Although, come to think of it. Why are you using GLfloat for x and y if you are going to store them in an integer data structure 2 lines later?
Let T(x,y) be the number of tours over a X × Y grid such that:
the tour starts in the top left square
the tour consists of moves that are up, down, left, or right one
square
the tour visits each square exactly once, and
the tour ends in the bottom left square.
It’s easy to see, for example, that T(2,2) = 1, T(3,3) = 2, T(4,3) = 0, and T(3,4) = 4. Write a program to calculate T(10,4).
I have been working on this for hours ... I need a program that takes the dimensions of the grid as input and returns the number of possible tours?
I have been working on this for hours ... I need a program that takes the dimensions of the grid as input and returns the number of possible tours?
I wrote this code to solve the problem ... I cant seem to figure out how to check all directions.
#include <iostream>
int grid[3][3];
int c = 0;
int main(){
solve (0, 0, 9);
}
int solve (int posx, int posy, steps_left){
if (grid[posx][posy] = 1){
return 0;
}
if (steps_left = 1 && posx = 0 && posy = 2){
c = c+1;
return 0;
}
grid[posx][posy] = 1;
// for all possible directions
{
solve (posx_next, posy_next, steps_left-1)
}
grid[posx][posy] = 0;
}
Algorithm by #KarolyHorvath
You need some data structure to represent the state of the cells on the grid (visited/not visited).
Your algorithm:
step(posx, posy, steps_left)
if it is not a valid position, or already visited
return
if it's the last step and you are at the target cell
you've found a solution, increment counter
return
mark cell as visited
for each possible direction:
step(posx_next, posy_next, steps_left-1)
mark cell as not visited
and run with
step(0, 0, sizex*sizey)
It's not difficult, since you've been given the algorithm. In order to
solve the problem, you'll probably want some sort of dynamic data
structure (unless you're only interested in the exact case of T(10,4)).
For the rest, left is -1 on the x index, right +1, and down is -1 on the
y dimension, up +1. Add bounds checking and verification that you've
not visited, and the job is done.
But I wonder how much time such an obvious algorithm will take. There's
a four way decision on each cell; for the fourty cells of T(10,4),
that's 4^40 decisions. Which is not feasable. Things like eliminating
already visited cells and bounds checking eliminate a lot of branches,
but still... The goal of the competition might be to make you find a
better algorithm.
You really should pick a debugger and see what's going on on a small board (2x2, 3x3).
One obvious problem is that = is assignment, not comparison. Compare with ==.
There are more problems. Find them.