# Working with matrices solution

Project Description
When dealing with matrices, its often needed to explore all the elements adjacent to a given one. Given an element matrix[i][j], the set of elements that are the adjacent to it are those having row index and column index in the range:
i-1 to i+1
j-1 to j+1
Note that we include the element itself in the set of adjacent elements.
When finding the neighbors, of course care must be taken when dealing with elements at the border of the matrix. Look at the following examples. The first example depicts the neighbors of the matrix element having value 0 (the one having row 0 and column 0 as indexes).

The second example depicts the neighbors of the matrix element having value 30 (the one having row 2 and column 3 as indexes).

Hence the row and column indexes must be adjusted consequently.
The exploration of the neighbors of a given element is an essential component of several games (for example, Minesweeper or Battleship).
In this project, you have to write functions that scan the elements of a matrix and that explore the neighbors of matrix elements.
To begin, create a file called project3.py under the project3 folder.

TODO1: Counting in the neighborhood

You have to write a function called count_nonneg_neighbors that counts the number of non-negative integer elements that are in the set of the neighboring elements of a given element of a matrix. The given element must be included in the count (if it is a non-negative integer). The function MUST have the following as its input arguments:

• the matrix

• the row index

• the column index

The function MUST return a list having the following structure and content:
[[rowInd, colInd], count]
where rowInd and colInd are the row and column indexes passed to the function, and count is the count of the positive integers in the neighboring elements.
The matrix elements can also contain non-numeric elements such as characters and/or string(s) of characters. The function must take care of this possibility.

Test cases

To test your function, you can use the following matrices.

Test case 1

Given the following matrix:

Consider the sample output table below. Given the row index and column index for a matrix element (presented in the two leftmost column), the expected return values for count_nonneg_neighbors are given in the rightmost column:

row index
column index
return values

0
0
[[0, 0], 3]

2
3
[[2, 3], 3]

1
2
[[1, 2], 6]

Test case 2

Given the following matrix:

Consider the sample output table below. Given the row index and column index for a matrix element (presented in the two leftmost column), the expected return values for count_nonneg_neighbors are given in the rightmost column:

row index
column index
return values

0
0
[[0, 0], 3]

0
2
[[0, 2], 2]

3
2
[[3, 2], 2]

TODO 2 - Sum of neighboring elements

You have to write a function called sum_neighbors that sums only all positive integers in the neighboring elements of a given element of the matrix. The given element must be included in the sum (if it is a positive integer).
The function MUST return a list having the following structure and content:
[[rowInd, colInd], count]
where rowInd and colInd are the row and column indexes passed to the function, and count is the count of the positive integers in the neighboring elements.
The matrix elements can also contain non-numeric elements such as characters and/or string(s) of characters. The function must take care of this possibility.

Test cases

To test your function, you can use the following matrices.

Test case 1

Given the following matrix:

Consider the sample output table below. Given the row index and column index for a matrix element (presented in the two leftmost column), the expected return values for sum_neighbors are given in the rightmost column:

row index
col index
return values

0
3
[[0, 3], 22]

2
0
[[2, 0], 20]

2
3
[[2, 3], 58]

Test case 2

Given the following matrix:

Consider the sample output table below. Given the row index and column index for a matrix element (presented in the two leftmost column), the expected return values for sum_neighbors are given in the rightmost column:

row index
col index
return values

0
0
[[0, 0], 7]

0
2
[[0, 2], 6]

3
2
[[3, 2], 15]

TODO 3 - Extract reverse string

You have to write a function called find_chars_reverse that, given a matrix as an input argument, must do the following things:

• Scan the matrix from the bottom-right to the upper left corner in row order and,

• Return a string composed by the concatenation of the characters (or strings) contained in the matrix elements.

Scanning the matrix from the bottom-right to the upper left corner in row order means that, if the matrix has M rows and N columns, the function must:

• First, scan the elements in row M, then those in row M-1, up to row 0; and

