Hexadecimal and the Alphabet
Jelly, 18 bytes
b⁴µ:⁵©+¹%⁵ḅ⁵ß¹®S¤?
Try it online!
The binary, 18 byte version of the source code has the xxd dump
0000000: 62 b6 8c 3a b7 85 2b 8e 25 b7 a3 b7 95 8e 88 53 83 3f b..:..+.%......S.?
and works with this version of the Jelly interpreter.
How it works
b⁴µ:⁵©+¹%⁵ḅ⁵ß¹®S¤? Define the main link -- Left input: a (number)
b⁴ Convert from integer to base 16.
µ Start a new, monadic link.
:⁵ Divide all base 16 digits by 10.
© Save the result in a register.
+¹ Add the quotients to the base 16 digits.
%⁵ Take all resulting sums modulo 10.
ḅ⁵ Convert from base 10 to integer.
®S¤ Take the sum of the quotients from the list in the register.
? If the result is non-zero:
ß Recursively call the main link.
¹ Else, apply the identity function.
Ḍ
(decimal-to-integer) should have worked as a shorthand for ḅ⁵
, but the latest version of Jelly at the time of this post had a bug that prevented me from using it.
JavaScript ES6, 98 92 67 64 bytes
Saved 3 bytes thanks to @Downgoat, 3 more thanks to @user81655
Found a much, much shorter version, ditching the loop for recursion:
h=x=>(y=x.toString(16))>(r=y.replace(/\D/g,z=>'0x'+z-9))?h(+r):r
Probably the most interesting part of this program is the replace
function:
z=> // Implicit: z = one of "a", "b", "c", "d", "e", "f"
'0x'+z // Add '0x' to the beginning of z.
// If z == "a", this results in "0xa".
-9 // Subtract 9. JavaScript automatically coerces the string to a number,
// and because the prefix "0x" means "convert from hexadecimal",
// the "a" is converted to 10, which then becomes 1 because of the subtraction.
Test snippet
(taken from here)
h=x=>(y=x.toString(16))>(r=y.replace(/\D/g,z=>'0x'+z-9))?h(+r):r
<!-- Try the test suite below! --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");inputbox.value="234589";textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML+='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{var evalResult=eval(code);if(typeof evalResult=="function"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>
CJam, 21 19 bytes
r{siGb_{(9%)}%_@#}g
Test it here.
Explanation
A very rare case of negative modulo results being helpful. :)
r e# Read input.
{ e# While the condition on top of the stack is truthy...
s e# Convert to string. This is a no-op in the first iteration, but necessary
e# on subsequent iterations.
i e# Convert to integer.
Gb e# Get base-16 digits.
_{ e# Copy and map over the copy...
( e# Decrement.
9% e# Modulo 9. If the digit was originally in the range 0 to 9, it will remain
e# unchanged because -1 % 9 == -1. If the digit was in 10 to 15, it will become
e# 0 to 5, respectively.
) e# Increment. Undoes the decrement for unchanged digits and fixes the letter
e# digits because A corresponds to 1, not 0.
}%
_ e# Duplicate result.
@# e# Pull up original digits and try to find them in the array. This will be zero,
e# i.e. falsy, if they are equal and -1, i.e. truthy, if they are not.
}g