Missing numbers in arithmetic sum

14

1

Challenge

Giving a valid arithmetic sum with some missing numbers, output the full expression.

Example:

    1#3                 123
+   45#     =>     +    456
--------            --------
    579                 579

Input

  • Expression format can be an array ["1#3", "45#", "579"], a string "1#3+45#=579", or 3 inputs f("1#3","45#","579")

Output

  • Same as input
  • You don't need to output the result

Notes

  • The missing numbers are going to be represented using # or any other constant non-numeric character you want
  • Assume result wont have a missing number
  • Assume Input/Output consist in 2 terms and a final result
  • Assume both term > 0 and result >= 2
  • There might be multiple solutions. You can output anyone as long as the sum result match

Test Cases with possibly outputs (pretty format)

    #79                     879
+   44#         =>      +   444
--------                --------
    1323                   1323

    5#5                     555
+   3#3         =>      +   343
--------                --------
    898                     898

      #                       1
+     #         =>      +     1
--------                --------
      2                       2

    ###                     998
+   ###         =>      +     1     PD: there are a lot of possible outputs for this one
--------                --------
    999                     999


    123                     123
+     #         =>      +     1
--------                --------
    124                     124


      9                       9
+    #6         =>      +    46
--------                --------
     55                      55


    #123651                     1123651
+      #98#         =>      +      7981
------------                -----------
    1131632                     1131632

Standard rules apply

Luis felipe De jesus Munoz

Posted 2018-08-30T14:36:34.223

Reputation: 9 639

Do we need to strip leading zeros? – None – 2018-08-30T14:55:09.363

@Mnemonic not necessarily – Luis felipe De jesus Munoz – 2018-08-30T14:58:47.693

can I take the input with the sides around = swapped? e.g. 579=1#3+45# – dzaima – 2018-08-30T15:25:55.287

@dzaima yes , no problem – Luis felipe De jesus Munoz – 2018-08-30T15:28:18.613

test-case request: ###+###=2 – dzaima – 2018-08-30T15:43:03.030

2"Assume both term > 0" does "assume" mean that I have to output both terms > 0 or that I can assume that there's always a solution with both > 0 but output whatever? – dzaima – 2018-08-30T15:48:03.170

1also your added test-case avoids exactly what I was asking for - the leading zeroes – dzaima – 2018-08-30T15:48:39.290

Distantly related (as in: both require fixing arithmetic equations). – Kevin Cruijssen – 2018-08-31T09:55:05.483

Can I take input with == instead of =? – Titus – 2018-09-10T18:39:34.820

Answers

9

Brachylog, 22 16 bytes

{Ṣ∧Ị∋|}ᵐ²ịᵐ.k+~t

Try it online!

-6 bytes thanks to @Fatelize

Explanation

{Ṣ∧Ị∋|}ᵐ²ịᵐ.k+~t
{     }ᵐ²                   #   for each letter in each string
 Ṣ∧Ị∋                       #       if " " return a digit; else input
     |                      #
         ịᵐ                 #   cast each string to number
            k+              #   the sum of all but the last one
              ~t            #       is equal to the last one
           .                #   output that list

Kroppeb

Posted 2018-08-30T14:36:34.223

Reputation: 1 558

1{"#"∧Ị∋|}ᵐ²ịᵐ.k+~t is 4 bytes shorter. I'm not sure why you did something this convoluted in your map. – Fatalize – 2018-08-31T06:57:52.640

Since we can use any non-numeric character, you should use e.g. space with instead of "#" which will save two more bytes. – Fatalize – 2018-08-31T06:59:22.080

8

JavaScript (ES6), 74 57 bytes

Takes input as (a)(b)(result), where a and b are strings with . for unknown digits and result is an integer. Returns an array of 2 integers.

a=>b=>F=(c,n)=>`${r=[c,n]}`.match(`^`+[a,b])?r:F(c-1,-~n)

Try it online!

Commented

a => b =>                // a, b = term patterns (e.g. a = ".79", b = "44.")
  F = (c,                // c = expected result (e.g. 1323)
          n) =>          // n = guessed value of b, initially undefined
    `${r = [c, n]}`      // we coerce r = [c, n] to a string (e.g. "879,444")
                         // if n is still undefined, this gives just c followed by a comma
    .match(`^` + [a, b]) // we coerce [a, b] to a string, prefixed with "^" (e.g. "^.79,44.")
    ?                    // this is implicitly turned into a regular expression; if matching:
      r                  //   return r
    :                    // else:
      F(c - 1, -~n)      //   decrement c, increment n and do a recursive call

