Navigating through a Maze using path-planning (Dijkstra) - algorithm
I'm working on an robot that would be able to navigate through a maze, avoid obstacles and identify some of the objects in it. I have a monochromatic bitmap of the maze, that is supposed to be used in the robot navigation.
Up till now I have processed the bitmap image, and converted it into an adjacency list. I will now use the dijkstra's algorithm to plan the path.
However the problem is that I have to extract the entrance point/node and exit node from the bmp image itself for dijkstra's algorithm to plan the path.
The robots starting position will be slightly different (inch or two before the entrance point) from the entrance point of maze, and I am supposed to move to the entrance point using any "arbitrary method" and then apply dijkstra algorithm to plan path from maze's entrance to exit.
On the way I have to also stop at the "X's" marked in the bmp file I have attached below. These X's are basically boxes in which I have to pot balls. I will plan the path from entrance point to exit point , and not from the entrance to 1st box, then to second, and then to the exit point; because I think the boxes will always be placed at the shortest path.
Since the starting position is different from the entrance point, how will I match my robot's physical location with the coordinates in the program and move it accordingly. Even if the entrance position would have been same as starting position there may have been an error. How should I deal with it? Should I navigate only on the bases of the coordinates provided by dijkstra or use ultrasonics as well to prevent collisions? And if we yes, can you give me an idea of how should I use the both (ultrasonics, and coordinates)?
Here's the sample Bitmap image of the maze.
I know you need this for robotics but here is an example how to translate pixels to array in java to give some ideas?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class RobotDemo extends JFrame {
private static final long serialVersionUID = 1L;
public RobotDemo() {
super("Robot Demo");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
getContentPane().add(new RobotPanel(), BorderLayout.CENTER);
pack();
setResizable(false);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new RobotDemo();
frame.setVisible(true);
}
});
}
}
interface Constants {
public static final int TILE_WIDTH = 32;
public static final int TILE_HEIGHT = 32;
public static final int NUM_TILE_COLS = 20;
public static final int NUM_TILE_ROWS = 10;
public static final int PIXEL_STEPS = 3;
public static final int REFRESH_RATE = 200;
public static final Dimension PANEL_SIZE = new Dimension(TILE_WIDTH * NUM_TILE_COLS, TILE_HEIGHT * NUM_TILE_ROWS);
public static enum RobotState {
awaiting_instruction,
moving_north,
moving_south,
moving_east,
moving_west
};
public static enum RobotInstruction {
NORTH,
SOUTH,
EAST,
WEST
}
public void draw(Graphics g);
}
class RobotPanel extends JPanel implements Constants, ActionListener {
private static final long serialVersionUID = 1L;
private Timer timer = new Timer(REFRESH_RATE, this);
private Map map = new Map();
private Robot robot = new Robot(map);
public RobotPanel() {
timer.start();
}
public Dimension getPreferredSize() { return PANEL_SIZE; }
public Dimension getMinimumSize() { return PANEL_SIZE; }
public Dimension getMaximumSize() { return PANEL_SIZE; }
protected void paintComponent(Graphics g) {
super.paintComponent(g);
map.draw(g);
robot.draw(g);
draw(g);
}
public void actionPerformed(ActionEvent e) {
robot.update();
repaint();
}
public void draw(Graphics g) {
for(int r = 0; r < NUM_TILE_ROWS; r++) {
for(int c = 0; c < NUM_TILE_COLS; c++) {
g.drawRect(c * TILE_WIDTH, r * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
}
}
}
}
class Robot implements Constants {
private RobotState state = RobotState.moving_east;
private int row = TILE_HEIGHT;
private int col = TILE_WIDTH;
private int mapX = 1;
private int mapY = 1;
private Map map;
int nextRowCheck = 1;
int nextColCheck = 2;
public Robot(Map m) {
map = m;
}
public int getRow() {
return mapY;
}
public int getCol() {
return mapX;
}
private boolean needsNewInstruction(){
int newRow = row;
int newCol = col;
if(state == RobotState.moving_north) newRow -= PIXEL_STEPS;
if(state == RobotState.moving_south) newRow += PIXEL_STEPS;
if(state == RobotState.moving_east) newCol += PIXEL_STEPS;
if(state == RobotState.moving_west) newCol -= PIXEL_STEPS;
if((newRow / TILE_HEIGHT) != mapY) return true;
if((newCol / TILE_WIDTH) != mapX) return true;
return false;
}
public void draw(Graphics g) {
Color c = g.getColor();
g.setColor(Color.GREEN);
g.fillRect(col, row, TILE_WIDTH, TILE_HEIGHT);
g.setColor(c);
}
public void update() {
System.out.println("UPDATE [" + row + "][" + col + "] = [" + (row / TILE_HEIGHT) + "][" + (col / TILE_WIDTH) + "]");
if(needsNewInstruction()) {
System.out.println("NEEDS NEW INSTRUCTION [" + row + "][" + col + "] = [" + (row / TILE_HEIGHT) + "][" + (col / TILE_WIDTH) + "]");
mapX = nextColCheck;
mapY = nextRowCheck;
System.out.println("UPDATED MAP REFERENCE [" + mapY + "][" + mapX + "]");
row = mapY * TILE_HEIGHT;
col = mapX * TILE_WIDTH;
System.out.println("UPDATED PIXEL REFERENCE [" + row + "][" + col + "]");
RobotInstruction instruction = map.getNextInstruction(this);
if(instruction == RobotInstruction.NORTH) {
state = RobotState.moving_north;
nextRowCheck = mapY - 1;
}
if(instruction == RobotInstruction.SOUTH) {
state = RobotState.moving_south;
nextRowCheck = mapY + 1;
}
if(instruction == RobotInstruction.EAST) {
state = RobotState.moving_east;
nextColCheck = mapX + 1;
}
if(instruction == RobotInstruction.WEST) {
state = RobotState.moving_west;
nextColCheck = mapX - 1;
}
}
move();
}
public void move() {
if(state == RobotState.moving_north) row -= PIXEL_STEPS;
if(state == RobotState.moving_south) row += PIXEL_STEPS;
if(state == RobotState.moving_east) col += PIXEL_STEPS;
if(state == RobotState.moving_west) col -= PIXEL_STEPS;
}
}
class Map implements Constants {
int[][] map = new int[][] {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
public Map() {
}
public RobotInstruction getNextInstruction(Robot robot) {
int row = robot.getRow();
int col = robot.getCol();
System.out.println("GET NEXT INSTRUCTION FOR [" + row + "][" + col + "]");
if(map[row][col + 1] == 0) return RobotInstruction.EAST;
if(map[row + 1][col] == 0) return RobotInstruction.SOUTH;
if(map[row - 1][col] == 0) return RobotInstruction.NORTH;
if(map[row][col - 1] == 0) return RobotInstruction.WEST;
return null;
}
public void draw(Graphics g) {
Color color = g.getColor();
for(int r = 0; r < NUM_TILE_ROWS; r++) {
for(int c = 0; c < NUM_TILE_COLS; c++) {
g.setColor(map[r][c] == 0 ? Color.CYAN : Color.RED);
g.fillRect(c * TILE_WIDTH, r * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
}
}
g.setColor(color);
}
}
Here is an example how to populate your navigational array with directions. the code above doesn't use the code below so you would have to do that yourself ...
public class Maze {
private static final char E = 'E'; // Ending position
private static final char X = 'X'; // Wall
private static final char O = ' '; // Space
private static final char L = 'L'; // Left
private static final char R = 'R'; // Right
private static final char U = 'U'; // Up
private static final char D = 'D'; // Down
private static final char FALSE = '0'; // Not accessible
private static final char TRUE = '1'; // Is accessible
private static final Node END_NODE = new Node(4, 4);
private static final int[] ROW_DIRECTIONS = {-1, 1, 0, 0};
private static final int[] COL_DIRECTIONS = { 0, 0, -1, 1};
private static final char[][] OPPOSITES = new char[][] {{O, D, O},{R, O, L},{O, U, O}};
public static void main(String[] args) {
char[][] maze = new char[][] {
{X, X, X, X, X, X},
{X, O, O, X, O, X},
{X, O, X, X, O, X},
{X, O, O, O, X, X},
{X, X, O, X, O, X},
{X, O, O, O, O, X},
{X, O, X, X, O, X},
{X, X, X, X, X, X}};
// PLOT THE DESTINATION CELL AND ADD IT TO LIST
List<Node> nodes = new ArrayList<Node>();
nodes.add(END_NODE);
maze[END_NODE.row][END_NODE.col] = E;
// PRINT THE MAZE BEFORE ANY CALCULATIONS
printMaze(maze);
// SOLVE THE MAZE
fillMaze(maze, nodes);
printMaze(maze);
// CONVERT MAZE TO AN ADJACENCY MATRIX
compileMaze(maze);
printMaze(maze);
}
/**
* The parallel arrays define all four directions radiating from
* the dequeued node's location.
*
* Each node will have up to four neighboring cells; some of these
* cells are accessible, some are not.
*
* If a neighboring cell is accessible, we encode it with a directional
* code that calculates the direction we must take should we want to
* navigate to the dequeued node's location from this neighboring cell.
*
* Once encoded into our maze, this neighboring cell is itself queued
* up as a node so that recursively, we can encode the entire maze.
*/
public static final void fillMaze(char[][] maze, List<Node> nodes) {
// dequeue our first node
Node destination = nodes.get(0);
nodes.remove(destination);
// examine all four neighboring cells for this dequeued node
for(int index = 0; index < ROW_DIRECTIONS.length; index++) {
int rowIndex = destination.row + ROW_DIRECTIONS[index];
int colIndex = destination.col + COL_DIRECTIONS[index];
// if this neighboring cell is accessible, encode it and add it
// to the queue
if(maze[rowIndex][colIndex] == O) {
maze[rowIndex][colIndex] = getOppositeDirection(ROW_DIRECTIONS[index], COL_DIRECTIONS[index]);
nodes.add(new Node(rowIndex, colIndex));
}
}
// if our queue is not empty, call this method again recursively
// so we can fill entire maze with directional codes
if(nodes.size() > 0) {
fillMaze(maze, nodes);
}
}
/**
* Converts the maze to an adjacency matrix.
*/
private static void compileMaze(char[][] maze) {
for(int r = 0; r < maze.length; r++) {
for(int c = 0; c < maze[0].length; c++) {
if(maze[r][c] == X || maze[r][c] == O) {
maze[r][c] = FALSE;
}
else {
maze[r][c] = TRUE;
}
}
}
}
/**
* prints the specified two dimensional array
*/
private static final void printMaze(char[][] maze) {
System.out.println("====================================");
for(int r = 0; r < maze.length; r++) {
for(int c = 0; c < maze[0].length; c++) {
System.out.print(maze[r][c] + " ");
}
System.out.print("\n");
}
System.out.println("====================================");
}
/**
* Simply returns the opposite direction from those specified
* by our parallel direction arrays in method fillMaze.
*
* coordinate 1, 1 is the center of the char[][] array and
* applying the specified row and col offsets, we return the
* correct code (opposite direction)
*/
private static final char getOppositeDirection(int row, int col) {
return OPPOSITES[1 + row][1 + col];
}
}
class Node {
int row;
int col;
public Node(int rowIndex, int colIndex) {
row = rowIndex;
col = colIndex;
}
}
Related
How to generate random integer that are random "enough"?
I'm trying to solve the 280th problem in Project Euler, and for this I have written the following simulation; #include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> /* Directions 1 2 3 4 */ int grid[5][5] = { {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2} }; int InitPos[2] = {2, 2}; int MaxExp = 5000000; bool Success = false; int StepCount = 0; int ExpNumber = 1; int AntsBag = 0; void Init(); void CarryFood(int * pos); void LeftFood(int * pos); bool checkMovability(int * pos, int direction); bool moveToDirection(int pos[2], int direction); bool checkSuccess(); void ShowResult(); int main(int argc, char const *argv[]) { timeval curTime; gettimeofday(&curTime, NULL); int milli = curTime.tv_usec / 1000; time_t t; srand((unsigned)time(&t)); //timeTData*.txt corresponds to using "time(&t)" above //milliData.txt corresponds to using "milli" variable above //timeTUnsigData*.txt corresponds to using "(unsigned)time(&t)" above printf("%% Experiment Number : %d \n", MaxExp); while(ExpNumber <= MaxExp) { Init(); int pos[2]; pos[0] = InitPos[0]; pos[1] = InitPos[1]; do{ int direction = (rand() % 4) + 1; if (moveToDirection(pos, direction)) { StepCount++; } if (pos[1] == 4&&grid[pos[0]][4]==2&&AntsBag==0) { CarryFood(pos); } if (pos[1] == 0&&grid[pos[0]][0]==0&&AntsBag==2) { LeftFood(pos); } checkSuccess(); } while(!Success); ShowResult(); ExpNumber++; } return 0; } void Init() { Success = false; StepCount = 0; AntsBag = 0; int gridInit[5][5] = { {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2}, {0, 0, 0, 0, 2} }; for (int i = 0; i < 5; ++i) { for (int j = 0; j < 5; ++j) { grid[i][j] = gridInit[i][j]; } } } void ShowResult() { /* for (int i = 0; i < 5; ++i) { printf("\n"); for (int j = 0; j < 5; ++j) { printf("%d ", grid[i][j]); } } */ printf("%d %d\n", StepCount, ExpNumber); } void CarryFood(int * pos) { AntsBag = 2; grid[pos[0]][4] = 0; } void LeftFood(int * pos) { AntsBag = 0; grid[pos[0]][0] = 2; } bool checkMovability(int * pos, int direction) { switch(direction) { case 1: { if(pos[1]==0){ return false; } break; } case 2: { if (pos[0]==0) { return false; } break; } case 3: { if (pos[0]==4) { return false; } break; } case 4: { if (pos[1]==4) { return false; } break; } default: { printf("Wrong direction input is given!!\n"); return false; break; } } return true; } bool moveToDirection(int * pos, int direction) { if ( !checkMovability(pos, direction) ) { return false; } switch(direction){ case 1: { pos[1] -= 1; break; } case 2: { pos[0] -= 1; break; } case 3: { pos[0] += 1; break; } case 4: { pos[1] += 1; break; } default: { printf("I'm stunned!\n"); return false; break; } } return true; } bool checkSuccess() { for (int i = 0; i < 5; ++i) { if (grid[i][0] != 2) { return false; } } //printf("Success!\n"); Success = true; return true; } And the redirected the output to a *.txt file and find the expected value of the number of steps with the following octave code; clear load data.txt n = data(:,1); output_precision(15); mean(n) %% The actual data %% milliData1 -> 430.038224000000 %% milliData2 -> 430.031745000000 %% timeTData1 -> 430.029882400000 %% timeTData2 -> 430.019626400000 %% timeUnsigData1 -> 430.028159000000 %% timeUnsigData2 -> 430.009509000000 However, even I run the exact same code twice I get different results, as you can see from the above results.(Note that, I have tried this with different srand(..) inputs for the reason I'm going to explain). I thought that the reason for this is because how I generate a random integer between 1-4 for the random directions of the ant, because as far as I have been though, the probability distribution of this experiment should be the same as long as I repeat the experiment large number of time (in this particular case 5000000 times). So my first question is that is it really the problem with the method of how I generate random integers ? If so, how can we overcome this problem, I mean how can we generate integer random enough so that when we repeat the same experiment large number of times, the expected value between those is smaller than these result that I have got ?
You can use something like std::mt19937 gen{std::random_device{}()}; std::uniform_int_distribution<int> dist{1, 4}; int randNumber = dist(gen); This generates a more uniform distribution of values.
What is the most efficient way to represent edge weights for Dijkstra's algorithm
I'm making a little game where I'm going to have a character on a grid that moves around. I was going to use Dijkstra's algorithm for the pathing as they move around. Only problem being is I want to make thin walls(instead of just removing nodes) like so: http://i.gyazo.com/85d110c17cf027d3ad0219fa26938305.png I was thinking the best way to do it was just edit the edge weights between 2 squares to be so high that it would never be crossed. Anyway, onto the question: What is the most efficient way to assign edge weights to each connection in the grid? I've thought about using an adjacency matrix, but for a 15x6 grid, that's a 90x90 matrix which seems... excessive. Any help would be nice, thanks (:
You only need to store edges between the rectilinear squares and a square can have at most 4 neighbors, once for each direction. Store the edge accessed by node as up to 4 entries of the enumeration {up, down, left, right}. That's is less than 90 x 4.
Some pointers that can help you decide what you should do: It seems your graph is unweighted, so you could use a BFS, which is both simpler to implement and more efficient than Dijkstra's algorithm in this case. 90x90 matrix is hardly an issue for a modern machine (unless you are going to use the pathfinding algorithm in a very tight loop) If you are using double as weights, a lot of languages got infinity value that you could use. In java that's Double.POSITIVE_INFINITY. Beauty about infinity - as much as you add to it, it stays infinity (and does not overflow like integers). You can always use adjacency lists, which can be thought of as a sparsed implementation of a matrix - where most edges have some constant predefined weight (infinity for example, for non existing edge). Note that using adjacency matrix rather than adjacency lists for very sparsed graph (like yours) makes the time complexity of BFS O(V^2) instead of O(V+E) (which is actually O(V) in your case), and O(V^2) for Dijkstra's algorithm instead of O(E + VlogV) (which is O(VlogV) for your graph)
I agree with rocky's answer - just store the weights for the four directions for each square in an array (each array element will be a struct/tuple which contains the four weights). To look up an edge between two arbitrary squares, you first check if they are adjacent, and if so use the appropriate weight from the array. Not sure why anyone mentioned adjacency lists or matrix, which are redundant here.
Try code below to create you game. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { object[,] input = { { new object[] { 0, -1, -1, 1, 6}, //index, left, up, right, down new object[] { 1, 0, -1, -1, 7}, //index, left, up, right, down new object[] { 2, -1, -1, 3, 8}, //index, left, up, right, down new object[] { 3, 2, -1, 4, 9}, //index, left, up, right, down new object[] { 4, 3, -1, -1, 10}, //index, left, up, right, down new object[] { 5, -1, -1, -1, 11} //index, left, up, right, down }, { new object[] { 6, -1, 0, 7, -1}, //index, left, up, right, down new object[] { 7, 6, 1, -1, 13}, //index, left, up, right, down new object[] { 8, -1, 2, 9, 14}, //index, left, up, right, down new object[] { 9, 8, 3, -1, -1}, //index, left, up, right, down new object[] {10, -1, 4, 11, -1}, //index, left, up, right, down new object[] {11, 10, 5, -1, 17} //index, left, up, right, down }, { new object[] {12, -1, -1, 13, 19}, //index, left, up, right, down new object[] {13, 12, 7, 14, 20}, //index, left, up, right, down new object[] {14, 13, 8, 15, 21}, //index, left, up, right, down new object[] {15, 14, -1, -1, 22}, //index, left, up, right, down new object[] {16, -1, -1, 17, 23}, //index, left, up, right, down new object[] {17, 16, 11, -1, 24} //index, left, up, right, down }, { new object[] {18, -1, 12, 19, 24}, //index, left, up, right, down new object[] {19, 18, 13, -1, 25}, //index, left, up, right, down new object[] {20, -1, 14, 21, 26}, //index, left, up, right, down new object[] {21, 20, 15, -1, 27}, //index, left, up, right, down new object[] {22, -1, 16, 23, 28}, //index, left, up, right, down new object[] {23, 22, 17, -1, 29} //index, left, up, right, down }, { new object[] {24, -1, 18, 25, -1}, //index, left, up, right, down new object[] {25, 24, 19, 26, -1}, //index, left, up, right, down new object[] {26, -1, 20, 27, -1}, //index, left, up, right, down new object[] {27, 26, 21, 28, -1}, //index, left, up, right, down new object[] {28, 27, 22, 29, -1}, //index, left, up, right, down new object[] {29, 28, 23, -1, -1} //index, left, up, right, down }, }; cell game = new cell(input); } } public class cell { public static cell[,] board = new cell[5, 6]; public int index { get; set; } //row number * 6 + col public int row { get; set;} public int col { get; set;} public cell up { get; set; } public cell down { get; set; } public cell left { get; set; } public cell right { get; set; } public cell() { } public cell(object[,] input) { int cellNumber = 0; int boardRow = 0; int boardCol = 0; int cellRow = 0; int cellCol = 0; for (int row = 0; row < 5; row++) { for (int col = 0; col < 6; col++) { board[row, col] = new cell(); } } for (int row = 0; row < 5; row++) { for (int col = 0; col < 6; col++) { object[] items = (object[])input[row, col]; cellNumber = (int)items[0]; boardRow = cellNumber / 6; boardCol = cellNumber % 6; board[boardRow, boardCol].index = cellNumber; board[boardRow, boardCol].row = row; board[boardRow, boardCol].col = col; cellNumber = (int)items[1]; cellRow = cellNumber / 6; cellCol = cellNumber % 6; if (cellNumber == -1) { board[boardRow, boardCol].left = null; } else { board[boardRow, boardCol].left = board[cellRow, cellCol]; } cellNumber = (int)items[2]; cellRow = cellNumber / 6; cellCol = cellNumber % 6; if (cellNumber == -1) { board[boardRow, boardCol].up = null; } else { board[boardRow, boardCol].up = board[cellRow, cellCol]; } cellNumber = (int)items[3]; cellRow = cellNumber / 6; cellCol = cellNumber % 6; if (cellNumber == -1) { board[boardRow, boardCol].right = null; } else { board[boardRow, boardCol].right = board[cellRow, cellCol]; } cellNumber = (int)items[4]; cellRow = cellNumber / 6; cellCol = cellNumber % 6; if (cellNumber == -1) { board[boardRow, boardCol].down = null; } else { board[boardRow, boardCol].down = board[cellRow, cellCol]; } } } } } }
Use this code to initialize the game board for large arrays. Then add nulls for location of walls making sure you add the walls to two cells. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { cell game = new cell(90, 100); } } public class cell { public static cell[,] board = null; public int index { get; set; } //row number * 6 + col public int row { get; set;} public int col { get; set;} public cell up { get; set; } public cell down { get; set; } public cell left { get; set; } public cell right { get; set; } public bool visited { get; set; } public cell() { } public cell(int rows, int cols) { board = new cell[rows, cols]; int cellNumber = 0; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { board[row, col] = new cell(); board[row, col].visited = false; } } for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { cellNumber = (row * cols) + col; board[row, col].index = cellNumber; board[row, col].row = row; board[row, col].col = col; if (col == 0) { board[row, col].left = null; } else { board[row, col].left = board[row, col - 1]; } if (row == 0) { board[row, col].up = null; } else { board[row, col].up = board[row - 1, col]; } if (col == cols - 1) { board[row, col].right = null; } else { board[row, col].right = board[row, col + 1]; } if (row == rows - 1) { board[row, col].down = null; } else { board[row, col].down = board[row + 1, col]; } } } } } }
Converting Relation to Matrix
I have 2 sets and 1 relation. I want to show them in a matrix. char a[] = "12345"; char b[] = "ABCDE"; char r[] = "1C2B3E4D5A"; int rel[LA][LA] = { /* A B C D E*/ /* 1*/{0, 0, 0, 0, 0} , /* 2*/{0, 0, 0, 0, 0} , /* 3*/{0, 0, 0, 0, 0} , /* 4*/{0, 0, 0, 0, 0} , /* 5*/{0, 0, 0, 0, 0} }; in the char array each char is an element char a[] = "12345"; is A{1,2,3,4,5} Relation char r[] = "1C2B3E4D5A"; is R= {(1,C),(2.B).... } My question is how can I Show them on Matrix that If there is a relation on A and B in R in the matrix this point get 1 . Output must like that : int rel[LA][LA] = { /* A B C D E*/ /* 1*/{0, 0, 1, 0, 0} , /* 2*/{0, 1, 0, 0, 0} , /* 3*/{0, 0, 0, 0, 1} , /* 4*/{0, 0, 0, 1, 0} , /* 5*/{1, 0, 0, 0, 0} }; Firstly I tried : for(i=0;i<LR-1;i=i+2){ // Look at element from A for(j=0;j<LA;j++){ // Look at A if(r[i]==a[j]){ for(k=1;k<LR;k=k+2){ // Look at element from B for(m=0;m<LA;m++){ // Look at B if(r[k]==b[m]){ rel[j][m]=1; // if both exist that point gets 1 } } } } } } It does not work.
Here is a solution to your problem: public static void main(String[] args) { char[] a = "12345".toCharArray(); char[] b = "ABCDE".toCharArray(); char[] r = "1C2B3E4D5A".toCharArray(); int LA=a.length; int LB=b.length; int LR=r.length; int[][] rel=new int[LA][LB]; for(int i=0;i<LR;i+=2){ int indexa=index(a,r[i]); int indexb=index(b,r[i+1]); rel[indexa][indexb]=1; } // Print out the matrix for(int i=0;i<LA;i++){ for(int j=0;j<LB;j++){ System.out.print(rel[i][j]); } System.out.println(""); } } /** * Return the position of a value v array arr */ public static int index(char[] arr,char v){ for(int i=0;i<arr.length;i++){ if(arr[i]==v){ return i; } } return -1; }
Tampering detection by using sobel edge in processing
I have to use Sobel edge detection to detect how an image has been tampered with. I have been able to implement the edge filter, but have not been able to figure out how to use it to detect tampering. I want to show the tampering by highlighting the region that has been tampered with in another color. Can someone help please? PImage img, edgeImg; int[][] sobelx = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } }; int[][] sobely = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; void setup() { img = loadImage("face1.jpg"); size(img.width, img.height); edgeImg = createImage(img.width, img.height, RGB); } void draw() { image(img, 0, 0); int matrixsize = 3; loadPixels(); img.loadPixels(); int loc = 0; for (int x = 1; x < img.width - 1; x++) { for (int y = 1; y < img.height - 1; y++) { loc = x + y * img.width; int sx = convolution(x, y, sobelx, matrixsize, img); int sy = convolution(x, y, sobely, matrixsize, img); int sum = abs(sy) + abs(sx); sum = constrain(sum, 0, 255); edgeImg.pixels[loc] = sum; } } edgeImg.updatePixels(); image(edgeImg, 0, 0); filter(THRESHOLD, 0.8); } int convolution(int x, int y, int [][] mat, int matrixsize, PImage img) { float rtotal = 0.0; float gtotal = 0.0; float btotal = 0.0; int total = 0; int offset = matrixsize/2; for(int i=0; i<matrixsize; i++) { for(int j=0; j<matrixsize; j++) { int xloc = x + i - offset; int yloc = y + j - offset; int loc = xloc + img.width*yloc; loc = constrain(loc,0,img.pixels.length - 1); rtotal = rtotal + red(img.pixels[loc])*mat[i][j]; gtotal = gtotal + green(img.pixels[loc])*mat[i][j]; btotal = btotal + blue(img.pixels[loc])*mat[i][j]; total = total + int(brightness(img.pixels[loc])*mat[i][j]); } } rtotal = constrain(rtotal, 0, 255); gtotal = constrain(gtotal, 0, 255); btotal = constrain(btotal, 0, 255); return total; }
I don't know how the algorithm can be used for your particular purpose, but I would guess you would need to run the same filter to the original image and compare the results. PImage original = loadImage("face1.jpg"); PImage edgeImg; // previously created original.loadPixels(); edgeImg.loadPixels(); for (int i=0; i<original.pixels.length; i++) { color origPx = original.pixels[i]; color edgePx = edgeImg.pixels[i]; // compare red values, since the edgeImg is B&W if ( (origPx >> 16 & 0xFF) != (edgePx >> 16 & 0xFF) ) { // don't match? do something! } }
Blackberry - fields layout animation
It's easy to show some animation within one field - BitmapField or Screen: [Blackberry - background image/animation RIM OS 4.5.0][1] But what if you need to move fields, not just images? May be used: game workflow functionality, like chess, puzzle etc application user-defined layout, like in Google gadgets enhanced GUI animation effects So, I'd like to exchange my expirience in this task, on the other hand, I'd like to know about any others possibilities and suggestions.
This effect may be easily achived with custom layout: class AnimatedManager extends Manager { int ANIMATION_NONE = 0; int ANIMATION_CROSS_FLY = 1; boolean mAnimationStart = false; Bitmap mBmpBNormal = Bitmap.getBitmapResource("blue_normal.png"); Bitmap mBmpBFocused = Bitmap.getBitmapResource("blue_focused.png"); Bitmap mBmpRNormal = Bitmap.getBitmapResource("red_normal.png"); Bitmap mBmpRFocused = Bitmap.getBitmapResource("red_focused.png"); Bitmap mBmpYNormal = Bitmap.getBitmapResource("yellow_normal.png"); Bitmap mBmpYFocused = Bitmap.getBitmapResource("yellow_focused.png"); Bitmap mBmpGNormal = Bitmap.getBitmapResource("green_normal.png"); Bitmap mBmpGFocused = Bitmap.getBitmapResource("green_focused.png"); int[] width = null; int[] height = null; int[] xPos = null; int[] yPos = null; BitmapButtonField mBButton = new BitmapButtonField(mBmpBNormal, mBmpBFocused); BitmapButtonField mRButton = new BitmapButtonField(mBmpRNormal, mBmpRFocused); BitmapButtonField mYButton = new BitmapButtonField(mBmpYNormal, mBmpYFocused); BitmapButtonField mGButton = new BitmapButtonField(mBmpGNormal, mBmpGFocused); public AnimatedManager() { super(USE_ALL_HEIGHT | USE_ALL_WIDTH); add(mBButton); add(mRButton); add(mYButton); add(mGButton); width = new int[] { mBButton.getPreferredWidth(), mRButton.getPreferredWidth(), mYButton.getPreferredWidth(), mGButton.getPreferredWidth() }; height = new int[] { mBButton.getPreferredHeight(), mRButton.getPreferredHeight(), mYButton.getPreferredHeight(), mGButton.getPreferredHeight() }; xPos = new int[] { 0, getPreferredWidth() - width[1], 0, getPreferredWidth() - width[3] }; yPos = new int[] { 0, 0, getPreferredHeight() - height[2], getPreferredHeight() - height[3] }; Timer timer = new Timer(); timer.schedule(mAnimationTask, 0, 100); } TimerTask mAnimationTask = new TimerTask() { public void run() { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { updateLayout(); }; }); }; }; MenuItem mAnimationMenuItem = new MenuItem("Start", 0, 0) { public void run() { mAnimationStart = true; }; }; protected void makeMenu(Menu menu, int instance) { super.makeMenu(menu, instance); menu.add(mAnimationMenuItem); } public int getPreferredHeight() { return Display.getHeight(); } public int getPreferredWidth() { return Display.getWidth(); } protected void sublayout(int width, int height) { width = getPreferredWidth(); height = getPreferredHeight(); if (getFieldCount() > 3) { Field first = getField(0); Field second = getField(1); Field third = getField(2); Field fourth = getField(3); layoutChild(first, this.width[0], this.height[0]); layoutChild(second, this.width[1], this.height[1]); layoutChild(third, this.width[2], this.height[2]); layoutChild(fourth, this.width[3], this.height[3]); if (mAnimationStart) { boolean anim1 = performLayoutAnimation(0, width - this.width[0], height - this.height[0]); boolean anim2 = performLayoutAnimation(1, 0, height - this.height[1]); boolean anim3 = performLayoutAnimation(2, width - this.width[2], 0); boolean anim4 = performLayoutAnimation(3, 0, 0); mAnimationStart = anim1 || anim2 || anim3 || anim4; } setPositionChild(first, xPos[0], yPos[0]); setPositionChild(second, xPos[1], yPos[1]); setPositionChild(third, xPos[2], yPos[2]); setPositionChild(fourth, xPos[3], yPos[3]); } setExtent(width, height); } boolean performLayoutAnimation(int fieldIndex, int x, int y) { boolean result = false; if (xPos[fieldIndex] > x) { xPos[fieldIndex] -= 2; result = true; } else if (xPos[fieldIndex] < x) { xPos[fieldIndex] += 2; result = true; } if (yPos[fieldIndex] > y) { yPos[fieldIndex] -= 1; result = true; } else if (yPos[fieldIndex] < y) { yPos[fieldIndex] += 1; result = true; } return result; } } BitmapButtonField class I've used: class BitmapButtonField extends ButtonField { Bitmap mNormal; Bitmap mFocused; int mWidth; int mHeight; public BitmapButtonField(Bitmap normal, Bitmap focused) { super(CONSUME_CLICK); mNormal = normal; mFocused = focused; mWidth = mNormal.getWidth(); mHeight = mNormal.getHeight(); setMargin(0, 0, 0, 0); setPadding(0, 0, 0, 0); setBorder(BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0))); setBorder(VISUAL_STATE_ACTIVE, BorderFactory .createSimpleBorder(new XYEdges(0, 0, 0, 0))); } protected void paint(Graphics graphics) { Bitmap bitmap = null; switch (getVisualState()) { case VISUAL_STATE_NORMAL: bitmap = mNormal; break; case VISUAL_STATE_FOCUS: bitmap = mFocused; break; case VISUAL_STATE_ACTIVE: bitmap = mFocused; break; default: bitmap = mNormal; } graphics.drawBitmap(0, 0, bitmap.getWidth(), bitmap.getHeight(), bitmap, 0, 0); } public int getPreferredWidth() { return mWidth; } public int getPreferredHeight() { return mHeight; } protected void layout(int width, int height) { setExtent(mWidth, mHeight); } protected void applyTheme(Graphics arg0, boolean arg1) { } }