In this HackerRank Crossword Puzzle Interview preparation kit problem you need to Complete the crosswordPuzzle function. It should return an array of strings, each representing a row of the finished puzzle.


HackerRank Crossword Puzzle Interview preparation kit solution


Problem solution in Python programming.

from copy import deepcopy


def fill_board(board, words):
    if len(words) == 0:
        for a in board:
            for b in a:
                print(b, end="")
            print("")
    first_open_space = open_space_finder(board)
    result = word_placer(first_open_space, board, words)
    if not result:
        return False

def open_space_finder(board):
    for a in range(len(board)):
        for b in range(len(board[a])):
            if board[a][b] == '-':
                return word_finder([a, b], board)


def word_finder(open_space, board):
    word_place =[]
    x = open_space[0]
    y = open_space[1]
    if x in range(1, len(board)-1):
        if look_up(x,y,board):
            word_place.append([x-1, y])
            word_place.append(open_space)
            return fill_down(word_place, board)
        if look_down(x,y,board):
            word_place.append(open_space)
            word_place.append([x+1, y])
            return fill_down(word_place, board)
    elif x == 0:
        if look_down(x,y,board):
            word_place.append(open_space)
            word_place.append([x+1, y])
            return fill_down(word_place, board)

    if y in range(1, len(board[y])-1):
        if look_left(x,y,board):
            word_place.append([x, y-1])
            word_place.append(open_space)
            return fill_across(word_place, board)
        if look_right(x,y, board):
            word_place.append(open_space)
            word_place.append([x, y+1])
            return fill_across(word_place, board)
    elif y == 0:
        if look_right(x,y, board):
            word_place.append(open_space)
            word_place.append([x, y+1])
            return fill_across(word_place, board)


def look_up(x, y, board):
    return board[x-1][y]!='+'


def look_down(x, y, board):
    return board[x+1][y]!='+'


def look_left(x, y, board):
    return board[x][y-1]!='+'


def look_right(x, y, board):
    return board[x][y+1] != '+'


def fill_down(place_list, board):
    where_to_start = place_list[len(place_list)-1]
    x =where_to_start[0]+1
    y= where_to_start[1]
    while x<len(board):
        if board[x][y]!='+':
            place_list.append([x,y])
            x += 1
        else:
            x=len(board)
    return place_list


def fill_across(place_list, board):
    where_to_start = place_list[len(place_list)-1]
    x = where_to_start[0]
    y = where_to_start[1]+1
    while y<len(board[x]):
        if board[x][y] != '+':
            place_list.append([x,y])
            y += 1
        else:
            y = len(board[x])
    return place_list


def word_placer(place_list, board, words):
    words_that_fit = [X for X in words if len(X) == len(place_list)]

    for a in words_that_fit:
        board1 = deepcopy(board)
        words1 = deepcopy(words)
        for index in range(len(a)):
            x = place_list[index][0]
            y = place_list[index][1]
            if board[x][y] == '-':
                board1[x][y] = a[index]
            else:
                if board[x][y] != a[index]:
                    break
            if index == len(a)-1:
                words1.remove(a)
                buzz = fill_board(board1, words1)
                break
    return False
first_board = []
for x in range(10):
    string = input()
    string_list =list(string)
    first_board.insert(x, string_list)
words = input().split(';')
fill_board(first_board, words)


Problem solution in Java Programming.

import java.util.*;

public class CrosswordPuzzle {

    private static final StringBuilder output = new StringBuilder();

