Cell phone Charge

Challenge Taken with permission from my University Code Challenge Contest

The dependence we have on mobile phones makes us charge them every night up to the maximum level of the battery, so we do not run the risk of running out of power by the middle of the next day. There are even people who, when they see a free outlet during the day, put it to charge for what may happen.

I am one of them.

Over the years, I have refined my technique to not charge the battery to the maximum every night. With my perfectly known repetitive routines, I am clear on what times of the day I will be able to do those partial recharges (and how many units the level will increase) and what lowers the battery level between each charge. With these data, every night I calculate the minimum battery level I have to leave the house the next day with so that it never falls below my self-imposed threshold of two units.

What I have not yet managed to master is that same calculation when I leave the established routine and I have several alternatives to do things. It happens, for example, on the days when I'm en route to another city to which I can arrive in different ways.

In my first approach to the problem, I am assuming that I want to move around a "chessboard", from the upper-left corner to the lower-right corner. In each "cell" I can either charge the mobile a specific amount, or I cannot and its load level goes down.

Challenge

Given a FxC matrix of integers, output the minimal battery level amount I need to go from the top-left corner to the bottom-right without the load level ever falling below 2 units.

In the matrix, a positive number indicates how much I can charge my mobile phone before I have to resume following my path, while a negative number indicates that there are no outlets and that the mobile's battery drops its charge level by that amount. It is guaranteed that the quantities in the source and destination cells (top-left and bottom-right corner) are always 0 and that the rest of the values (absolute value) do not exceed 100.

Example
Given: $$\begin{bmatrix} 📱&-1&1&-1 \\ -1&-1&-1&-1 \\ -1&1&-1&-1 \\ 1&1&-1&0 \end{bmatrix}$$

The path I need less battery is:

$$\begin{bmatrix} 📱&-1&1&-1 \\ \color{blue}{-1}&-1&-1&-1 \\ \color{blue}{-1}&1&-1&-1 \\ \color{blue}{1}&\color{blue}{1}&\color{blue}{-1}&0 \end{bmatrix}$$

And the minimal battery level amount I need is 4

Notes

• The Start is always going to be the top-left corner
• The End is always going to be the bottom-right corner
• You cannot go to a cell you've already passed. Example: Once in position (0,1), you cannot go to the initial point (0,0)
• Your battery level cannot (for any reason) go under 2
• You can assume there will always be a beginning and an end
• You can take the 1-dimensional arrays as multidimensional if you need to [1,2,3] == [[1,2,3]]
• There can be multiple correct (minimal needed charge) paths
• Your goal is to only output the lowest initial battery level needed, not the route
• You can only go vertically and horizontally (not diagonally)

Test Cases

[0, 0] => 2
[0, 1, 0] => 2
[0, -1, 0] => 3
[0, 15, -20, 5, 0] => 7
[[0, -3],[-5, 0]] => 5
[[0, -5, -9, 5], [-3, 5, 2, -2], [2, -4, -4, 0]] => 5
[[0, -1, 1, -1], [-1, -1, -1, -1], [-1, 1, -1, -1], [1, 1, -1, 0]] => 4

• I forgot the day of the challenge. Sandbox post – Luis felipe De jesus Munoz Feb 15 '19 at 15:05
• To anybody remembering: The challenge "The Hungry Moose" never made it out of the sandbox, so this is no dupe. – Black Owl Kai Feb 15 '19 at 15:20
• @BlackOwlKai I think both challenges are different – Luis felipe De jesus Munoz Feb 15 '19 at 15:43
• Will the optimal path ever require moving left or up? For example [[0,1,-1],[-9,-9,1],[-9,1,-1],[-9,-1,-9],[-9,1,0]] – Kamil Drakari Feb 15 '19 at 16:37
• @dana no, there are only 2 0s placed one at the top-left corner and the other one at the bottom-right – Luis felipe De jesus Munoz Feb 18 '19 at 17:42

JavaScript (ES7),  162 156  154 bytes

m=>(M=g=(x,y,n,k)=>m.map((r,Y)=>[r[x+1]]+[m[y+1]]?r.map((v,X)=>r[1/v&&(x-X)**2+(y-Y)**2==1&&g(X,Y,u=v+n,k<u?k:u,r[X]=g),X]=v):M=M>k?M:k))(0,0,0)|M<0?2-M:2


Try it online!

Commented

