-2

In the code below i try to read a file with the size of a 2d array and the numbers for each cell. Then the program must find a number that can be added in the cell with a zero value in magic array. All this in order to create magic squares based on the initialized magic array with the elements of the external file. The problem is that i always get the message "magic squares cannot be created" even when the if statement in next_successor method get true from all the arguments? where is the problem? i got really stuck any help will be appreciated!

so i think the main problem is with the methods:

  1. next_successor
  2. check_row
  3. check_column
  4. check_diagonals

The rules that i have to follow in order to create the methods are: In order for current_number to be inserted into magic[row,column], the following checks (by check_row(), check_column() and check_diagonals()) should be made:

  • For each of the row, column, and possibly main diagonals (in the case of row=column or row=N-column-1) to which position magic[row,column] belongs, and for each current_number that does not has yet been inserted into the magic square (according to the value used[current_number-1]), we perform the following checks to decide whether current_number can be inserted into magic[row,column]:
  • Suppose (in the row or column or main diagonal where the position magic[row,column]) is located after the number current_number is placed in the position magic[row,column], m positions have been filled, so there are N-m empty positions left to be filled.
  • Let be the sum of the numbers already in the row or column or main diagonal (including current_number).
  • Let be the sum of the − smallest numbers (from 1 to N*N) not yet entered into the magic square (according to the table used) and the sum of the − largest numbers not yet entered (similarly) . If = then ==0.
  • Let be the magic constant. If +> or +<, for some row or column or main diagonal to which magic[row, column] belongs, then current_number cannot be inserted into position magic[row,column ], i.e. the respective check_row(), check_column() and check_diagonals() will return false, otherwise they will all return true.

the txt external file has the following elements:

6
0 0 13 0 20 0
0 15 0 0 0 12
8 0 2 0 31 0
0 14 0 7 0 1
28 0 0 0 0 0
0 0 6 0 0 21
import java.io.*;
import java.util.*;


public class MainSolver{
    static ArrayList<MagicSquare> stuckAL;
    static Stack<MagicSquare> stuckST;
    static LinkedList<MagicSquare> stuckLL;
    static int datastructure; 
    static int N = 0;
    static int[][] input;
    
