001    package aima.search.nqueens;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import aima.basic.XYLocation;
007    
008    public class NQueensBoard {
009    
010            /**
011             * X---> increases left to right with zero based index Y increases top to
012             * bottom with zero based index | | V
013             */
014            int[][] board;
015    
016            int size;
017    
018            public NQueensBoard(int n) {
019    
020                    size = n;
021                    board = new int[size][size];
022                    for (int i = 0; i < size; i++) {
023                            for (int j = 0; j < size; j++) {
024                                    board[i][j] = 0;
025                            }
026                    }
027            }
028    
029            public void addQueenAt(XYLocation l) {
030    
031                    if (!(queenExistsAt(l)))
032                            board[l.getXCoOrdinate()][l.getYCoOrdinate()] = 1;
033            }
034    
035            public void removeQueenFrom(XYLocation l) {
036    
037                    if (board[l.getXCoOrdinate()][l.getYCoOrdinate()] == 1) {
038                            board[l.getXCoOrdinate()][l.getYCoOrdinate()] = 0;
039                    }
040            }
041    
042            private boolean queenExistsAt(int x, int y) {
043    
044                    return (board[x][y] == 1);
045            }
046    
047            public boolean queenExistsAt(XYLocation l) {
048    
049                    return (queenExistsAt(l.getXCoOrdinate(), l.getYCoOrdinate()));
050            }
051    
052            public void moveQueen(XYLocation from, XYLocation to) {
053    
054                    if ((queenExistsAt(from)) && (!(queenExistsAt(to)))) {
055                            removeQueenFrom(from);
056                            addQueenAt(to);
057                    }
058            }
059    
060            public void clear() {
061    
062                    for (int i = 0; i < size; i++) {
063                            for (int j = 0; j < size; j++) {
064                                    board[i][j] = 0;
065                            }
066                    }
067            }
068    
069            public void setBoard(List<XYLocation> al) {
070    
071                    clear();
072    
073                    for (int i = 0; i < al.size(); i++) {
074                            addQueenAt(al.get(i));
075                    }
076            }
077    
078            public int getNumberOfQueensOnBoard() {
079    
080                    int count = 0;
081                    for (int i = 0; i < size; i++) {
082                            for (int j = 0; j < size; j++) {
083                                    if (board[i][j] == 1) {
084                                            count++;
085                                    }
086                            }
087                    }
088                    return count;
089            }
090    
091            public List<XYLocation> getQueenPositions() {
092    
093                    ArrayList<XYLocation> result = new ArrayList<XYLocation>();
094                    for (int i = 0; i < size; i++) {
095                            for (int j = 0; j < size; j++) {
096                                    if (queenExistsAt(i, j)) {
097                                            result.add(new XYLocation(i, j));
098                                    }
099                            }
100                    }
101                    return result;
102    
103            }
104    
105            private boolean isSquareHorizontallyAttacked(int x, int y) {
106    
107                    return numberOfHorizontalAttacksOn(x, y) > 0;
108            }
109    
110            private boolean isSquareVerticallyAttacked(int x, int y) {
111                    return numberOfVerticalAttacksOn(x, y) > 0;
112            }
113    
114            private boolean isSquareDiagonallyAttacked(int x, int y) {
115                    return numberOfDiagonalAttacksOn(x, y) > 0;
116            }
117    
118            public boolean isSquareUnderAttack(XYLocation l) {
119    
120                    int x = l.getXCoOrdinate();
121                    int y = l.getYCoOrdinate();
122                    return (isSquareHorizontallyAttacked(x, y)
123                                    || isSquareVerticallyAttacked(x, y) || isSquareDiagonallyAttacked(
124                                    x, y));
125            }
126    
127            public int getSize() {
128    
129                    return size;
130            }
131    
132            public void print() {
133    
134                    System.out.println(getBoardPic());
135    
136            }
137    
138            public String getBoardPic() {
139    
140                    StringBuffer buffer = new StringBuffer();
141                    for (int row = 0; (row < size); row++) { // row
142                            for (int col = 0; (col < size); col++) { // col
143                                    if (queenExistsAt(col, row)) {
144                                            buffer.append(" Q ");
145                                    } else {
146                                            buffer.append(" - ");
147                                    }
148                            }
149                            buffer.append("\n");
150                    }
151                    return buffer.toString();
152            }
153    
154            public int getNumberOfAttacksOn(XYLocation l) {
155    
156                    int x = l.getXCoOrdinate();
157                    int y = l.getYCoOrdinate();
158                    return numberOfHorizontalAttacksOn(x, y)
159                                    + numberOfVerticalAttacksOn(x, y)
160                                    + numberOfDiagonalAttacksOn(x, y);
161            }
162    
163            private int numberOfHorizontalAttacksOn(int x, int y) {
164    
165                    int retVal = 0;
166                    for (int i = 0; i < size; i++) {
167                            if ((queenExistsAt(i, y))) {
168                                    if (i != x)
169                                            retVal++;
170                            }
171                    }
172                    return retVal;
173            }
174    
175            private int numberOfVerticalAttacksOn(int x, int y) {
176    
177                    int retVal = 0;
178                    for (int j = 0; j < size; j++) {
179                            if ((queenExistsAt(x, j))) {
180                                    if (j != y)
181                                            retVal++;
182                            }
183                    }
184                    return retVal;
185            }
186    
187            private int numberOfDiagonalAttacksOn(int x, int y) {
188    
189                    int retVal = 0;
190    
191                    int i;
192                    int j;
193                    // forward up diagonal
194                    for (i = (x + 1), j = (y - 1); (i < size && (j > -1)); i++, j--) {
195                            if (queenExistsAt(i, j)) {
196                                    retVal++;
197                            }
198                    }
199                    // forward down diagonal
200                    for (i = (x + 1), j = (y + 1); ((i < size) && (j < size)); i++, j++) {
201                            if (queenExistsAt(i, j)) {
202                                    retVal++;
203                            }
204                    }
205                    // backward up diagonal
206                    for (i = (x - 1), j = (y - 1); ((i > -1) && (j > -1)); i--, j--) {
207                            if (queenExistsAt(i, j)) {
208                                    retVal++;
209                            }
210                    }
211    
212                    // backward down diagonal
213                    for (i = (x - 1), j = (y + 1); ((i > -1) && (j < size)); i--, j++) {
214                            if (queenExistsAt(i, j)) {
215                                    retVal++;
216                            }
217                    }
218    
219                    return retVal;
220            }
221    
222            @Override
223            public int hashCode() {
224                    List<XYLocation> locs = getQueenPositions();
225    
226                    int result = 17;
227                    for (XYLocation loc : locs) {
228                            result = 37 * loc.hashCode();
229                    }
230                    return result;
231            }
232    
233            @Override
234            public boolean equals(Object o) {
235    
236                    if (this == o) {
237                            return true;
238                    }
239                    if ((o == null) || (this.getClass() != o.getClass())) {
240                            return false;
241                    }
242                    NQueensBoard aBoard = (NQueensBoard) o;
243                    boolean retVal = true;
244                    List<XYLocation> locs = getQueenPositions();
245    
246                    for (XYLocation loc : locs) {
247                            if (!(aBoard.queenExistsAt(loc))) {
248                                    retVal = false;
249                            }
250                    }
251                    return retVal;
252            }
253    
254            @Override
255            public String toString() {
256                    StringBuffer buf = new StringBuffer();
257                    for (int row = 0; row < size; row++) { // rows
258                            for (int col = 0; col < size; col++) { // columns
259                                    if (queenExistsAt(col, row)) {
260                                            buf.append('Q');
261                                    } else {
262                                            buf.append('-');
263                                    }
264                            }
265                            buf.append("\n");
266                    }
267                    return buf.toString();
268            }
269    
270    }