Arnauld

Posted 2018-08-30T14:36:34.223

Reputation: 111 334

Ah, so that's what's happening. I tried to understand your code without explanation yesterday (and I'm bad at JS), but didn't understand why -~n couldn't be just n+1 and how F=(c,n)=> was used. Now that you added an explanation it all makes sense. c is the third input, n is undefined (and ~undefined becomes -1 unlike undefined+1). All clear now (and not something I can port to Java unfortunately, which was mainly why I tried to understand it xD). PS: Already upvoted yesterday, so I just upvoted one of your other answers (which I didn't upvote already, not a lot available..) ;p – Kevin Cruijssen – 2018-08-31T15:59:07.593

@KevinCruijssen FWIW, I wrote a tip about this some times ago. But yeah ... that's a JS thing and is probably not portable to many other languages.

– Arnauld – 2018-08-31T16:08:49.913

Well, I might be able to semi-port it but just creating a recursive second method, and using a ternary-if to check for null, manually converting it to -1. However, Java has a (very) limited recursive StackOverflow limit, so using a recursive method with randomness hoping it would end up correct within about 1024 recursive calls isn't going to work anyway in Java. Ah well. I've upvoted your tip. Have a nice weekend! :) – Kevin Cruijssen – 2018-08-31T16:38:42.393

@KevinCruijssen My first JS attempt was doing exactly that: trying random values with a recursive function. And it was usually doing significantly less iterations than the one using a counter. Fun fact: even for ###+###=999, your odds are 1 in 1000. So with 1024 iterations, you should succeed slightly more often than you fail. :) – Arnauld – 2018-08-31T17:05:58.760

7

Matlab, 143 134 132 119 115 bytes

function[m]=f(x,y,r),p=@(v)str2num(strrep(v,'#',char(randi([48,57]))));m=[1,1];while sum(m)-r,m=[p(x),p(y)];end;end

-4 bytes thanks to @Luismendo

Try it Online


Pretty big and pretty stupid. It simply replaces all # with random digits until it finds the correct ones.

DimChtz

Posted 2018-08-30T14:36:34.223

Reputation: 916

5

R, 67 51 bytes

Rock simple and scales horribly, just grep all the sum combinations. Use "." for unknown digits. It won't find the same answer as test case number 4, but it will give a possible answer, which follows the letter of the rules as given.

-16 bytes by grepping after forming the output and replacing paste with the ? operator.

function(x,y,z,`?`=paste)grep(x?y,1:z?z:1-1,v=T)[1]

Try it online!

J.Doe

Posted 2018-08-30T14:36:34.223

Reputation: 2 379

1

I was looking for various operators and you come up with ?... I think this is a first. by the way, I forgot if I already told you but we're trying to get R nominated for september language of the month - you can upvote if not done already.

– JayCe – 2018-08-31T14:26:36.740

I could've chosen anything with low precedence. Feels like there should be a better way to get the match... – J.Doe – 2018-08-31T14:31:44.610

3

Charcoal, 32 bytes

F²⊞υ0W⁻ζΣIυ≔E⟦θη⟧⭆κ⎇⁼μ#‽χμυ←Eυ⮌ι

Try it online! Link is to verbose version of code. Explanation:

F²⊞υ0

Push two string 0s to the predefined empty list u to get the while loop going.

W⁻ζΣIυ

Repeat while the sum of casting the values in u to integer is not equal to the desired result.

≔E⟦θη⟧

Create an array of the two inputs and map over it.

⭆κ⎇⁼μ#‽χμυ

Replace each # with a random digit and assign the result back to u.

←Eυ⮌ι

Print the result right justified. (Left justified would be just υ for a 4-byte saving.)

Neil

Posted 2018-08-30T14:36:34.223

Reputation: 95 035

3

Jelly, 20 bytes

ØDṛċ¡V€)ŒpḌð€ŒpS⁼¥ƇḢ

Try it online!

Erik the Outgolfer

Posted 2018-08-30T14:36:34.223

Reputation: 38 134

3

05AB1E (legacy), 23 20 bytes

[²³«εð9ÝΩ:}²gôJDO¹Q#

-3 bytes thanks to @Emigna.

Unknown digits are spaces ( ). Input order should be: expected result; longest string; shortest string.

Try it online.

Explanation:

[                 # Start an infinite loop
 ²³«              #  Take the second and third inputs, and merge them together
               #   i.e. " 79" and " 4 " → " 79 4 "
    ε     }    #  Map each character to:
     ð   :     #   Replace a space with:
      9ÝΩ      #   A random digit in the range [0,9]
               #    i.e. " 79 4 " → ['3','7','9','2','4','3']
               #    i.e. " 79 4 " → ['5','7','9','7','4','4']
²g             #  Get the length of the second input
               #   i.e. " 79" → 3
  ô            #  And split it into two numbers again
               #   i.e. ['3','7','9','2','4','3'] and 3 → [['3','7','9'],['2','4','3']]
               #   i.e. ['5','7','9','7','4','4'] and 3 → [['5','7','9'],['7','4','4']]
   J           #  Join each list together to a single number
               #   i.e. [['3','7','9'],['2','4','3']] → [379,243]
               #   i.e. [['5','7','9'],['7','4','4']] → [579,744]
    D          #  Duplicate this list
     O         #  Sum the list
               #   i.e. [379,243] → 622
               #   i.e. [579,744] → 1323
      ¹Q#      #  If it's equal to the first input: stop the infinite loop
               #  (and output the duplicate list implicitly)
               #   i.e. 1323 and 622 → 0 (falsey) → continue the loop
               #   i.e. 1323 and 1323 → 1 (truthy) → stop the loop and output [579,744]

Kevin Cruijssen

Posted 2018-08-30T14:36:34.223

Reputation: 67 575

1Replace saves 3 over the if. – Emigna – 2018-08-31T06:10:15.137

@Emigna Ah, of course. Thanks! – Kevin Cruijssen – 2018-08-31T06:52:00.723

3

Perl 6, 81 74 bytes

-7 bytes thanks to nwellnhof!

{first {try S/\=/==/.EVAL},map {$^a;S:g[\#]=$a[$++]},[X] ^10 xx.comb('#')}

Try it online!

Anonymous code block that takes input as a string containing an arithmetical expression e.g. "12#+45#=579". Substitutes each # with possible permutations of digits, substitutes the= with == and finds the first valid result.

Explanation:

{  # Anonymous code block                                                      }
 first   # Find the first of:
                                                               ^10  # The range of 0 to 9
                                                                   xx.comb('#') # Multiplied by the number #s in the code
                                                          ,[X]  # The cross-product of these lists
                          map   # Map each crossproduct to:
                              {$^a;.trans: "#"=>{$a[$++]}}  # The given string with each # translated to each element in the list
      {try S/\=/==/.EVAL}, # Find which of these is true when = are changed to == and it is eval'd

Jo King

Posted 2018-08-30T14:36:34.223

Reputation: 38 234

You can use S:g[\#]=$a[$++] instead of trans for 74 bytes.

– nwellnhof – 2018-09-01T13:05:46.380

@nwellnhof I didn't realise you could use S/// in that sort of syntax! Thanks! – Jo King – 2018-09-01T13:13:22.737

2

APL (Dyalog Unicode), 22 bytes

{'#'⎕R{⍕?10}t}⍣{⍎⍺}t∘←

Try it online!

dzaima

Posted 2018-08-30T14:36:34.223

Reputation: 19 048

2

Java 10, 203 198 193 bytes

(a,b,c)->{int A=0,B=0,l=a.length();for(a+=b,b="";A+B!=c;A=c.valueOf(b.substring(0,l)),B=c.valueOf(b.substring(l)),b="")for(var t:a.getBytes())b+=t<36?(t*=Math.random())%10:t-48;return A+"+"+B;}

Try it online.

Explanation:

(a,b,c)->{           // Method with 2 Strings & integer parameters and String return-type
  int A=0,B=0,       //  Result-integers, starting both at 0
      l=a.length();  //  Length of the first String-input
  for(a+=b,          //  Concat the second String-input to the first
      b="";          //  Reuse `b`, and start it as an empty String
      A+B!=c         //  Loop as long as `A+B` isn't equal to the integer-input
      ;              //    After every iteration:
       A=c.valueOf(b.substring(0,l)),
                     //     Set `A` to the first String-part as integer
       B=c.valueOf(n.substring(l)),
                     //     Set `B` to the second String-part as integer
       b="")         //     Reset `b` to an empty String
    for(var t:a.getBytes())
                     //   Inner loop over the characters of the concatted String inputs
      b+=t<36?       //    If the current character is a '#':
          (t*=Math.random())%10
                     //     Append a random digit to `b`
         :           //    Else (it already is a digit):
          t-48;      //     Append this digit to `b`
  return A+"+"+B;}   //  After the loop, return `A` and `B` as result

Kevin Cruijssen

Posted 2018-08-30T14:36:34.223

Reputation: 67 575

2

C (gcc), 228 213 203 172 170 bytes

-15 Bytes thanks to @ceilingcat. I've never used index before.

-10 Bytes thanks to @Logem. Preprocessor magic

refactored call to exit(0) with puts as parameter.

char*c,*p[9],k;main(i,v)int**v;{for(i=X[1],35))||X[2],35))?p[k++]=c,main(*c=57,v):k;!c*i--;)47==--*p[i]?*p[i]=57:Y[1])+Y[2])^Y[3])?main(i,v):exit(puts(v[2],puts(v[1])));}