    private static boolean solve(char[][] board, List<String> words) {
        Location start = null;
        StringBuilder prefixBuilder = new StringBuilder();
        Direction direction = null;
        int expectedSize = 0;
        int col = -1;
        int row = -1;
        for (int i = 0; i < board.length && row < 0; i++) {
            for (int j = 0; j < board[i].length && col < 0; j++) {
                if (board[i][j] == '-') {
                    row = i;
                    col = j;
                }
            }
        }

        if (col + 1 < board[row].length && board[row][col + 1] == '-') {
            direction = Direction.RIGHT;
            int start1 = col;
            for (int j = col - 1; j >= 0 && board[row][j] != '+'; j--) {
                prefixBuilder.append(board[row][j]);
                expectedSize++;
                start1 = j;
            }
            prefixBuilder.reverse();
            for (int j = col; j < board[row].length && board[row][j] != '+'; j++) {
                expectedSize++;
            }
            start = new Location(row, start1);
        } else {
            direction = Direction.DOWN;
            int start1 = row;
            for (int i1 = row; i1 < board.length && board[i1][col] == '-'; i1++) {
                expectedSize++;
            }
            for (int i1 = row - 1; i1 >= 0 && board[i1][col] != '+'; i1--) {
                prefixBuilder.append(board[i1][col]);
                expectedSize++;
                start1 = i1;
            }
            prefixBuilder.reverse();
            start = new Location(start1, col);
        }

        String prefix = prefixBuilder.toString();
        List<String> matching = new ArrayList<>();
        for (String word : words) {
            if (word.length() == expectedSize && (prefix.isEmpty() || word.startsWith(prefix))) {
                matching.add(word);
            }
        }
        if (matching.isEmpty()) {
            return false;
        }

        for (String matched : matching) {
            words.remove(matched);

            if (direction == Direction.RIGHT) {
                for (int i = 0; i < matched.length(); i++) {
                    board[start.row][start.col + i] = matched.charAt(i);
                }
            } else {
                for (int i = 0; i < matched.length(); i++) {
                    board[start.row + i][start.col] = matched.charAt(i);
                }
            }

            char[][] clone = clone(board);
            boolean result = true;
            if (!words.isEmpty()) {
                result = solve(clone, words);
            }
            if (!result) {
                words.add(matched);
            } else {
                print(clone);
                return true;
            }
        }
        return words.isEmpty();
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        char[][] board = new char[10][];
        for (int i = 0; i < 10 && scanner.hasNextLine(); i++) {
            String str = scanner.nextLine();
            board[i] = str.toCharArray();
        }

        String[] words = scanner.nextLine().split(";");
        List<String> list = new ArrayList<>(words.length);
        Collections.addAll(list, words);
        solve(board, list);
        System.out.println(output);
    }

    private static void print(char[][] board) {
        if (output.length() > 0) {
            return;
        }

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                output.append(board[i][j]);
            }
            output.append(System.lineSeparator());
        }
    }

    private static char[][] clone(char[][] board) {
        char[][] result = new char[board.length][];
        System.arraycopy(board, 0, result, 0, board.length);
        return result;
    }

    private static class Location {
        private final int row;
        private final int col;

        public Location(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }

    private enum Direction {
        LEFT, RIGHT, UP, DOWN
    }
}


Problem solution in C++ programming.

#include <cassert>
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

struct Gap
{
  Gap(int x, int y, int l, bool acr) : row(x), col(y), len(l), across(acr) {}
  
  int row;
  int col;
  int len;
  bool across;
};

bool operator==(const Gap& lhs, const Gap& rhs)
{
  return ((lhs.row == rhs.row) &&
          (lhs.col == rhs.col) && 
          (lhs.len == rhs.len) && 
          (lhs.across == rhs.across));
}

ostream& operator<<(ostream& os, const Gap& g)
{
  return os << "{" << g.row << ", " << g.col << ", " << g.len << ", " << g.across << "}";
}

pair<vector<vector<char>>, bool> solve(vector<vector<char>> M, vector<Gap> g, vector<string> w)
{
  if (w.empty())
    return make_pair(M, true);
  
  // Over all gaps
  for (int i = 0; i < g.size(); ++i)
  {
    // Try every remaining word
    for (int j = 0; j < w.size(); ++j)
    {
      Gap gg = g[i];
      if (gg.len != w[j].size())
        continue;
      
      // Make a copy of M
      vector<vector<char>> MM = M;
      
      // Every character of the gap
      if (gg.across)
      {
        bool success = true;
        for (int k = 0; k < gg.len; ++k)
        {
          if (MM[gg.row][gg.col + k] == '-')
            MM[gg.row][gg.col + k] = w[j][k];
          
          else if (MM[gg.row][gg.col + k] != w[j][k])
            success = false;
        }
        
        if (success)
        {
          vector<Gap> gg = g;
          gg.erase(gg.begin() + i);
          vector<string> ww = w;
          ww.erase(ww.begin() + j);
          pair<vector<vector<char>>, bool> x = solve(MM, gg, ww);
          if (x.second == true)
            return x;
        }
      }
      else
      {
        bool success = true;
        for (int k = 0; k < gg.len; ++k)
        {
          if (MM[gg.row + k][gg.col] == '-')
            MM[gg.row + k][gg.col] = w[j][k];
          
          else if (MM[gg.row + k][gg.col] != w[j][k])
            success = false;
        }
        
        if (success)
        {
          vector<Gap> gg = g;
          gg.erase(gg.begin() + i);
          vector<string> ww = w;
          ww.erase(ww.begin() + j);
          pair<vector<vector<char>>, bool> x = solve(MM, gg, ww);
          if (x.second == true)
            return x;
        }
      }
      
    }
  }
  
  return make_pair(M, false);
}