m => (                          // m[] = input matrix
M =                           // initialize M to a non-numeric value
g = (x, y, n, k) =>           // g = recursive depth-first search function
m.map((r, Y) =>             // for each row r[] at position Y in m[]:
[r[x + 1]] +              //   if either r[x + 1]
[m[y + 1]] ?              //   or m[y + 1] is defined:
r.map((v, X) =>         //     for each value v at position X in r[]:
r[                    //
1 / v &&            //       if v is numeric
(x - X) ** 2 +      //       and the squared Euclidean distance
(y - Y) ** 2 == 1   //       between (x, y) and (X, Y) is 1:
&&                  //
g(                //         do a recursive call:
X, Y,           //           with (X, Y)
u = v + n,      //           with n = n + v
k < u ? k : u,  //           with k = min(k, n + v)
r[X] = g        //           set r[X] to a non-numeric value
),                //         end of recursive call
X                   //       then restore r[X]
] = v                 //       to its initial value
)                       //     end of inner map()
:                         //   else (we've reached the bottom right corner):
M = M > k ? M : k       //     update M to max(M, k)
)                           // end of outer map()
)(0, 0, 0) |                    // initial call to g with x = y = n = 0 and k undefined
M < 0 ? 2 - M : 2               // return 2 - M if M is negative, or 2 otherwise


Python 2, 208 202 bytes

lambda s:2-f(s)
def f(s,x=0,y=0):
if x>-1<y<s[y:]>[]<s[y][x:]!="">s[y][x]:k=s[y][x];s[y][x]="";return k+min(0,max([len(s[y+1:]+s[y][x+1:])and f(eval(s),x+a/3-1,y+a%3-1)for a in 7,1,5,3]))
return-9e9


Try it online!

Python 2, 217 211 bytes

i=input()
X,Y=len(i[0]),len(i)
s=[[0]*4+[i]];r=[]
for m,l,x,y,g in s:
if X>x>-1<y<Y<"">g[y][x]:r+=[m]*(Y-y<2>X-x);l+=g[y][x];g[y][x]="";s+=[[min(m,l),l,x+a/3-1,y+a%3-1,eval(g)]for a in 7,1,5,3]
print 2-max(r)


Try it online!

R, 224220217213 210 bytes

f=function(x,m=rbind(0,cbind(0,x,0),0),i=2,j=2,p=F,k=c(1:-1,0,0,-1:1),b=Inf,^=min){m[i,j]=0
for(h in 1:4)b=b^'if'(all(c(R<-i+k[h],C<-j+k[h+4])>dim(x)),max(2,2-cumsum(p)^0),if(v<-m[R,C])b^f(x,m,R,C,c(p,v)))
b}


Try it online!

C# (Visual C# Interactive Compiler), 242 bytes

a=>{int m=1<<31,n=~m;void g(int w,int x,int y,int z){for(int i=4,t,c,d,e;i-->0;)try{t=a[c=i<1?w-1:i<2?w+1:w,d=i>2?x-1:i>1?x+1:x];n=t==0&z<n?z:n;a[c,d]=m;e=y+t<2?2-y-t:0;if(t!=m)g(c,d,y+t+e,z+e);a[c,d]=t;}catch{}}a[0,0]=m;g(0,0,2,2);return n;}


Try it online!

//a: input matrix
a=>{
// m: marker for used cells
// n: result, initialized to a huge value
int m=1<<31,n=~m;
// recursive function
// w: 1st dim coordinate
// x: 2nd dim coordinate
// y: current charge level
// z: initial charge for current path
void g(int w,int x,int y,int z){
// i: loop variable
// t: temp holds overwritten value
// c: adjacent 1st dim coordinate
// d: adjacent 2nd dim coordinate
// e: delta charge needed
for(int i=4,t,c,d,e;i-->0;)
// avoid index out of range errors
// by using try/catch
try{
// determine neighbor
// coordinates and save value
t=a[c=i<1?w-1:i<2?w+1:w,
d=i>2?x-1:i>1?x+1:x];
// if we have found a 0, check if
// initial charge is lower than the
// lowest so far. save it if it is.
n=t==0&z<n?z:n;
// mark current cell used
a[c,d]=m;
// determine if we need to
// increase the initial charge
e=y+t<2?2-y-t:0;
// make recursive call if current
// cell was not previously in use
if(t!=m)g(c,d,y+t+e,z+e);
// restore current cell value
a[c,d]=t;
}catch{}
}
// mark starting cell used
a[0,0]=m;
// start the recursive function
g(0,0,2,2);
// return the result to the caller
return n;
}