athanasia
athanasia

Reputation: 1

Magic Square in Java: Why always prints: Magic Squares cannot be created?

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:

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++;
            }
        }
    }
}

Upvotes: -2

Views: 177

Answers (1)

WJS
WJS

Reputation: 40034

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.

Upvotes: 0

Related Questions