Below is the code I am referring to, and the first recursive call # checkDirections(grid, i - 1, j) is giving me a StackOverFlow error. I understand that this means the code is not hitting the base case, but I do not understand why.
class Solution {
public int orangesRotting(int[][] grid) {
int rowLength = grid.length;
int colLength = grid[0].length;
int minMinutes = 0;
for (int i = 0; i < rowLength; i++) {
for (int j = 0; j < colLength; j++) {
if (grid[i][j] == 2) {
checkDirections(grid, i, j);
}
}
}
return minMinutes;
}
public void checkDirections(int[][] grid, int i, int j) {
if ((i < 0 || i > grid.length || j < 0 || j > grid[0].length) || grid[i][j] == 0) {
return;
} else if (grid[i][j] == 1) {
grid[i][j] = 2;
return;
}
//check left
checkDirections(grid, i - 1, j);
//check right
checkDirections(grid, i + 1, j);
//check up
checkDirections(grid, i, j - 1);
//check down
checkDirections(grid, i, j + 1);
}
}
Currently I'm trying to replicate this wonderful project https://www.youtube.com/watch?v=u8pwmzUVx48, though with more minimum hardware, in which for the classification i'm using a neural network embbeded inside the arduino uno which had been trained offline in more stronger PC. The code of the classifier is here
#include <math.h>
#include <Wire.h>
double dataMagnitude[100];
double feature[7];
double feat_hid[10];
double output[4];
int classi;
const double w_hid[8][10] =
{
{18.9336670380822,11.9186055569093,-5.40114594311576,-21.1410711100689,-49.7798510124792,-14.8215222433047,-34.7308138535581,118.348601654702,-13.6275407707706,-11.6090487951753},
{-21.4994463865001,72.0672467700052,4.05328299052883,21.4875491464005,51.1604296852446,-15.8459578543758,6.30350750703905,-152.565733734759,12.8648040583067,13.8199895673734},
{8.66214515599865,-200.488705071393,-5.86973559011113,-23.4805286444925,-1.11016147795671,-3.04686605995311,-93.4143749063794,-73.8925691072615,-6.18427236042285,-10.9872535411407},
{-12.317892447947,-37.2154526807162,3.83978412266769,2.12866508710205,-11.9740446238331,10.2198116665101,41.9369083083022,63.2036147993661,1.40768362243561,15.4978881385563},
{7.58319670243546,161.895072542918,-2.3654701067923,1.91708846557259,-2.87224127392426,-16.5850302581614,45.2372430254377,34.255971511768,-2.30234070310014,-7.8952356779332},
{0.603971580989218,128.0244079393,0.628535912033608,-1.25788426737745,-0.204480047424961,-41.3372322514891,3.26860448943873,4.163893213914,0.443532051478394,-0.276136697942473},
{-3.63944154925129,18.3802540188974,0.975095285922393,-0.326187652485656,1.25521855841132,39.4877166809573,-15.3542772116519,-14.9546824078715,0.965532742621277,3.72386985716534},
{5.93321854314305,12.673690719929,-3.36580252980446,-21.2089241183081,-10.8980644878121,-7.29095431091201,-30.2240843969778,-2.48980394834853,-5.4167647620581,-5.68671825319015}
}, w_out[11][4] =
{
{1.07887052819228,-21.9615926704441,105.450147012522,-84.5674248703326},
{0.0344508533215184,0.551350792323934,-0.96380329372866,0.37800164808339},
{-99.251397621058,23.1671754381478,7.53147169676884,68.5527504861813},
{-5.0354869957171,4.36918523413481,0.408725687040089,0.257576074543764},
{-27.4478368365984,7.00659524306471,1.74370945871769,18.6975321348269},
{-0.213736004615516,-0.784795805217531,0.0732416484342244,0.925290161399087},
{8.62052547929066,-45.9408034639393,116.959261953552,-79.6389839689755},
{-8.5317661802465,45.4251911929737,-117.146523754862,80.2530987422069},
{127.053878005091,-29.4397580015468,-9.33919798608733,-88.2749220175082},
{1.11869995358251,-21.5111648695486,105.002356379838,-84.6098914639344},
{-5.81786935588552,3.78305066207264,0.11556429335063,-0.0807455995360207}
};
double S, Sig, Sigma, Sigma1, Sigma2, MAV, RMS, VAR, SDT, WL, ZC, SSC, Xn, accum, accumi;
char analogpin = 0, N=100;
void setup()
{
/* add setup code here */
Serial.begin(9600);
Wire.begin();
}
void loop()
{
do{
//data acqusition
for( int i = 0; i<100;i++)
{
Xn = (analogRead(analogpin))-510;
dataMagnitude[i]=Xn;
delayMicroseconds(830);
// Serial.println(dataMagnitude[i]);
}
S = 0;
for (size_t i = 0; i < N; i++)
{
S = S + dataMagnitude[i];
}
Sig = 0;
Sigma = 0;
Sigma1 = 0;
Sigma2 = 0;
for (size_t i = 0; i < N; i++)
{
Sig = Sig + abs(dataMagnitude[i]);
Sigma = Sigma + pow(dataMagnitude[i], 2);
Sigma1 = Sigma1 + pow((dataMagnitude[i] - S / N), 2);
}
for (size_t i = 0; i < N - 1; i++)
{
Sigma2 = Sigma2 + abs(dataMagnitude[i + 1] - dataMagnitude[i]);
}
//featureextract
MAV = (((1 / (double)N)*Sig-27.67)*2/(272.02-27.67))-1;
RMS = (sqrt((1 / (double)N)*Sigma)-34.91002721)*2/(284.1419012-34.91002721)-1;
VAR = (((1 / (double)(N))*Sigma1)-698.4139)*2/(52178.5691-698.4139)-1;
SDT = (sqrt((1 / (double)(N)) * Sigma1)-26.42752164)*2/(228.4262881-26.42752164)-1;
WL = (Sigma2-1621)*2/(11273-1621)-1;
//ZC = 0;
for (size_t i = 0; i < N - 1; i++)
{
if (dataMagnitude[i] == 0 && dataMagnitude[i] != dataMagnitude[i + 1])
{
ZC++;
}
}
ZC = (ZC-0)*2/(39-0)-1;
//SSC = 0;
for (size_t i = 0; i < N - 2; i++)
{
if (dataMagnitude[i]>dataMagnitude[i + 1] && dataMagnitude[i + 1]<dataMagnitude[i + 2])
{
SSC++;
}
else if (dataMagnitude[i]<dataMagnitude[i + 1] && dataMagnitude[i + 1]>dataMagnitude[i + 2])
{
SSC++;
}
}
SSC = (SSC-48)*2/(78-48)-1;
double feature[] = { MAV, RMS, VAR, SDT, WL, ZC, SSC };
//neural network construction
//first-hidden layer
for (int i = 0; i < 10; i++)
{
accum = w_hid[7][i];
for (int j = 0; j < 7; j++)
{
accum += (feature[j] * w_hid[j][i]);
}
feat_hid[i] = tanh(accum);
}
for (int i = 0; i < 4; i++)
{
accumi = w_out[10][i];
for (int j = 0; j < 10; j++)
{
accumi += (feat_hid[j] * w_out[j][i]);
}
output[i] = round(accumi);
}
//Classify the output
if (output[0] == 1 && output[1] < 1 && output[2] < 1 && output[3] < 1)
{
classi = 1;
}
else if (output[0] < 1 && output[1] == 1 && output[2] < 1 && output[3] < 1)
{
classi = 2;
}
else if (output[0] < 1 && output[1] < 1 && output[2] == 1 && output[3] < 1)
{
classi = 3;
}
else if (output[0] < 1 && output[1] < 1 && output[2] < 1 && output[3] == 1)
{
classi = 4;
}
else
{
classi = 0;
}
Wire.beginTransmission(5);
Wire.write(classi);
//Wire.write(int(output[2]));
Wire.endTransmission();
Serial.println("wew");
Serial.println(output[0]);
Serial.println(output[1]);
Serial.println(output[2]);
Serial.println(output[3]);
//Serial.println(classi);
//Serial.println(feature[1]);
//Serial.println(feature[2]);
//Serial.println(feature[3]);
//Serial.println(feature[4]);
//Serial.println(feature[5]);
//Serial.println(feature[6]);
for (size_t i = 0; i < 10; i++)
{
feat_hid[i] = 0;
}
for (size_t i = 0; i < 4; i++)
{
output[i] = 0;
}
}while(analogRead(analogpin)>0);
}
But the real time implementation is rather dissatisfying, in which the output always mismatched, though by offline implementation is quite better.
My assumption is that the data capturing when online is rather bad, or maybe because any other things?
Thanks for any feedback
How did you train the network offline?
If you have used Matlab to train the network (i.e. to identify the weight and bias values) and then implement the same network on Arduino.
In such case we have problems with number precision. Matlab by default works on 64 bit precision whereas Arduino works on 32 bit.
Difference in the way the numbers are represented creates the Error.
I am writing the recursive method for a minesweeper game and I am encountering a stackOverflow error in the recursive method that clears out empty spaces, The error does not occur when checking for 3 of the surrounding spaces but only when checking all eight. Can you please help identify the issue?
The stack trace is :
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.awt.Component.firePropertyChange(Component.java:8419)
at javax.swing.AbstractButton.setText(AbstractButton.java:306)
at Minesweeper.Minesweeper.showTile(Minesweeper.java:105)
at Minesweeper.Minesweeper.clearEmpty(Minesweeper.java:137)
at Minesweeper.Minesweeper.clearEmpty(Minesweeper.java:177)
The class:
public class Minesweeper implements ActionListener {
JFrame frame = new JFrame("Minesweeper");
JButton reset = new JButton("Reset");
JButton solve = new JButton("Solve");
JToggleButton[][] buttons = new JToggleButton[20][20];
int[][] counts = new int [20][20];
Container grid = new Container();
final int MINE = 10;
public static void main(String[] args)
{
new Minesweeper();
}
public Minesweeper()
{
frame.setSize(600, 600);
frame.setLayout(new BorderLayout());
frame.add(reset, BorderLayout.NORTH);
frame.add(solve, BorderLayout.SOUTH);
reset.addActionListener(this);
solve.addActionListener(this);
grid.setLayout(new GridLayout(20, 20));
for (int r = 0; r < buttons.length; r++) {
for (int c = 0; c < buttons[0].length; c++) {
buttons[r][c] = new JToggleButton();
buttons[r][c].addActionListener(this);
grid.add(buttons[r][c]);
buttons[r][c].setSize(frame.getWidth() / 20, frame.getHeight() / 22);
}
}
frame.add(grid,BorderLayout.CENTER);
addRandomMines();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void addRandomMines()
{
ArrayList<Integer> mineList = new ArrayList<Integer>();
for (int x = 0; x < counts.length; x++) {
for (int y = 0; y < counts[0].length; y++){
mineList.add((x*100)+y);
}
}
counts = new int[20][20];
for (int i = 0; i < 30; i++) {
int choice = (int)(Math.random()*mineList.size());
counts[mineList.get(choice)/100][mineList.get(choice)%100] = MINE;
mineList.remove(choice);
}
for (int x = 0; x < counts.length; x++) {
for (int y = 0; y < counts[0].length; y++){
if (counts[x][y]!=MINE) {
int mineCount = 0;
if (x > 0 && y > 0 && counts[x - 1][y - 1] == MINE)
mineCount++;
if (y > 0 && counts[x][y - 1] == MINE)
mineCount++;
if (x > 0 && counts[x - 1][y] == MINE)
mineCount++;
if (x < counts.length - 1 && counts[x + 1][y] == MINE)
mineCount++;
if (y < counts.length - 1 && counts[x][y + 1] == MINE)
mineCount++;
if (x < counts.length - 1 && y < counts.length - 1 && counts[x + 1][y + 1] == MINE)
mineCount++;
if (x > 0 && y < counts.length - 1 && counts[x - 1][y + 1] == MINE)
mineCount++;
if (x < counts.length - 1 && y > 0 && counts[x + 1][y - 1] == MINE)
mineCount++;
counts[x][y] = mineCount;
}
}
}
}
public void showTile(int r, int c)
{
if (counts[r][c] == 0) {
buttons[r][c].setText("");
buttons[r][c].setSelected(true);
}
else if (counts[r][c]==MINE) {
buttons[r][c].setForeground(Color.red);
buttons[r][c].setText("X");
buttons[r][c].setSelected(true);
}
else {
buttons[r][c].setText(counts[r][c] + "");
if (counts[r][c]==1)
buttons[r][c].setForeground(Color.blue);
else if (counts[r][c]==2)
buttons[r][c].setForeground(Color.magenta);
else if (counts[r][c]==3)
buttons[r][c].setForeground(Color.green);
buttons[r][c].setSelected(true);
}
}
public void lostGame() {
for (int x = 0; x < buttons.length; x++) {
for (int y = 0; y < buttons[0].length; y++) {
if (counts[x][y]==MINE) {
showTile(x, y);
}
}
}
}
public void clearEmpty(ArrayList<Integer> toClear)
{
if (toClear.size()==0){
return;
}
else {
int x = toClear.get(0)/100;
int y = toClear.get(0)%100;
toClear.remove(0);
if (counts[x][y]==0) {
if (x > 0 && y > 0) {
showTile(x-1,y-1);
if (counts[x-1][y-1]==0)
toClear.add((x-1)*100 + (y-1));
}
if (y > 0) {
showTile(x,y-1);
if (counts[x][y-1]==0)
toClear.add(x*100 + (y-1));
}
if (x <counts.length-1 && y > 0) {
showTile(x+1,y-1);
if (counts[x+1][y-1]==0)
toClear.add((x+1)*100 + (y-1));
}
if (x > 0) {
showTile(x-1,y);
if (counts[x-1][y]==0)
toClear.add((x-1)*100 + y);
}
if (x <counts.length-1 && y > 0) {
showTile(x+1,y);
if (counts[x+1][y]==0)
toClear.add((x+1)*100 + y);
}
if (x > 0 && y < counts[0].length-1) {
showTile(x-1,y+1);
if (counts[x-1][y+1]==0)
toClear.add((x-1)*100 + (y+1));
}
if (y < counts[0].length-1) {
showTile(x,y+1);
if (counts[x][y+1]==0)
toClear.add(x*100 + (y+1));
}
if (x <counts.length-1 && y < counts[0].length-1) {
showTile(x+1,y+1);
if (counts[x+1][y+1]==0)
toClear.add((x+1)*100 + (y+1));
}
}
clearEmpty(toClear);
}
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(reset)) {
for (int r = 0; r < buttons.length; r++) {
for (int c = 0; c < buttons[0].length; c++) {
buttons[r][c].setSelected(false);
buttons[r][c].setText("");
}
}
addRandomMines();
} else if (event.getSource().equals(solve)) {
} else {
for (int r = 0; r < buttons.length; r++) {
for (int c = 0; c < buttons[0].length; c++) {
if (event.getSource().equals(buttons[r][c])) {
if (counts[r][c] == MINE) {
showTile(r, c);
lostGame();
}
else if (counts[r][c] == 0) {
ArrayList<Integer> toClear = new ArrayList<Integer>();
toClear.add(r*100+c);
clearEmpty(toClear);
}
else {
showTile(r, c);
}
}
}
}
}
}
}
I think that you're using the wrong algorithm...
Try to use an iterative instead of an recursive approach.
As User404 already mentioned your current algorithm keeps the list growing...
For your implementation: you have 400 tiles. Assuming (worst case) all tiles are empty you call your method clearEmpty() once. You will find out that all 8 neighbors are empty so you add this 8 neighbors to the list while only removing the first one. Now you pass the array to the method again (2nd call) and will find 8 neighbors for the first entry again. So your 3rd call will have a list with 15 tiles.
Real problem
This way you will never come to an end as you never check if the current checked tile is already cleared but you only add to the list more than you will ever remove.
Solution
At least you should check if the tile you want to add to the list is already cleared or is already in the list.
You example is a clear example why recursive algorithms should be used with care as the termination is difficult sometimes and also you have to take care that no work is done multiple times.
This dynamic programming algorithm is returning unhandled exception error probably due to the two dimensional arrays that I am using for various (and very large) number of inputs. I can't seem to figure out the issue here. The complete program as follows:
// A Dynamic Programming based solution for 0-1 Knapsack problem
#include<stdio.h>
#include<stdlib.h>
#define MAX 10000
int size;
int Weight;
int p[MAX];
int w[MAX];
// A utility function that returns maximum of two integers
int maximum(int a, int b) { return (a > b) ? a : b; }
// Returns the maximum value that can be put in a knapsack of capacity W
int knapSack(int W, int wt[], int val[], int n)
{
int i, w;
int retVal;
int **K;
K = (int**)calloc(n+1, sizeof(int*));
for (i = 0; i < n + 1; ++i)
{
K[i] = (int*)calloc(W + 1, sizeof(int));
}
// Build table K[][] in bottom up manner
for (i = 0; i <= n; i++)
{
for (w = 0; w <= W; w++)
{
if (i == 0 || w == 0)
K[i][w] = 0;
else if (wt[i - 1] <= w)
K[i][w] = maximum(val[i - 1] + K[i - 1][w - wt[i - 1]], K[i - 1][w]);
else
K[i][w] = K[i - 1][w];
}
}
retVal = K[n][W];
for (i = 0; i < size + 1; i++)
free(K[i]);
free(K);
return retVal;
}
int random_in_range(unsigned int min, unsigned int max)
{
int base_random = rand();
if (RAND_MAX == base_random) return random_in_range(min, max);
int range = max - min,
remainder = RAND_MAX % range,
bucket = RAND_MAX / range;
if (base_random < RAND_MAX - remainder) {
return min + base_random / bucket;
}
else {
return random_in_range(min, max);
}
}
int main()
{
srand(time(NULL));
int val = 0;
int i, j;
//each input set is contained in an array
int batch[] = { 10, 20, 30, 40, 50, 5000, 10000 };
int sizeOfBatch = sizeof(batch) / sizeof(batch[0]);
//algorithms are called per size of the input array
for (i = 0; i < sizeOfBatch; i++){
printf("\n");
//dynamic array allocation (variable length to avoid stack overflow
//calloc is used to avoid garbage values
int *p = (int*)calloc(batch[i], sizeof(int));
int *w = (int*)calloc(batch[i], sizeof(int));
for (j = 0; j < batch[i]; j++){
p[j] = random_in_range(1, 500);
w[j] = random_in_range(1, 100);
}
size = batch[i];
Weight = batch[i] * 25;
printf("| %d ", batch[i]);
printf(" %d", knapSack(Weight, w, p, size));
free(p);
free(w);
}
_getch();
return 0;
}
Change this:
for (i = 0; i < size + 1; i++)
free(K[i]);
free(K);
return K[size][Weight];
To this:
int retVal;
...
retVal = K[size][Weight];
for (i = 0; i < size + 1; i++)
free(K[i]);
free(K);
return retVal;