    public static void main() throws IOException {
        //THE PROGRAM READS THE EXTERNAL FILE
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter the file name: ");
        String fileName = sc.next();
        System.out.println("Enter data structure to use: (arraylist, stack, queue, linkedlist): ");
        System.out.println("1: arraylist");
        System.out.println("2: stack");
        System.out.println("3: queue");
        System.out.println("4: linkedlist");
        datastructure = sc.nextInt();
        
        File file = new File(fileName);
        Scanner fileScanner = new Scanner(file);
        
        N = fileScanner.nextInt();
        input = new int[N][N];

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                input[i][j] = fileScanner.nextInt();
            }
        }
        
        MagicSquare.size = N;
        MagicSquare ms = new MagicSquare();
        
        for(int i=0; i<N ;i++){
            for(int j=0; j<N ;j++){
                ms.set_cell(i,j,input[i][j]);
                if (ms.magic[i][j] != 0) {
                    ms.used[ms.magic[i][j]-1] = true;
                }
            }
        }
        
        ms.check_used();
    
        
        //PRINTING THE INPUT AND MAGIC ARRAY
        System.out.println("Size of array from file: "+N);
        ms.display(input);
        System.out.println();
        
        System.out.println("Size of array from MagicSquare object: "+ms.N);
        ms.display(ms.magic);
        
        fileScanner.close();
        
        //IT STARTS THE INITIALIZATION OF DATASTRUCTURES & START THE SEARCH OF SUCCESSORS
        initialize_search(ms,datastructure);
        search(datastructure);
    }
    //THIS PART OF CODE NEEDS TO STAY AS IT IS. CAN'T MAKE CHANGES
    static void initialize_search(MagicSquare ms, int datastructure) {
        switch (datastructure) {
            case 1:
            case 2:
                stuckAL = new ArrayList();
                stuckAL.add(ms);
                break;
            case 3:
                stuckST=new Stack();
                stuckST.push(ms);
                break;
            case 4:
                stuckLL=new LinkedList();
                stuckLL.add(ms);
                break;
            default:
                break;
        }
    }
    //THIS PART OF CODE NEEDS TO STAY AS IT IS. CAN'T MAKE CHANGES
    static void search(int datastructure) {
        MagicSquare current = null, next;
        switch (datastructure) {
            case 1:
                System.out.println("Search using ArrayList as a Stack");
                break;
            case 2:
                System.out.println("Search using ArrayList as a Queue");
                break;
            case 3:
                System.out.println("Search using Stack as a Stack");
                break;
            case 4:
                System.out.println("Search using LinkedList as a Queue");
                break;
            default:
                break;
        }
    
        boolean empty_frontier=false;
        
        while (!empty_frontier) {
            if (datastructure == 1) {
                current = stuckAL.get(stuckAL.size()-1);
                stuckAL.remove(stuckAL.size()-1);
            }
            else if (datastructure == 2) {
                current = stuckAL.get(0);
                stuckAL.remove(0);
            }
            else if (datastructure == 3)
                current = stuckST.pop();
            else if (datastructure == 4)
                current = stuckLL.removeFirst();

            current.initialize_successors();
            
            while((next=current.next_successor()) != null)
            {
                if (next.numbers == N*N)
                {
                    System.out.println("SOLUTION FOUND ");
                    System.out.println("==============");
                    next.display(next.magic);
                    return;
                }
                else switch (datastructure) {
                    case 1: ;
                    case 2: stuckAL.add(next);
                        break;
                    case 3: stuckST.push(next);
                        break;
                    case 4: stuckLL.addLast(next);
                        break;
                }
            }

            switch (datastructure) {
                case 1:
                    if (stuckAL.isEmpty())
                        empty_frontier=true;
                    break;
                case 2:
                    if (stuckAL.isEmpty())
                        empty_frontier=true;
                    break;
                case 3:
                    if (stuckST.isEmpty())
                        empty_frontier=true;
                    break;
                case 4:
                    if (stuckLL.isEmpty())
                        empty_frontier=true;
                    break;
            }
        }
        System.out.println("MAGIC SQUARES CANNOT BE CREATED");
    }
}

class MagicSquare {
    public static int size;
    public int N;
    public int C;
    public int[][] magic;
    public boolean[] used;
    public int numbers;
    public int row;
    public int column;
    public int current_number;
    