Try it online!

cleblanc

Posted 2018-08-30T14:36:34.223

Reputation: 3 360

194 bytes - Try it online! – Logern – 2018-09-25T13:07:45.353

You can save two bytes replacing the macro -DX=c=index(v, with -DX=(c=index(v, TIO link in my last comment. – Logern – 2018-09-25T13:24:17.157

Thanks guys. Doesn't look like I even tried to golf this before... – cleblanc – 2018-09-25T13:33:45.867

1

Python 3, 121 155 152 149 bytes

import re
def f(i,k=0,S=re.sub):s=S('#','%s',i)%(*list('%0*d'%(i.count('#'),k)),);print(s)if eval(S('=','==',S('\\b0*([1-9])','\\1',s)))else f(i,k+1)

Try it online!

+34 New solution with regex to circumvent the fact that python doesn't support numbers with leading zeroes.

-3 thanks to @Jonathan Frech


The old solution doesn't work if # is the first character in any number (because eval doesn't accept leading zeroes) and is therefore invalid :(

def f(i,k=0):
 s=i.replace('#','%s')%(*list('%0*d'%(i.count('#'),k)),)
 print(s)if eval(s.replace('=','=='))else f(i,k+1)

Try it online!

Black Owl Kai

Posted 2018-08-30T14:36:34.223

Reputation: 980

1I'm afraid this submission is invalid for the reason stated in the post. – Erik the Outgolfer – 2018-08-30T17:10:24.387

2Since your function does not contain any compound statements you can condense it to only one line. – Jonathan Frech – 2018-08-30T23:21:46.733

1

C# .NET, 225 220 196 bytes

(a,b,c)=>{int A=0,B=0,l=a.Length;for(a+=b,b="";A+B!=c;A=int.Parse(b.Substring(0,l)),B=int.Parse(b.Substring(l)),b="")foreach(var t in a)b+=(t<36?new System.Random().Next(10):t-48)+"";return(A,B);}

Port of my Java 10 answer.
(I'm very rusty in C# .NET golfing, so can defintely be golfed..)

-3 bytes implicitly thanks to @user82593 and this new C# tip he added.
-29 bytes thanks to @hvd.

Try it online.

Explanation:

(a,b,c)=>{        // Method with 2 string & int parameters and int-tuple return-type
  int A=0,B=0,    //  Result-integers, starting both at 0
      l=a.Length; //  Length of the first string-input
  for(a+=b,       //  Concat the second string-input to the first
      b="";       //  Reuse `b`, and start it as an empty string
      A+B!=c      //  Loop as long as `A+B` isn't equal to the integer-input
      ;           //    After every iteration:
       A=int.Parse(b.Substring(0,l)),
                  //     Set `A` to the first string-part as integer
       B=int.Parse(b.Substring(l)),
                  //     Set `B` to the second string-part as integer
       b="")      //     Reset `b` to an empty string
    foreach(var t in a)
                  //   Inner loop over the characters of the concatted string inputs
      b+=(t<36?   //    If the current character is a '#':
           new System.Random().Next(10)
                  //     Use a random digit
          :       //    Else (it already is a digit):
           t-48)  //     Use this digit as is
         +"";     //    And convert it to a string so it can be appended to the string
  return(A,B);}   //  After the loop, return `A` and `B` in a tuple as result

Kevin Cruijssen

Posted 2018-08-30T14:36:34.223

Reputation: 67 575

You can use the regular using System; instead, it is shorter than namespace System{}. – hvd – 2018-09-01T08:01:05.453

@hvd That was it!.. I haven't done C# in years, lol.. I tried using System.*; similar as imports in Java, but that didn't work. Forgot I had to remove the .* part.. Thanks for the -5 bytes. – Kevin Cruijssen – 2018-09-01T11:01:13.810

1Re-reading it now, that was actually a sub-optimal suggestion. You can write int.Parse (-4), use new System.Random() (+7) and drop using System; (-13) to save another 10 bytes. :) Also, you do not need .ToCharArray(), that takes off 14 more bytes. – hvd – 2018-09-01T11:05:24.133

@hvd Thanks! Not sure how I forgot about int.Parse vs System.Int32.Parse... It's basically the same as System.String and string.. And didn't knew it was possible to loop over the characters without the .ToCharArray(). Thanks for another -24 bytes. :D – Kevin Cruijssen – 2018-09-01T11:49:34.200

0

Powershell, 91 byte

The script finds all solutions. The total number of iterations is 10 power the number of characters #. The recursion depth is equal to the number of characters #.

filter f{$h,$t=$_-split'#',2
if($t){0..9|%{"$h$_$t"}|f}elseif($h-replace'=','-eq'|iex){$h}}

Test script:

filter f{$h,$t=$_-split'#',2
if($t){0..9|%{"$h$_$t"}|f}elseif($h-replace'=','-eq'|iex){$h}}

@(
    ,('1#3+45#=579','123+456=579')
    ,('#79+44#=1323','879+444=1323')
    ,('5#5+3#3=898','505+393=898 515+383=898 525+373=898 535+363=898 545+353=898 555+343=898 565+333=898 575+323=898 585+313=898 595+303=898')
    ,('#+#=2','0+2=2 1+1=2 2+0=2')
    ,('9+#6=55','9+46=55')
    ,('123+##=124','123+01=124')
    ,('#123651+#98#=1131632','1123651+7981=1131632')
    ,('##+##=2','00+02=2 01+01=2 02+00=2')
    ,('##+##=99','00+99=99 01+98=99 02+97=99 03+96=99 04+95=99 05+94=99 06+93=99 07+92=99 08+91=99 09+90=99 10+89=99 11+88=99 12+87=99 13+86=99 14+85=99 15+84=99 16+83=99 17+82=99 18+81=99 19+80=99 20+79=99 21+78=99 22+77=99 23+76=99 24+75=99 25+74=99 26+73=99 27+72=99 28+71=99 29+70=99 30+69=99 31+68=99 32+67=99 33+66=99 34+65=99 35+64=99 36+63=99 37+62=99 38+61=99 39+60=99 40+59=99 41+58=99 42+57=99 43+56=99 44+55=99 45+54=99 46+53=99 47+52=99 48+51=99 49+50=99 50+49=99 51+48=99 52+47=99 53+46=99 54+45=99 55+44=99 56+43=99 57+42=99 58+41=99 59+40=99 60+39=99 61+38=99 62+37=99 63+36=99 64+35=99 65+34=99 66+33=99 67+32=99 68+31=99 69+30=99 70+29=99 71+28=99 72+27=99 73+26=99 74+25=99 75+24=99 76+23=99 77+22=99 78+21=99 79+20=99 80+19=99 81+18=99 82+17=99 83+16=99 84+15=99 85+14=99 86+13=99 87+12=99 88+11=99 89+10=99 90+09=99 91+08=99 92+07=99 93+06=99 94+05=99 95+04=99 96+03=99 97+02=99 98+01=99 99+00=99')
) | % {
    $s,$e = $_
    $r = $s|f
    "$($e-eq$r): $r"
}

Powershell, 'Assume both term > 0' is mandatory, 110 bytes

filter f{$h,$t=$_-split'#',2
if($t){0..9|%{"$h$_$t"}|f}else{$a,$b,$c=$_-split'\D'
$_|?{+$a*+$b*!(+$a+$b-$c)}}}

mazzy

Posted 2018-08-30T14:36:34.223

Reputation: 4 832

0

PHP, 112 bytes

lame brute force solution

for(;$s=$argn;eval(strtr($s,['='=>'==','#'=>0]).'&&die($s);'))for($k=$n++;$k;$k=$k/10|0)$s[strpos($s,35)]=$k%10;

takes string as input, stops at first solution. Run as pipe with -nR or try it online.

Titus

Posted 2018-08-30T14:36:34.223

Reputation: 13 814