How many matchstick moves to change a number?

Using the matchstick numbers here: Count the Matchsticks

 _        _   _         _    _    _    _    _
| |   |   _|  _|  |_|  |_   |_     |  |_|  |_|
|_|   |  |_   _|    |   _|  |_|    |  |_|   _|


How many matchsticks must be moved and/or removed to change one number into another?

You will take two single digit numbers (0 to 9) as input (however works for you language), and return the number of moves needed to convert from the first input number to second input number, as though they were written in matchsticks. If no such operation is possible output some sort of 'Error Response' (any consistent output other a than a positive number or zero (if the output is a number, could be from -1 -> -Infinity) or you let the program crash):

Input: 9 0
Output: 1

Input: 8 9
Output: 1

Input: 0 1
Output: 4

Input: 7 8
Output: 'Error response'

Input: 8 7
Output: 4

Input: 2 5
Output: 2

Input: 2 3
Output: 1

Input: 5 6
Output: 'Error response'

Input: 4 4
Output: 0

Input: 6 7
Output: 4

Here is the full table of first and second inputs, and each cell is the output:

input 1 v/input 2 > 0 1 2 3 4 5 6 7 8 9
0 0 4 2 2 3 2 1 3 err 1
1 err 0 err err err err err err err err
2 err 4 0 1 3 2 err 3 err err
3 err 3 1 0 2 1 err 2 err err
4 err 2 err err 0 err err 2 err err
5 err 4 2 1 2 0 err 3 err err
6 1 4 2 2 3 1 0 4 err 1
7 err 1 err err err err err 0 err err
8 1 5 2 2 3 2 1 4 0 1
9 1 4 2 1 2 1 1 3 err 0
• code-gold competitions don't usually have to handle both checking for error conditions and calculating a result. It's better to have just one or the other. Feb 16 at 21:53
• @Noodle9 I mainly want to give an expected output when the operation is not possible, especially so as not to create ambiguous answers... I.e. going from 1 → 8 isn't possible, so it shouldn't give a positive integer response Feb 16 at 22:01
• I'd also note that the matrix could be considered as symmetrical without errors, so it adds something worthwhile to the problem to break that. Feb 17 at 4:01

Python 3, 1169995 89 bytes

Thanks to ovs for informing me about byte literals. 2 bytes saved by l4m2. 6 bytes saved by emanresuA.

r=b'w][:koR{'
g=lambda x,y:bin(r[x]&~r[y]).count('1')
lambda x,y:g(x,y)<g(y,x)or g(x,y)


Try it online!

Python 3.10+, 9793 87 bytes

Thanks to Kevin Cruijssen for this golf

lambda x,y:g(x,y)<g(y,x)or g(x,y)
r=b'w][:koR{'
g=lambda x,y:(r[x]&~r[y]).bit_count()

Attempt This Online!

• You can use a byte literal instead of the list: r=b'w\x12][:koR\x7f{'
– ovs
Feb 16 at 13:30
• r[x]^r[y]&r[x])=>r[x]&~r[y]
– l4m2
Feb 16 at 13:46
• bin(...).count('1') can be (...).bit_count() in Python 3.10+: try it online. Feb 16 at 13:48
• Both versions can save six bytes by using literal bytes instead of hex escapes (Try it online!) Feb 16 at 18:59

JavaScript, 989788 82 bytes

-6 bytes from tsh

f=

x=>y=>n(x=r[x])>n(y=r[y])||n(y&~x)
r=[2,91,40,9,81,5,4,27,0,1]
n=c=>c&&n(c>>1)+c%2

arrx=[...Array(11)];
fb=(a,b)=>f(a)(b)===true?'-':f(a)(b)
document.write('<table>'+arrx.map((_,i)=>'<tr>'+arrx.map((_,j)=>'<td>'+(i*j?fb(i-1,j-1):'<b>'+(i+j?i+j-1:'')+'</b>')+'</td>').join+'</tr>').join+'</table>')

Digit map 0,5,6,1,2,3,4

Maybe longer than Python cuz n and r

• Lowest cost map finder
– l4m2
Feb 16 at 14:49
• What does that do? Feb 16 at 23:00
• Why not x=>y=>n(X=r[x])>n(Y=r[y])||n(Y&~X)?
– tsh
Feb 17 at 8:26

05AB1E, 25 bytes

•Q¡ĀŠL›š»•₃вIèÂ±&b1öÂ@iθ


Input as a pair of integers; outputs the pair as error value (if this is not allowed, a trailing ë® can be added to output -1 instead).

Port of @l4m2's JavaScript answer, so make sure to upvote him/her as well!

Explanation:

                 #  e.g. input = [2,1]