    //THIS CONSTRUCTOR WITHOUT ARGUMENTS INITIALIZE N and C, the magic array and the numbers variable with zeros, as well as the used array with false values.
    public MagicSquare() {
        this.N = size;
        C = N*((N*N+1)/2);
       
        magic = new int[N][N];
        used = new boolean[N*N];
       
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                magic[i][j] = 0;
            }
        }
        for (int i = 0; i < used.length; i++) {
            used[i] = false;
        }
       
        numbers = 0;
        row = 0;
        column = 0;
        current_number = 0;
    }
    //THIS CONSTRUCTOR creates a copy of the object (mainly regarding the N, C, magic, numbers and used variables)
    public MagicSquare(MagicSquare ms) {
        N = ms.N;
        C = ms.C;
        
        magic = new int[N][N];
        used = new boolean[N*N];
        
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                magic[i][j] = ms.magic[i][j];
            }
        }
        for (int i = 0; i < used.length; i++) {
            used[i] = ms.used[i];
        }
        
        numbers = ms.numbers;
        row = ms.row;
        column = ms.column;
        current_number = ms.current_number;
    }
    //METHOD THAT IS CALLED TO FILL EACH CELL OF MAGIC ARRAY WITH NUMBER FROM EXTERNAL FILE
    public void set_cell(int row, int col, int number){
       if (number>=1 && number<=N*N && row>=0 && row<N*N && col>=0 && col<N*N && magic[row][col]==0){
           magic[row][col] = number;
           numbers++;
       }
    }
    //METHOD THAT: "initializes" the process of constructing the "successors" of a MagicSquare object. As a successor we characterize a new object, which is in principle the same as its "parent" (with regard to the fields magic, numbers and used), but has an additional position of the magic square filled in in a valid way. The initialize_successors() method will practically give as values to the row and column fields the row and column of the next null of the magic table, while in addition it will initialize the value of the current_number field (eg, to 0).
    public void initialize_successors() {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (magic[i][j] == 0) {
                    row = i;
                    column = j; 
                    current_number = 0;
                    return;
                }
            }
        }
    }
    //METHOD THAT: each time it is called it will find the next value of current_number that can be placed in magic[row,column], construct an object that is a copy of the current object, but with the current_number in magic[row,column], and will return it. If no next value of current_number is found that can be inserted into magic[row, column], it will return null. In order for the current value of current_number to be inserted in the magic[row, column] position, this value must not already be used in the magic square (checked via the used table), and the methods check_row(), check_column() and check_diagonals() to return true.
    public MagicSquare next_successor() {
        MagicSquare successor;
        while (current_number < N*N) {
            current_number++;
            
            if (!used[current_number-1] && check_row() && check_column() && check_diagonals()) {
                successor = new MagicSquare(this);
                successor.magic[row][column] = current_number;
                successor.used[current_number-1] = true;
                successor.numbers++;
                /*if(column == N-1) {
                    successor.row++;
                    successor.column = 0;
                } 
                else {
                    successor.column++;
                }*/
                System.out.println("next successor returns successor!");
                return successor;
            }
            //break;
        }
        System.out.println("next successor returns null!");
        return null;
    }
    //METHOD THAT: returns true if current_number is consistent with the row numbers of magic[row,column], otherwise returns false.
    public boolean check_row(){
        int sum = current_number;
        int m = numbers;
        int emptyPositions = N - m;
        int a = getSumOfSmallestElementsNotUsed();
        int b = getSumOfLargestElementsNotUsed();
        System.out.println();
        System.out.println("current number being tested in row: "+current_number);
        for (int i = 0; i < N; i++) {
            if (magic[row][i] != 0) {
                sum += magic[row][i];
            }
        }
        System.out.println("sum of numbers in row: "+sum);
        if (sum + a > C || sum + b < C) {
            System.out.println("row gives false!");
            return false;
        }
        System.out.println("row gives true!");
        return true;
    }
    //METHOD THAT: returns true if current_number is consistent with the column numbers of magic[row,column], otherwise returns false.
    public boolean check_column(){
        int sum = current_number;
        int m = numbers;
        int emptyPositions = N - m;
        int a = getSumOfSmallestElementsNotUsed();
        int b = getSumOfLargestElementsNotUsed();
        System.out.println("current number being tested in column: "+current_number);
        for (int i = 0; i < N; i++) {
            if (magic[i][column] != 0) {
                sum += magic[i][column];
            }
        }
        System.out.println("sum of numbers in column: "+sum);
        if (sum + a > C || sum + b < C) {
            System.out.println("column gives false!");
            return false;
        }
        System.out.println("column gives true!");
        return true;
    }
    //METHOD THAT: which will return true if current_number is consistent with the numbers of each of the two main diagonals of the magic square, provided that magic[row,column] belongs to one or the other or both of the main diagonals of the magic square respectively, otherwise it will return false.
    public boolean check_diagonals(){
        int sum = current_number;
        int m = numbers;
        int emptyPositions = N - m;
        int a = getSumOfSmallestElementsNotUsed();
        int b = getSumOfLargestElementsNotUsed();
        System.out.println("current number being tested in diagonals: "+current_number);
        if (row == column) { //main diagonal
            for (int i = 0; i < N; i++) {
                if (magic[i][i] != 0) {
                    sum += magic[i][i];
                }
            }
        } else if (row == N-column-1) { //other diagonal
            for (int i = 0; i < N; i++) {
                if (magic[i][N-i-1] != 0) {
                    sum += magic[i][N-i-1];
                }
            }
        }
        System.out.println("sum of numbers in diagonal: "+sum);
        if (sum + a > C || sum + b < C) {
            System.out.println("diagonals gives false!");
            return false;
        }
        System.out.println("diagonals gives true!");
        return true;
    }
    //METHOD THAT: calculate the sum of the 2 first empty elements of used array and therefore the smallest
    public int getSumOfSmallestElementsNotUsed(){
        int sum = 0;
        int count = 0;
        for (int i = 0; i < used.length; i++) {
            if (!used[i]) {
                sum += (i + 1);
                count++;
            }
            if (count == 2) {
                break;
            }
        }
        System.out.println("sum of 2 smallest elements: "+sum);
        return sum;
        
    }
    //METHOD THAT: calculate the sum of the 2 last empty elements of used array and therefore the largest
    public int getSumOfLargestElementsNotUsed(){
        int sum = 0;
        int count = 0;
        for (int i = used.length - 1; i >= 0; i--) {
            if (!used[i]) {
                sum += (i + 1);
                count++;
            }
            if (count == 2) {
                break;
            }
        }
        System.out.println("sum of 2 largest elements: "+sum);
        return sum;
    }

    
    public boolean isComplete() {
        return numbers == N*N;
    }

    public void display(int array[][]) {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }
    
    public void check_used(){
        int i,j;
        int k=0;

        for(i=0; i<magic.length; i++){
            for(j=0; j<magic[i].length; j++){
                System.out.println("POSITION IN USED ARRAY: "+k+" WITH VALUE: "+used[k]+" FROM POSITION IN MAGIC ARRAY: "+i+","+j+" WITH VALUE: "+magic[i][j]);
                k++;
            }
        }
    }
}
athanasia
  • 1
  • 1
  • Is there a reason you marked your input as Javascript? – Sören Jan 29 '23 at 15:45
  • where did i mark it as javascript? i'm sorry it's my first time using stack overflow. do you have any suggestions for the problem? – athanasia Jan 29 '23 at 15:49
  • When you edited your question, you marked your input as Javascript. – Sören Jan 29 '23 at 15:52
  • Why did you write hundreds of lines of code without running a single test? It's time to learn debugging. Either use lots of `println` statements or use an IDE debugger. – Gilbert Le Blanc Jan 29 '23 at 15:54
  • the javascript mark is a mistake .. i didn't even see that when edit the question. now with the debugging part i do tests for about 2 weeks now it always gives me the same result. i added println to see the semi-results of eack method but nothing helps. i don't know where is the mistake. – athanasia Jan 29 '23 at 16:07

