This week I have started to study Python a little more into detail in the courses of HackBulgaria. After end of the second day, the last problem was considered worthy for blogging, as far as it took me about an hour (or less) to come up with a solution.
Anyway, the problem was not that difficult, the difficulty was that I am somehow reluctant to work with dictionaries, especially when the key to the dictionary is a tuplet. Enough speaking, here comes the description of the problem, taken from here:
Matrix Calculation
You are given a NxM
matrix of integer numbers.
We can drop a bomb at any place in the matrix, which has the following effect:
- All of the 3 to 8 neighbours (depending on where you hit!) of the target are reduced by the value of the target.
- Numbers can be reduced only to 0 – they cannot go to negative.
For example, if we have the following matrix:
1 2 3 |
10 10 10 10 9 10 10 10 10 |
and we drop at 9
, this will result in the following matrix:
1 2 3 |
1 1 1 1 9 1 1 1 1 |
Implement a function called matrix_bombing_plan(m)
.
The function should return a dictionary where keys are positions in the matrix, represented as tuples, and values are the total sum of the elements of the matrix, after the droping at that position.
The positions are the standard indexes, starting from (0, 0)
For example if we have the following matrix:
1 2 3 |
1 2 3 4 5 6 7 8 9 |
and run the function, we will have:
1 2 3 4 5 6 7 8 9 10 11 |
(0, 0): 42, (0, 1): 36, (0, 2): 37, (1, 0): 30, (1, 1): 15, (1, 2): 23, (2, 0): 29, (2, 1): 15, (2, 2): 26 |
We can see that if we drop at(1, 1) or (2, 1), we will do the most damage!
So, after some analysis, this is what I realized:
- We should make the function work with any size of a matrix;
- We should give as an imput the matrix;
- We should calculate the boundaries of the given matrix;
- I should find a way to be able to reach the values in the dictionary and change them;
- I should use 3 different dictionaries – one for the input, one for the calculation of every single case, one for the output;
- The one for the calculation for every single case should be rewritten with new values every time, thus I need to know how to erase a dictionary in Python;
- It could be a good idea to make a function, returning me a 0 for each negative value;
- Enough 🙂
Did it work? Check out by yourself:
So, how did I did it? Here comes the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
m = {(0, 0): 1, (0, 1): 2, (0, 2): 3, (1, 0): 4, (1, 1): 5, (1, 2): 6, (2, 0): 7, (2, 1): 8, (2, 2): 9, (0, 3): 1000, (1, 3): 500, (2, 3): 500, } def zero_if_negative(myValue): if myValue<1: return 0 return myValue def matrix_bombing_plan(myValue): lResult = dict(myValue) #define greatest k[0] iGreatest0 #define greatest k[1] iGreatest1 iGreatestRow = 0 iGreatestCol = 0 for k in iter(myValue.keys()): if iGreatestRow < k[0]: iGreatestRow = k[0] if iGreatestCol < k[1]: iGreatestCol = k[1] for k in iter(myValue.keys()): iRow = k[0] iCol = k[1] #Rebuilding the dictionary here: lTempResult = dict(myValue) #Left, Right, Up and Down: if iRow+1<=iGreatestRow: lTempResult[iRow+1,iCol]-=lTempResult[iRow,iCol] lTempResult[iRow+1,iCol] = zero_if_negative(lTempResult[iRow+1,iCol]) if iRow-1>=0: lTempResult[iRow-1,iCol]-=lTempResult[iRow,iCol] lTempResult[iRow-1,iCol] = zero_if_negative(lTempResult[iRow-1,iCol]) if iCol+1<=iGreatestCol: lTempResult[iRow,iCol+1]-=lTempResult[iRow,iCol] lTempResult[iRow,iCol+1] = zero_if_negative(lTempResult[iRow,iCol+1]) if iCol-1>=0: lTempResult[iRow,iCol-1]-=lTempResult[iRow,iCol] lTempResult[iRow,iCol-1] = zero_if_negative(lTempResult[iRow,iCol-1]) #Diagonals: if iCol-1>=0 and iRow-1>=0: lTempResult[iRow-1,iCol-1]-=lTempResult[iRow,iCol] lTempResult[iRow-1,iCol-1] = zero_if_negative(lTempResult[iRow-1,iCol-1]) if iCol+1<=iGreatestCol and iRow-1>=0: lTempResult[iRow-1,iCol+1]-=lTempResult[iRow,iCol] lTempResult[iRow-1,iCol+1]= zero_if_negative(lTempResult[iRow-1,iCol+1]) if iCol-1>=0 and iRow+1<=iGreatestRow: lTempResult[iRow+1,iCol-1]-=lTempResult[iRow,iCol] lTempResult[iRow+1,iCol-1] = zero_if_negative(lTempResult[iRow+1,iCol-1]) if iCol+1<=iGreatestCol and iRow+1<=iGreatestRow: lTempResult[iRow+1,iCol+1]-=lTempResult[iRow,iCol] lTempResult[iRow+1,iCol+1] = zero_if_negative(lTempResult[iRow+1,iCol+1]) lResult[iRow,iCol]=sum(lTempResult.values()) return lResult print(matrix_bombing_plan(m)) |
Update – it is possible not to use the function “zero_if_negative”, but to loop over the dictionary lTempResult[] and assign to zero each negative value, like this:
1 2 3 4 5 6 7 8 9 10 |
if iCol+1<=iGreatestCol and iRow+1<=iGreatestRow: lTempResult[iRow+1,iCol+1]-=lTempResult[iRow,iCol] #^-- existing code: #v-- new code: for key in lTempResult: if lTempResult[key]<0: lTempResult[key]=0 #^-- new code: #v-- existing code: lResult[iRow,iCol]=sum(lTempResult.values()) |
Enjoy it 🙂