vector<Gap> find_gaps(const vector<vector<char>>& M)
{
  vector<Gap> gaps;
  
  // row wise iteration
  for (int row = 0; row < M.size(); ++row)
  {
    int start = -1;
    int stop = -1;
    if (M[row][0] == '-')
    {
      start = 0; stop = 0;
    }
    
    int col = 1;
    for (col = 1; col < M[row].size(); ++col)
    {
      if ((M[row][col] != M[row][col - 1]) && (start == -1))
      {
        start = col;
      }
      else if (M[row][col] != M[row][col - 1])
      {
        stop = col - 1;
        if (stop > start)
        {
          gaps.push_back(Gap(row, start, stop - start + 1, true));
        }
        
        start = -1;
        stop = -1;
      }
    }
    
    stop = col - 1;
    if ((M[row][stop] == '-') && (stop > start))
    {
      gaps.push_back(Gap(row, start, stop - start + 1, true));
    }
  }
  
  // column wise iteration
  for (int col = 0; col < M[0].size(); ++col)
  {
    int start = -1;
    int stop = -1;
    if (M[0][col] == '-')
    {
      start = 0; stop = 0;
    } 
    
    int row = 1;
    for (row = 1; row < M.size(); ++row)
    {
      if ((M[row][col] != M[row - 1][col]) && (start == -1))
      {
        start = row;
      }
      else if (M[row][col] != M[row - 1][col])
      {
        stop = row - 1;
        if (stop > start)
        {
          gaps.push_back(Gap(start, col, stop - start + 1, false));
        }
        
        start = -1;
        stop = -1;
      }
    }
    
    stop = row - 1;
    if ((start > -1) && (M[stop][col] == '-') && (stop > start))
    {
      gaps.push_back(Gap(start, col, stop - start + 1, false));
    }
    
  }
  
  return gaps;
}

vector<string> vectorize(const string& words)
{
  int start = 0; 
  int stop = 0;
  vector<string> out;
  
  for (int stop = 0; stop < words.size(); ++stop)
  {
    if (words[stop] == ';')
    {
      out.push_back(words.substr(start, stop - start));
      start = stop + 1;
      stop = stop + 2;
    }
  }
  
  // Push the last word
  out.push_back(words.substr(start, stop - start));
  
  return out;
}

int main() 
{
  {
    // Test vectorize words
    string x = "LONDON;DELHI;ICELAND;ANKARA";
    vector<string> w = vectorize(x);
    assert(w.size() == 4);
    assert(w[0] == "LONDON");
    assert(w[1] == "DELHI");
    assert(w[2] == "ICELAND");
    assert(w[3] == "ANKARA");
  }
  
  {
    // Test find_gaps
    vector<vector<char>> M = 
      { //0    1    2    3    4    5
        {'+', '-', '+', '-', '-', '+'}, // 0,3,2,true; 0,1,3,false; 0,3,3,false
        {'-', '-', '-', '-', '+', '+'}, // 1,0,4,true
        {'+', '-', '+', '-', '+', '+'}, // 
        {'+', '+', '+', '+', '+', '+'}, //
        {'+', '-', '+', '-', '-', '-'}, // 4,3,3,true; 4,1,2,false
        {'+', '-', '+', '+', '+', '+'}
      };
    
    vector<Gap> gaps = find_gaps(M);
    assert(gaps.size() == 6);
    assert(gaps[0] == Gap(0, 3, 2, true));
    assert(gaps[1] == Gap(1, 0, 4, true));
    assert(gaps[2] == Gap(4, 3, 3, true));
    assert(gaps[3] == Gap(0, 1, 3, false));
    assert(gaps[4] == Gap(4, 1, 2, false));
    assert(gaps[5] == Gap(0, 3, 3, false));
  }
  
  vector<vector<char>> M(10, vector<char>(10, ' '));
  for (int i = 0; i < 10; ++i)
    for (int j = 0; j < 10; ++j)
      cin >> M[i][j];  
  
  vector<Gap> gaps = find_gaps(M);

  string words;
  cin >> words;
  vector<string> w = vectorize(words);

  pair<vector<vector<char>>, bool> x = solve(M, gaps, w);
  if (x.second == true)
  {
    vector<vector<char>>& m = x.first;
    for (auto v : m)
    {
      for (auto c : v)
        cout << c;
      cout << endl;
    }
  }
}