• For each row, scan the element from the Nth to the 0th column.

Test case 1

Given the following matrix:
[[0,'xx x',2,'B aB'],['c',4,-5,20],['d',7,8,'e']]
The function must return the following string:
'edcB aBxx x'

Test case 2

Given the following matrix:
[[0,-1,2,-10],[3,4,-5,20],[6,7,8,30]]
The function must return the following string:
''

TODO 4 - String analysis

You have to write a function called analyze_string that will analyze the content of the string you built in TODO 3. More precisely, the function must count the number of lower case characters, upper case characters, blank characters, and digit characters that are contained in the input string. A digit character is a character representing a digit (from 0 to 9), such as '1'.
The function MUST return a list like the following one:
[lowcase_count, uppcase_count, blank_count, digit_count]
where lowcase_count is the number of lower case letters, uppcase_count is the number of the upper case letters, blank_count is the number of blank characters, and digit_count is the number of digit characters in the string. The counters MUST be in the order above.
You already saw several methods working on strings. Python string type provides several methods that performs useful functions on string. Refer to the Python documentation here: section 4.7.1. String Methods , to find the methods you need to use for your task.

TODO 5 - Main function

You have to write the main() function. It must scan the matrix, and:

• Count the non-negative integers in the set of neighbors of each element of the matrix by calling the count_nonneg_neighbors function, and

• Calculate the sum of the positive integers in the set of neighbors of each element of the matrix by calling the sum_neighbors function

Then, main() must call the function find_chars_reverse() and finally the function analyze_string() to analyze the string produced by find_chars_reverse().
The main() function must produce a printout similar to the following:
The number of positive neighbors for element 0 0 is: 3
The number of positive neighbors for element 0 1 is: 4
The number of positive neighbors for element 0 2 is: 3
The number of positive neighbors for element 0 3 is: 2
The number of positive neighbors for element 1 0 is: 5
The number of positive neighbors for element 1 1 is: 7
The number of positive neighbors for element 1 2 is: 6
The number of positive neighbors for element 1 3 is: 4
The number of positive neighbors for element 2 0 is: 4
The number of positive neighbors for element 2 1 is: 5
The number of positive neighbors for element 2 2 is: 5
The number of positive neighbors for element 2 3 is: 3
The sum of positive integers neighboring of: 0 0 is: 7
The sum of positive integers neighboring of: 0 1 is: 9
The sum of positive integers neighboring of: 0 2 is: 26
The sum of positive integers neighboring of: 0 3 is: 22
The sum of positive integers neighboring of: 1 0 is: 20
The sum of positive integers neighboring of: 1 1 is: 30
The sum of positive integers neighboring of: 1 2 is: 71
The sum of positive integers neighboring of: 1 3 is: 60
The sum of positive integers neighboring of: 2 0 is: 20
The sum of positive integers neighboring of: 2 1 is: 28
The sum of positive integers neighboring of: 2 2 is: 69
The sum of positive integers neighboring of: 2 3 is: 58
The string contained in the matrix is:
number of upper case is: 0 number of lower case: 0
number of blank characters is: 0 number of digits is: 0
Note that main() produces the printout above for the matrix used in Test Case 1 described in the section TODO 1.

NOTES

All the print statements MUST be in the main() function; so do NOT put the print statements required by the specifications in the body of the other functions.
We encourage you to use as many print statements as you may need in the body of the functions, but only for debugging purposes. Once you see that your function works properly, just put the # sign at the beginning of the print statement, so that it will not be executed any longer.
For example, if you want to be sure that you are generating the right sequence of indexes to be used in a for statement, you can add to your code the following print statement:
print (list(range(1,10)))

for i in range (1, 10):
......
If you see that the range you generated is the correct one, just make the print statement above a comment:
# print (list(range(1,10)))

When we write in the project specifications: the function MUST do such and suc, this means that your implementation must adhere to those specifications. If you do not do that, you will lose points.