Increasing the conditions in IF statement with loop PHP, Diagonal Check

Viewed 273

I have homework to do this program in PHP, that take a matrix and the keywords, so it can find them in the matrix diagonally:

enter image description here

So this is how the first matrix looks, there are many with different keywords, here for instance keywords are "beef" and "pork". So I made a program for an input that looks like these 2 examples:

enter image description hereenter image description here

There correct input for these two is here:

enter image description here enter image description here

Here is my code that works only in the first case, I don't know how to make a loop that will make more and more conditions instead of writing down all these conditions with && in if statement.

Please give me some tips on how to do it:

<?PHP


$input_line = trim(fgets(STDIN));
$input_array = explode(" ",$input_line);

// get mojiban
$mojiban = array();
for($ix=0; $ix<$input_array[0];$ix++){
    $mojiban[] = str_split(trim(fgets(STDIN)));
}

//get words
    $words = array();
    for( $kx = 0; $kx < $input_array[1]; $kx++ ){
    $words[] = trim(fgets(STDIN));
}

////check verticales
//get word
    $wordCharArray = array();
for($dx=0; $dx < $input_array[1]; $dx++){
    $wordCharArray = str_split($words[$dx]);

//looping and checking
    
    for ( $line = 0; $line < $input_array[0] ; $line++) {
        for ( $column = 0; $column < $input_array[0] ; $column++ ){
           // for ($wordsNumber = 0; $wordsNumber < $input_array[1] ; $wordsNumber++){
            
                if ($mojiban[$line][$column] == $wordCharArray[0] && $mojiban[$line+1][$column+1] == $wordCharArray[1]) {
                    echo ($column+1)." ".($line+1)."\n";
                
            //}
        }
    }
}

Thanks in Advance!

4 Answers

Here's a solution to your problem right now it only checks for diagonal elements. You can refactor as you want from below.

There are many different solutions but the solution for your code I have pasted first checks for the character match in the array. If there is a match, it proceeds to check diagonally for the element from the position that it found the first element.

<?php

// First martix
// $searchWords = ["BEEF", "PORK"];
// $matrix = ["HPPLLM", "UROQUV", "FBSRZY", "DPEFKT", "GBBEUY", "EMCQFY"];

// Second martix
$searchWords = ["ABA", "BAB"];
$matrix = ["ACEG", "HBDF", "EGAC", "DFHB"];

// returns true if it diagonally matches the element in matrix from start row
function checkDiagonallyForString(string $search, array $matrix, int $startRow, int $firstMatchPosition)
{
    $endRow = $startRow + (strlen($search) - 2);
    $finding = true;

    foreach (range($startRow, $endRow) as $searchIndex => $rowValue) {
        if (!$finding) {
            break;
        }
        $char = $search[$searchIndex + 1];
        $finding = $matrix[$rowValue][$firstMatchPosition + $searchIndex] == $char;

    }
    return $finding;
}

// format: [word: [column, row]]
$found = [];

foreach ($matrix as $row => $matrixString) {
    if (!count($searchWords)) {
        break;
    }
    foreach ($searchWords as $wordRow => $word) {
        $position = strpos($matrixString, $word[1]);
        if ($position != false) {
            if (checkDiagonallyForString($word, $matrix, $row, $position)) {
                // $position = column of matrix
                // $row = row of matrix
                $found[$word] = [$position, $row];
                unset($searchWords[$wordRow]);
            }
        }
    }

}

// Pretty output
echo "<pre>";
print_r($found);

foreach ($found as $word => $indexes) {
    echo $word . " " . implode(" ", $indexes) . "\n";
}

The results are: enter image description hereenter image description here

Note: This is a complete answer but before copying and pasting this please try to get a general idea and attempt to solve it yourself. This is not the only way of doing it.

We can use implode tactics from comments. Here is example: click.

Code:

// First martix
$searchWords = ["BEEF", "PORK"];
$matrix = ["HPPLLM", "UROQUV", "FBSRZY", "DPEFKT", "GBBEUY", "EMCQFY"];

// Second martix
// $searchWords = ["ABA", "BAB"];
// $matrix = ["ACEG", "HBDF", "EGAC", "DFHB"];

$matrixStr = implode('', $matrix);
$matrixSize = count($matrix);
$positions = [];

foreach ($searchWords as $wordIdx => $word) {
    $wordSize = strlen($word);
    $found = false;
    for ($y = 0; $y <= $matrixSize - $wordSize && !$found; $y++) {
        for ($x = 0; $x <= $matrixSize - $wordSize && !$found; $x++) {
            $allLettersOk = true;
            for ($l = 0; $l < $wordSize; $l++) {
                if ($matrixStr[$y * $matrixSize + $x + $l * $matrixSize + $l] != $word[$l]) {
                    $allLettersOk = false;
                    break;
                }
            }
            if ($allLettersOk) {
                $positions[$word] = [$x + 1, $y + 1];
                $found = true;
            }
        }
    }
}

foreach ($positions as $word => $indexes) {
    echo $word . " " . implode(" ", $indexes) . "\n";
}

If you need a description to this code - write a comment.

// First martix
$searchWords = ["BEEF", "PORK"];
$matrix = ["HPPLLM", "UROQUV", "FBSRZY", "DPEFKT", "GBBEUY", "EMCQFY"];

// Second martix
// $searchWords = ["ABA", "BAB"];
// $matrix = ["ACEG", "HBDF", "EGAC", "DFHB"];

$matrixStr = implode('', $matrix);
$matrixSize = count($matrix);
$positions = [];

foreach ($searchWords as $wordIdx => $word) {
    $wordSize = strlen($word);
    $found = false;
    for ($y = 0; $y <= $matrixSize - $wordSize && !$found; $y++) {
        for ($x = 0; $x <= $matrixSize - $wordSize && !$found; $x++) {
            $allLettersOk = true;
            for ($l = 0; $l < $wordSize; $l++) {
                if ($matrixStr[$y * $matrixSize + $x + $l * $matrixSize + $l] != $word[$l]) {
                    $allLettersOk = false;
                    break;
                }
            }
            if ($allLettersOk) {
                $positions[$word] = [$x + 1, $y + 1];
                $found = true;
            }
        }
    }
}

foreach ($positions as $word => $indexes) {
    echo $word . " " . implode(" ", $indexes) . "\n";
}

Your $input_array contains your matrix, at each position you have a character, like this

$input_array = [
    ['H', 'P', 'P', 'L', 'L', 'M'],
    ['U', 'R', 'O', 'Q', 'U', 'V'],
    ['F', 'B', 'S', 'R', 'Z', 'Y'],
    ['D', 'P', 'E', 'F', 'K', 'T'],
    ['G', 'B', 'B', 'E', 'U', 'Y'],
    ['E', 'M', 'C', 'Q', 'F', 'Y'],
];

For the sake of simplicity, let's assume that you also have an array of arrays. I know you have strings, but string operations would make this solution difficult to read and we are mostly interested in the algorithm, so, for the sake of understandability I will not start from your actual data structure, but will answer questions if you have difficulty implementing this into your solution:

$words = [
    ['B', 'E', 'E', 'F'],
    ['P', 'O', 'R', 'K']
];

Notice that beef and pork are of the same length, but let's not assume that all words are of the same length.

//Computing row count so it can be reused
$rowCount = count($input_array);
//Computing the column count so it can be reused
//We assume that each row of the matrix has the same number of columns
$colCount = count($input_array[0]);
//Looping the rows
for ($row = 0; $row < $rowCount; $row++) {
    //Looping the columns of the row
    for ($column = 0; $column < $colCount; $column++) {
        //Computing the max length of allowed words
        $maxLength = min($rowCount - $row, $colCount - $col);
        //Looping the words
        for ($wIndex = 0; $wIndex < count($words); $wIndex++) {
            //Storing the length of the current word for later use
            $charCount = count($words[$wIndex]);
            //We avoid checking for the presence of words that are
            //Longer than the current position allows
            if ($charCount <= $maxLength) {
                //match is initialilzed with true and will be set false at
                //the first mismatch. If no mistmatch is found, then we know
                //that the word is present at the current position
                $match = true;
                //Looping the word's characters and check for possible
                //mismatches
                //Notice that we stop the loop either at the first mismatch
                //or at the last character if there is no mismatch
                for ($cIndex = 0; $match && ($cIndex < $charCount); $cIndex++) {
                    //If the word character at cIndex offset mismatches
                    //the character of input array at the same offset, starting
                    //from the [$row][$column] position, then it mismatches
                    if ($words[$wIndex][$cIndex] !== $input_array[$row + $cIndex][$column + $cIndex]) $match = false;
                }
                if ($match) {
                    //Say the word
                    echo implode("", $words[$wIndex]) . " found at row " . ($row + 1) . ", column " . ($column + 1);
                }
            }
        }
    }
}
Related