1 Answers1

0

What do you think this computes?

this.N = size;
C = N*((N*N+1)/2); // C = 108
  • The size is 6 for your problem.
  • So you will need the values 1 thru 36 inclusive.
  • let max = N*N. So the sum of 1 thru 36 is max*(max+1)/2.
  • divide by N to get the col or row sum and you ((max*(max+1))/2)/N = 111.
  • or (N*(max+1))/2)
  • in your case is should have been (N*(N*N+1))/2.

The issue was that. (N*N+1) is 37. Then you divide by 2 which drops the fraction (int arithemetic). You need to first multiply by N and then divide by 2.

WJS
  • 36,363
  • 4
  • 24
  • 39
  • so let's say size=6, then N will be 6 and C will be 111. what am I suppose to change because I get the same result for C? I understand that the sum of row must be 111 or a smaller number and equal to the col sum but where am I suppose to change it in the code? – athanasia Jan 29 '23 at 16:46
  • I added an explanation at the end. Should have doe it before. But you calculate `C as 108`. – WJS Jan 29 '23 at 16:55
  • so i changed the C in constructor to C = (N*(N*N+1))/2; but it keeps to give the same message "magic squares cannot be created". – athanasia Jan 29 '23 at 17:07
  • Well, there may be other problems. You need to use a debugger and/or put in some print statement at key locations to show what is going on. Ubiquitous print statements are one of the most used tools in debugging programs. Especially after conditionals to see if they are working as expected. Print the value tested in the conditionals and see if the are chosen based on what you want. – WJS Jan 29 '23 at 17:18
  • 1
    thanks for your help! i have added println statements especially in the check row-column and diagonals methods. it seems that when the next_sucesswor method returns the next successor the numbers value doesn't increase by one. – athanasia Jan 29 '23 at 17:28