Skip to content

Commit b5518e9

Browse files
committed
Add CrosswordSolver.java new algorithm
1 parent f34fe4d commit b5518e9

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* A class to solve a crossword puzzle using backtracking.
8+
* Example:
9+
* Input:
10+
* puzzle = {
11+
* {' ', ' ', ' '},
12+
* {' ', ' ', ' '},
13+
* {' ', ' ', ' '}
14+
* }
15+
* words = List.of("cat", "dog")
16+
*
17+
* Output:
18+
* {
19+
* {'c', 'a', 't'},
20+
* {' ', ' ', ' '},
21+
* {'d', 'o', 'g'}
22+
* }
23+
*/
24+
public class CrosswordSolver {
25+
26+
/**
27+
* Checks if a word can be placed at the specified position in the crossword.
28+
*
29+
* @param puzzle The crossword puzzle represented as a 2D char array.
30+
* @param word The word to be placed.
31+
* @param row The row index where the word might be placed.
32+
* @param col The column index where the word might be placed.
33+
* @param vertical If true, the word is placed vertically; otherwise, horizontally.
34+
* @return true if the word can be placed, false otherwise.
35+
*/
36+
public static boolean isValid(char[][] puzzle, String word, int row, int col, boolean vertical) {
37+
for (int i = 0; i < word.length(); i++) {
38+
if (vertical) {
39+
if (row + i >= puzzle.length || puzzle[row + i][col] != ' ') {
40+
return false;
41+
}
42+
} else {
43+
if (col + i >= puzzle[0].length || puzzle[row][col + i] != ' ') {
44+
return false;
45+
}
46+
}
47+
}
48+
return true;
49+
}
50+
51+
/**
52+
* Places a word at the specified position in the crossword.
53+
*
54+
* @param puzzle The crossword puzzle represented as a 2D char array.
55+
* @param word The word to be placed.
56+
* @param row The row index where the word will be placed.
57+
* @param col The column index where the word will be placed.
58+
* @param vertical If true, the word is placed vertically; otherwise, horizontally.
59+
*/
60+
public static void placeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
61+
for (int i = 0; i < word.length(); i++) {
62+
if (vertical) {
63+
puzzle[row + i][col] = word.charAt(i);
64+
} else {
65+
puzzle[row][col + i] = word.charAt(i);
66+
}
67+
}
68+
}
69+
70+
/**
71+
* Removes a word from the specified position in the crossword.
72+
*
73+
* @param puzzle The crossword puzzle represented as a 2D char array.
74+
* @param word The word to be removed.
75+
* @param row The row index where the word is placed.
76+
* @param col The column index where the word is placed.
77+
* @param vertical If true, the word was placed vertically; otherwise, horizontally.
78+
*/
79+
public static void removeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
80+
for (int i = 0; i < word.length(); i++) {
81+
if (vertical) {
82+
puzzle[row + i][col] = ' ';
83+
} else {
84+
puzzle[row][col + i] = ' ';
85+
}
86+
}
87+
}
88+
89+
/**
90+
* Solves the crossword puzzle using backtracking.
91+
*
92+
* @param puzzle The crossword puzzle represented as a 2D char array.
93+
* @param words The list of words to be placed.
94+
* @return true if the crossword is solved, false otherwise.
95+
*/
96+
public static boolean solveCrossword(char[][] puzzle, List<String> words) {
97+
// Create a mutable copy of the words list
98+
List<String> remainingWords = new ArrayList<>(words);
99+
100+
for (int row = 0; row < puzzle.length; row++) {
101+
for (int col = 0; col < puzzle[0].length; col++) {
102+
if (puzzle[row][col] == ' ') {
103+
for (String word : new ArrayList<>(remainingWords)) {
104+
for (boolean vertical : new boolean[]{true, false}) {
105+
if (isValid(puzzle, word, row, col, vertical)) {
106+
placeWord(puzzle, word, row, col, vertical);
107+
remainingWords.remove(word);
108+
if (solveCrossword(puzzle, remainingWords)) {
109+
return true;
110+
}
111+
remainingWords.add(word);
112+
removeWord(puzzle, word, row, col, vertical);
113+
}
114+
}
115+
}
116+
return false;
117+
}
118+
}
119+
}
120+
return true;
121+
}
122+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import java.util.Arrays;
8+
import java.util.List;
9+
import org.junit.jupiter.api.Test;
10+
11+
public class CrosswordSolverTest {
12+
13+
@Test
14+
public void testValidPlacement() {
15+
char[][] puzzle = {
16+
{ ' ', ' ', ' ' },
17+
{ ' ', ' ', ' ' },
18+
{ ' ', ' ', ' ' }
19+
};
20+
assertTrue(CrosswordSolver.isValid(puzzle, "cat", 0, 0, true));
21+
assertTrue(CrosswordSolver.isValid(puzzle, "dog", 0, 0, false));
22+
assertFalse(CrosswordSolver.isValid(puzzle, "cat", 1, 2, false));
23+
}
24+
25+
@Test
26+
public void testPlaceAndRemoveWord() {
27+
char[][] puzzle = {
28+
{ ' ', ' ', ' ' },
29+
{ ' ', ' ', ' ' },
30+
{ ' ', ' ', ' ' }
31+
};
32+
CrosswordSolver.placeWord(puzzle, "cat", 0, 0, true);
33+
assertEquals('c', puzzle[0][0]);
34+
assertEquals('a', puzzle[1][0]);
35+
assertEquals('t', puzzle[2][0]);
36+
37+
CrosswordSolver.removeWord(puzzle, "cat", 0, 0, true);
38+
assertEquals(' ', puzzle[0][0]);
39+
assertEquals(' ', puzzle[1][0]);
40+
assertEquals(' ', puzzle[2][0]);
41+
}
42+
43+
@Test
44+
public void testSolveCrossword() {
45+
char[][] puzzle = {
46+
{ ' ', ' ', ' ' },
47+
{ ' ', ' ', ' ' },
48+
{ ' ', ' ', ' ' }
49+
};
50+
List<String> words = Arrays.asList("cat", "dog", "car");
51+
assertTrue(CrosswordSolver.solveCrossword(puzzle, words));
52+
53+
/* Solved crossword:
54+
* c d c
55+
* a o a
56+
* t g r
57+
*/
58+
59+
assertEquals('c', puzzle[0][0]);
60+
assertEquals('a', puzzle[1][0]);
61+
assertEquals('t', puzzle[2][0]);
62+
63+
assertEquals('d', puzzle[0][1]);
64+
assertEquals('o', puzzle[1][1]);
65+
assertEquals('g', puzzle[2][1]);
66+
67+
assertEquals('c', puzzle[0][2]);
68+
assertEquals('a', puzzle[1][2]);
69+
assertEquals('r', puzzle[2][2]);
70+
}
71+
72+
@Test
73+
public void testNoSolution() {
74+
char[][] puzzle = {
75+
{ ' ', ' ', ' ' },
76+
{ ' ', ' ', ' ' },
77+
{ ' ', ' ', ' ' }
78+
};
79+
List<String> words = Arrays.asList("cat", "dog", "elephant"); // 'elephant' is too long for the grid
80+
assertFalse(CrosswordSolver.solveCrossword(puzzle, words));
81+
}
82+
}

0 commit comments

Comments
 (0)