•Q¡ĀŠL›š»•       # Push compressed integer 1867012004107141926
#  STACK: 1867012004107141926
₃в              # Convert it to base-95 as list
#  STACK: [2,91,40,9,81,5,4,27,0,1]
Iè            # 0-based index the input-pair into this list
#  STACK: [40,91]
Â           # Bifurcate it, short for Duplicate & Reverse copy
#  STACK: [40,91],[91,40]
±          # Bitwise-NOT the values in the copy
#  STACK: [40,91],[-92,-41]
&         # Bitwise-AND the values at the same positions together
#  STACK: [32,83]
b        # Convert each to a binary string
#  STACK: [100000,1010011]
1ö      # Convert both from base-1 to base-10 to sum its digits
#  STACK: [1,4]
Â     # Bifurcate it again
#  STACK: [1,4],[4,1]
# Pop the copy and push both integers separated to the stack
#  STACK: [1,4],4,1
@   # Check if the first >= the second
#  STACK: [1,4],1
i  # If this is truthy (1):
θ #  Pop and leave the last value of the pair
#   STACK: 4
#  (after which it is output implicitly as result)
# (implicit else)
#  (the implicit input is output implicitly as result)


See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •Q¡ĀŠL›š»• is 1867012004107141926 and •Q¡ĀŠL›š»•₃в is [2,91,40,9,81,5,4,27,0,1].

APL+WIN, 50 bytes

Prompts for first integer then second. index origin = 0

(((+/-/m)*.5)*2)++/</m←⌽(7⍴2)⊤⎕av⍳'wì][:koR{'[⎕,⎕]

(+/-/m)*.5 Takes square root of difference between matches to throw an error if negative.

• It can error or return negative number. Feb 16 at 22:55
• @AncientSwordRage Thanks for the clarification. I will see if I can benefit from it Feb 17 at 7:50

Charcoal, 45 bytes

Ｆ²⊞υ§⪪”)∧|XＣ¬πＸt？×”⁷ＮＵＭυΣ⭆ι⁻λ§§υ¬κμ⎇›⊟υΣυωＩ⊟υ


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

Ｆ²⊞υ§⪪”)∧|XＣ¬πＸt？×”⁷Ｎ


Input the two digits and extract their bit patterns for the seven segment display from the compressed string.

ＵＭυΣ⭆ι⁻λ§§υ¬κμ


Count how many segments are superfluous for each digit relative to the other. (Conveniently this still works even though I'm using string "arithmetic".)

⎇›⊟υΣυωＩ⊟υ


If the first digit has at least as many superfluous segments as the second then output that number.

• How does this handle 5→2 even though they have the same number of segments? Feb 16 at 21:16
• @AncientSwordRage Rather than counting the segments themselves it compares the segments used for 5 and 2, and says "there are two segments that 5 has that 2 doesn't use" and "there are two segments that 2 has that 5 doesn't use". If the second difference of used segments is greater then the operation is impossible otherwise the first difference of used segments is the desired result.
– Neil
Feb 16 at 21:42
• Makes more sense to me now! Feb 16 at 22:09

Husk, 42 bytes

?_1ṁ>0₂¹³>0Σ₂
¤z-!m(↑_7*2ḋ+3c)"];yfZ\\a|zt


Try it online!

This feels frustratingly long, principally because of my contorted way to construct the matrix of outputs (below), so can probably be golfed better.

We use a 7x10 matrix of 0s & 1s to represent the absence/presence of a matchstick at each of the 7 positions in each of 10 digits.
Husk doesn't have built-in compression for integers or arrays, but a 7-bit row can be conveniently encoded by the (8-bit) codepoint of one character, and converted using ḋc (binary digits of codepoints).
But the straightforward string representation of the rows is "w>|i]_d\177}", which includes characters not present in Husk's codepage. Only by subtracting 3 from each value do we arrive at a string - "t];yfZ\\a|z" in which all characters are present in Husk's 256-character codepage. We then move the zero row (t) to the end, to account for Husk's 1-based indexing. So now we've got ḋ+3c to decode.
But now when we try to access this as a matrix, the row for the digit 2 - corresponding to bits 0,1,1,1,1,1,0 fails, because the binary representation starts with a zero, and Husk drops the leading zero. Luckily it ends with a zero too, so we can work-around by doubling every row and taking the last 7 elements. So now we've got ↑_7*2ḋ+3c, which additionally needs parentheses now because it's too many functions to combine using any of Husk's multi-function combinators. So (↑_7*2ḋ+3c).
Frustratingly long.

After that, we just zip-subtract the relevant rows from each other: ¤z-!, check whether the sum is less than zero, and if it is, return -1: ?_1...>0Σ₂, otherwise return the number of subracted elements that are greater than one ṁ>0₂¹³.

Pyth, 41 Bytes

K"wD>nMk{Fo"Lsjb2M|<yGyHy.&G_hHg.*mC@KdQ


Takes something like [2, 3] as input, and prints True as error value.

Try it online!

Explanation

                                                Q=eval(input())
K"wD>nMk{Fo"                                   K="wD>nMk{Fo"
L                                  y=lambda b:
s                                  sum(
jb2                                base(b,2))
M                             g=lambda G,H:
yG                           y(G)
<                             <
yH                         y(H)
|                             or
y                        y(
G                      G
.&                       &
_hH                   ~H)
g               g(
.*              *
mC@Kd         [(lambda d:ord(K[d]))(i) for i in
Q        Q])
`