Problem solution in C programming.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int fill_puzzle(char *puzzle, char words[10][10], int W, int *lengths){
	char start,oldentry[10],*c;
	int scpos = 0;
	while(*(puzzle+scpos)!='-'&& scpos<100) scpos++;
	if(scpos==100)return 1;
	int length = 0;
	int across = 0;
	int delta = 10;
	if(*(puzzle+scpos+1)=='-') {
		across=1; //across clue
		delta = 1;
	}
	while(*(puzzle+scpos+delta*length)!='+' && ((!across && (scpos+delta*length<100)) || (across && (length<10*((scpos/10)+1)-scpos)))) length++;
	start = 0;
 	if((across && scpos%10>0) || (!across && scpos>10)){
		if(*(puzzle+scpos-across-(1-across)*10)!='+') { // joined to another word
			start = *(puzzle+scpos-across-(1-across)*10);
			length++;
			scpos -= across+(1-across)*10;
		}
	}
	for(int iw=0;iw<W;iw++){
		int startok = 1;
		if(start && start!=words[iw][0]) startok = 0;
		if(lengths[iw]==length && startok) {
			int temp = lengths[iw];
			lengths[iw] = 0;
			int fitok = 1;
			for(int wc=0;wc<length;wc++) {
				c = puzzle+scpos+10*wc;
				if(across) c = puzzle+scpos+wc;
				oldentry[wc] = *c;
				if(*c=='-'){
					*c = words[iw][wc];
				} else {
					if(*c!=words[iw][wc])fitok=0;
				}
			}
			if(fitok) fitok = fill_puzzle(puzzle,words,W,lengths);
			if(fitok) return 1;
			lengths[iw] = temp;
			for(int wc=0;wc<length;wc++) {
				c = puzzle+scpos+across*wc+(1-across)*10*wc;
				*c = oldentry[wc];
			}
		}
	}
	return 0;
}

int main() {
	char puzzle[100], words[10][10], line[101], eol;
	int *lengths = calloc(10,sizeof(int));
	for(int i=0;i<10;i++) {
		scanf("%s",line);
		for(int j=0;j<10;j++) *(puzzle+10*i+j) = line[j];
	}
	char c = 0;
	int wpos = 0;
	int nwords = 0;
	scanf("%s",line);
	for(int i=0;i<strlen(line);i++) {
		if(line[i]==';') {
			nwords++;
			wpos = 0;
		} else {
			words[nwords][wpos] = line[i];
			wpos++;
			lengths[nwords]++;
		}
	}
	nwords++;
	int fitok = fill_puzzle(puzzle,words,nwords,lengths);
	for(int i=0;i<10;i++) {
		for(int j=0;j<10;j++)printf("%c",*(puzzle+10*i+j));
		printf("\n");
	}
	return 0;
}


Problem solution in JavaScript programming.

const _ = require('lodash');
const H = Symbol('horizontal');
const V = Symbol('vertical');

// group words by length and sorted by # of occurrences of words of each length
// idea is that lengths with fewer words should be placed first
function groupWords(words) {
  return _.flatten(_.values(_.groupBy(words, 'length')).sort((a, b) => a.length - b.length));
}

// returns coords of first blank of specified length
function findBlank(grid, word) {
  const desiredLen = word.length;
  
  for (i = 0; i < 10; i += 1) {
    for (j = 0; j < 10; j += 1) {

      if (grid[i][j] === '-' || grid[i][j] === word[0]) {

        if (i < 9 && (i === 0 || grid[i - 1][j] === '+') && (grid[i + 1][j] === '-' || grid[i + 1][j] === word[1])) {
          let len = 0;

          while (i + len < 10 && (grid[i + len][j] !== '+')) {
            len += 1;
          }

          if (len === desiredLen) {
            return { dir: V, i, j }
          }
        }

        if (j < 9 && (j === 0 || grid[i][j - 1] === '+') && (grid[i][j + 1] === '-' || grid[i][j + 1] === word[1])) {
          let len = 0;

          while (j + len < 10 && (grid[i][j + len] !== '+')) {
            len += 1;
          }
          
          if (len === desiredLen) {
            return { dir: H, i, j }
          }
        }
      }
    }
  }

  return false;
}


function main(grid, words) {
  if (words.length === 0) {
    return grid;
  }

  for (let i = 0; i < words.length; i += 1) {
    const newWords = words.slice();
    const word = newWords.splice(i, 1)[0];
    
    const newGrid = place(grid, word);

    if (newGrid) {
      const result = main(newGrid, newWords);
      if (result) {
        return result;
      }
    }
  }
  
  return false;
}


function place(grid, word) {
  const len = word.length;
  const loc = findBlank(grid, word);

  if (!loc) {
    return false;
  }

  const newGrid = grid.slice().map(line => line.split(''));
  const iIncr = loc.dir === V ? 1 : 0;
  const jIncr = loc.dir === H ? 1 : 0;

  let i = loc.i;
  let j = loc.j;
  let count = 0;

  while (count < len) {
    if (newGrid[i][j] !== '-' && newGrid[i][j] !== word[count]) {
      return false;
    }

    newGrid[i][j] = word[count];
    i += iIncr;
    j += jIncr;
    count += 1;
  }
  
  return newGrid.map(line => line.join(''));
}

process.stdin.setEncoding('ascii');
let _input = '';
process.stdin.on('readable', () => _input += process.stdin.read() || '');
process.stdin.on('end', () => {
  const grid = _input.split('\n');
  const words = grid.pop().split(';');

  const result = main(grid, groupWords(words));

  //console.log(result); return;

  console.log(result.join('\n'));
});