Не хочу утверждать сразу, что решение правильное, возможно я и правда что-то упустил, но я провел тесты и ни одной ошибки не было замечено. Единственное исключение - если ищется слово, которое повторяется в кроссворде, однако это очень легко исправить (убрав break), однако так, как в задаче, скорее всего, имеется ввиду, что слово всегда одно, то убирать я его не буду. Результаты тестов сброшу в самом низу. Алгоритм сейчас объясню. Я решил сделать следующий алгоритм: для каждого слова я искал все ячейки, где есть начальная буква (possibleStartPosition), и где есть конечная буква (possibleEndPosition) слова. Далее важная суть решения тут:
if(getDistance(start, end) == word.length() -1 || (getDistance(start, end) > (((word.length() - 1) * Math.sqrt(2)) - 0.00000001) && getDistance(start, end) < (((word.length() - 1) * Math.sqrt(2)) + 0.00000001)))
                        possiblePairs.add(new Pair(start, end, word));
Через формулу нахождения расстояния между точками на плоскости ищется расстояние от начала и до конца слова, и если оно соответствует размеру слова - 1, то это возможная пара, где может находиться слово (0.много_нулей1 - это точность, с помощью которой рассчитывается расстояние диагонали, потому что диагональ равняется а на корень из двух, в общем, там все работает).
if(possiblePairs.size() == 1) {
                list.add(possiblePairs.get(0).createWord());
Если найдено только одно возможное совпадение (то есть, только одна начальная буква и конечная буква слова, расстояние от которых равняется размеру слова - 1), то это и есть это самое слово. Иначе мы проверяем все пары, далее идет проверку на позицию начальной точки и конечной (вертикально, горизонтально, диагонально + учитываются так же стороны (при диагональном 4 возможные позы начальной точки (слева-сверху, слева-снизу, справа-сверху, справа-снизу), при вертикальном 2 (сверху или снизу), при горизонтальном тоже 2 (слева или справа), точка конца же в противоположном направлении). Между начальной и конечной точкой считываются все буквы, включая буквы в самих точках (ибо они тоже части слова), после чего проверяется, равняется ли считанная комбинация слову или перевернутому слову, если да - добавление в список и переход до следующего слова. Тесты:
for(Word w : detectAllWords(crossword, "home", "same", "rrad", "jjeeop", "kovh", "sgr", "mlp", "fulmp", "gsf", "ejj", "poee", "lngr", "meo"))
    System.out.println(w);
Вывод программы:
home - (5, 3) - (2, 0)
same - (1, 1) - (4, 1)
rrad - (4, 3) - (1, 0)
jjeeop - (5, 4) - (0, 4)
kovh - (5, 0) - (5, 3)
sgr - (1, 1) - (3, 3)
mlp - (0, 3) - (2, 3)
fulmp - (0, 0) - (0, 4)
gsf - (2, 2) - (0, 0)
ejj - (3, 4) - (5, 4)
poee - (0, 4) - (3, 4)
lngr - (0, 2) - (3, 2)
meo - (3, 1) - (5, 1)
Для удобной проверки прямо сейчас вставлю сюда нужный массив (и важно учесть, что первое значение - x, а второе - y, счет начинается с левого-верхнего угла (y = 0, x = 0), вниз - y увеличивается, вправо - х увеличивается, и каждое значение меньше на 1, так как индексация массивов начинается с 0, собственно, вывод точно такой, какой нужен в задании):
{'f', 'd', 'e', 'r', 'l', 'k'},
{'u', 's', 'a', 'm', 'e', 'o'},
{'l', 'n', 'g', 'r', 'o', 'v'},
{'m', 'l', 'p', 'r', 'r', 'h'},
{'p', 'o', 'e', 'e', 'j', 'j'}
Как можно убедиться, отрабатывает отлично, единственное что - не ищет повторы, слово может быть только 1, это можно исправить, однако это было бы глупо не указать это в условии задачи, если бы это нужно было. В общем, нужна помощь справиться с боссом валидатором или ответ кого-то из Javarush, почему данный код может не работать. P.S. Подсказка ментора:
Размер списка возвращаемого методом detectAllWords отличается от правильного!
Однако это полный бред, ведь на каждое слово возможно только 1 добавление в список. Больше быть не может, меньше - если слово не найдено. Но по условию задачи, слово всегда должно находиться. UPD (20.01.2018): сделал небольшой фикс строчек 72-76, 82-86 и 112, однако данный фикс только исправил небольшой баг, который связан с повторами. Теперь программа способна работать корректно и с повторами (закомментировать break), и с одним словом (разкомментировать break), однако решение все еще не принимается. Не нашел еще ни одного слова, которое бы ломало программу, все слова спокойно ищутся, выходов за массивы нигде нет, неправильные варианты корректно отсеиваются в блоках if-else, все тесты успешны (включая со словами из 1 буквы). Так же удалена строчка 95, потому что она была для одного теста и я забыл её убрать. Еще есть одна строчка для тестирования всех входных пар, которые доходят до блоков.
System.out.println(String.format("ENTERED: %s - (%d, %d) - (%d, %d)", p.getContent(), p.getStart().getX(), p.getStart().getY(), p.getEnd().getX(), p.getEnd().getY()));
72-76
} else {
for (int i = p.getStart().getY(); i >= p.getEnd().getY(); i--) {
            content.append((char) crossword[i][p.getStart().getX()]);
       }
}
82-86
} else {
for (int i = p.getStart().getX(); i >= p.getEnd().getX(); i--) {
           content.append((char) crossword[p.getStart().getY()][i]);
      }
}
112
if (content.toString().equals(p.content)) {
И добавлю еще одни результаты тестов сюда. Ввод
for (Word w : detectAllWords(crossword, "home", "same", "poe", "lngh", "fder", "poee", "meh", "e", "o", "emas", "usa", "lk", "k", "ovhj", "jer", "jeo", "ud", "mlu", "vok", "jhvok"))
            System.out.println(w);
Вывод
ENTERED: home - (1, 3) - (4, 3)
ENTERED: meh - (3, 1) - (1, 3)
ENTERED: meh - (3, 1) - (5, 3)
ENTERED: meh - (3, 3) - (1, 3)
ENTERED: meh - (3, 3) - (5, 3)
ENTERED: e - (2, 0) - (2, 0)
ENTERED: o - (5, 1) - (5, 1)
ENTERED: ovhj - (5, 1) - (5, 4)
home - (1, 3) - (4, 3)
same - (1, 1) - (4, 1)
poe - (0, 4) - (2, 4)
lngh - (4, 0) - (1, 3)
fder - (0, 0) - (3, 0)
poee - (0, 4) - (3, 4)
meh - (3, 3) - (5, 3)
e - (2, 0) - (2, 0)
o - (5, 1) - (5, 1)
emas - (4, 1) - (1, 1)
usa - (0, 1) - (2, 1)
lk - (4, 0) - (5, 0)
k - (5, 0) - (5, 0)
ovhj - (5, 1) - (5, 4)
jer - (5, 4) - (3, 2)
jeo - (4, 4) - (4, 2)
ud - (0, 1) - (1, 0)
mlu - (0, 3) - (0, 1)
vok - (5, 2) - (5, 0)
jhvok - (5, 4) - (5, 0)
Где Entered - это все возможные комбинации, в ходе отсеивания все комбинации meh отсеялись, кроме настоящей (ибо где-то был moh, где-то еще что-то такое, и в ходе проверок осталась только 1). ПОСЛЕДНИЙ КОД
package com.javarush.task.task20.task2027;

import java.util.ArrayList;
import java.util.List;

/*
Кроссворд
*/
public class Solution {
    public static void main(String[] args) {
        int[][] crossword = new int[][]{
                {'f', 'd', 'e', 'r', 'l', 'k'},
                {'u', 's', 'a', 'm', 'e', 'o'},
                {'l', 'u', 'g', 'r', 'o', 'v'},
                {'m', 'l', 'p', 'r', 'r', 'h'},
                {'p', 'o', 'e', 'p', 'j', 'j'},
                {'t', 'r', 'w', 'e', 'k', 'a'},
                {'m', 'c', 'n', 'q', 's', 'o'},
                {'z', 'o', 'e', 'f', 'h', 's'}
        };

        for(Word w : detectAllWords(crossword, "lleess", "sseell"))
            System.out.println(w);
        /*
Ожидаемый результат
home - (5, 3) - (2, 0)
same - (1, 1) - (4, 1)
         */
    }

    public static List<Word> detectAllWords(int[][] crossword, String... words) {
        List<Word> list = new ArrayList<>();

        int crosswordWidth = crossword[0].length;


        for (String word : words) {
            char[] symbols = word.toCharArray();
            List<Position> possibleStartPositions = new ArrayList<>();
            List<Position> possibleEndPositions = new ArrayList<>();
            List<Pair> possiblePairs = new ArrayList<>();

            for (int i = 0; i < crossword.length; i++) {
                for (int k = 0; k < crosswordWidth; k++) {
                    if (crossword[i][k] == symbols[0])
                        possibleStartPositions.add(new Position(k, i));
                    if (crossword[i][k] == symbols[symbols.length - 1])
                        possibleEndPositions.add(new Position(k, i));
                }
            }

            for (Position start : possibleStartPositions) {
                for (Position end : possibleEndPositions) {
                    if (getDistance(start, end) == word.length() - 1 || (getDistance(start, end) > (((word.length() - 1) * Math.sqrt(2)) - 0.000000000000001) && getDistance(start, end) < (((word.length() - 1) * Math.sqrt(2)) + 0.000000000000001))) {
                        possiblePairs.add(new Pair(start, end, word));
                    }
                }
            }

            if (possiblePairs.size() == 1) {
                list.add(possiblePairs.get(0).createWord());
            } else {
                for (Pair p : possiblePairs) {
                    StringBuilder content = new StringBuilder();
                    //System.out.println(String.format("ENTERED: %s - (%d, %d) - (%d, %d)", p.getContent(), p.getStart().getX(), p.getStart().getY(), p.getEnd().getX(), p.getEnd().getY()));
                    try {
                        if (p.getStart().getX() == p.getEnd().getX()) {
                            if (p.getStart().getY() < p.getEnd().getY()) {
                                for (int i = p.getStart().getY(); i <= p.getEnd().getY(); i++) {
                                    content.append((char) crossword[i][p.getStart().getX()]);
                                }
                            } else {
                                for (int i = p.getStart().getY(); i >= p.getEnd().getY(); i--) {
                                    content.append((char) crossword[i][p.getStart().getX()]);
                                }
                            }
                        } else if (p.getStart().getY() == p.getEnd().getY()) {
                            if (p.getStart().getX() < p.getEnd().getX()) {
                                for (int i = p.getStart().getX(); i <= p.getEnd().getX(); i++) {
                                    content.append((char) crossword[p.getStart().getY()][i]);
                                }
                            } else {
                                for (int i = p.getStart().getX(); i >= p.getEnd().getX(); i--) {
                                    content.append((char) crossword[p.getStart().getY()][i]);
                                }
                            }
                        } else {
                            if (p.getStart().getX() < p.getEnd().getX()) {
                                if (p.getStart().getY() < p.getEnd().getY()) {
                                    if((p.getEnd().getX() - p.getStart().getX() != p.getContent().length()-1) || (p.getEnd().getY() - p.getStart().getY() != p.getContent().length()-1))
                                        continue;
                                    for (int i = 0, x = p.getStart().getX(), y = p.getStart().getY(); i < p.getContent().length(); i++, x++, y++) {
                                        content.append((char) crossword[y][x]);
                                    }
                                } else {
                                    if((p.getEnd().getX() - p.getStart().getX() != p.getContent().length()-1) || (p.getStart().getY() - p.getEnd().getY() != p.getContent().length()-1))
                                        continue;
                                    for (int i = 0, x = p.getStart().getX(), y = p.getStart().getY(); i < p.getContent().length(); i++, x++, y--) {
                                        content.append((char) crossword[y][x]);
                                    }
                                }
                            } else {
                                if (p.getStart().getY() < p.getEnd().getY()) {
                                    if((p.getStart().getX() - p.getEnd().getX() != p.getContent().length()-1) || (p.getEnd().getY() - p.getStart().getY() != p.getContent().length()-1))
                                        continue;
                                    for (int i = 0, x = p.getStart().getX(), y = p.getStart().getY(); i < p.getContent().length(); i++, x--, y++) {
                                        content.append((char) crossword[y][x]);
                                    }
                                } else {
                                    if((p.getStart().getX() - p.getEnd().getX() != p.getContent().length()-1) || (p.getStart().getY() - p.getEnd().getY() != p.getContent().length()-1))
                                        continue;
                                    for (int i = 0, x = p.getStart().getX(), y = p.getStart().getY(); i < p.getContent().length(); i++, x--, y--) {
                                        content.append((char) crossword[y][x]);
                                    }
                                }
                            }
                        }

                        if (content.toString().equals(p.content)) {
                            list.add(p.createWord());
                            break; // закомментировать, если нужны повторы
                        }
                    } catch (ArrayIndexOutOfBoundsException e) {

                    }
                }
            }
        }

        return list;
    }

    private static double getDistance(Position one, Position two) {
        return Math.sqrt(Math.pow((one.getX() - two.getX()), 2) + Math.pow((one.getY() - two.getY()), 2));
    }

    public static class Word {
        private String text;
        private int startX;
        private int startY;
        private int endX;
        private int endY;

        public Word(String text) {
            this.text = text;
        }

        public void setStartPoint(int i, int j) {
            startX = i;
            startY = j;
        }

        public void setEndPoint(int i, int j) {
            endX = i;
            endY = j;
        }

        @Override
        public String toString() {
            return String.format("%s - (%d, %d) - (%d, %d)", text, startX, startY, endX, endY);
        }
    }

    public static class Position {
        private int x, y;

        public Position(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }

    public static class Pair {
        private Position start, end;
        private String content;

        public Pair(Position start, Position end, String content) {
            this.start = start;
            this.end = end;
            this.content = content;
        }

        public Position getStart() {
            return start;
        }

        public Position getEnd() {
            return end;
        }

        public String getContent() {
            return content;
        }

        public Word createWord() {
            Word result = new Word(this.getContent());
            result.setStartPoint(this.getStart().getX(), this.getStart().getY());
            result.setEndPoint(this.getEnd().getX(), this.getEnd().getY());
            return result;
        }
    }
}