Eyeballing the binary values printed as ovals and sticks is not so easy...
To help with that, you must write a function (or a program) that prints numbers in custom binary representation.
So I want to take a number, say 3 (00000011) and output the bits in user-defined format, for example with space separated pairs:
00 00 00 11
or, say, in reversed order and with some decorators, e.g.:
11_00_00_00
Furthermore, there must be possibilty to show '0' and '1' as custom characters to distinguish them better, e.g.:
XX oo oo oo
So the challenge is to write the code which does that all whithin the following specification.
Specification
The function takes input like this: f(A, mask, zeros, ones)
Parameters:
A -- input number -- any (unsigned) integer in range 0-255.
mask -- a string parameter which defines the construction of the output.
zeros -- a string of the same length, defines 'zero' glyphs for each output slot.
ones -- a string of the same length, defines 'one' glyphs for each output slot.
Rules for the output construction:
Look at this image with example closely to understand how the output is generated:
So only the single digits in the mask are parsed and replaced by corresponding bits of A, other characters are left as is. Further, if the value of the taken bit is 1 then it shows up in the final output as "X" and if it is 0 then it shows up as "o". In the above example all four taken bits are "1" so we see "X" in all slots.
If the input number was 128, then, logically, the output would be X foo bar ooo. Characters in parameters "zeros" and "ones": any printable ASCII chars, assume they are always char-aligned with the mask.
Notes:
- Bits are 0-indexed: 0th bit is the MSB.
- Assume that digits 8,9 are not allowed in the mask string.
- Input Strings include any printable ASCII chars.
- 'Zeros' and 'ones' are char-aligned with the mask.
- For special characters/modifiers in your language: we can assume they will not appear in the input string.
For the clarity, see more examples.
Input -> Output examples
Output all 8 bits in common order with a space delimiter, in common oval-and-stick notation:
mask = "0123 4567"
zeros = "0000 0000"
ones = "1111 1111"
A=1 -> 0000 0001
Output in reversed order, in dash-and-glyph notation:
mask = "| 7654 3210 |"
zeros= " ---- ---- "
ones = " ssss ssss "
A=1 -> | s--- ---- |
A=3 -> | ss-- ---- |
A=128-> | ---- ---s |
Diverse notations in one output, e.g. for packed data:
mask = "0 | 123 4567"
zeros= " --- ----"
ones = "X kkk ssss"
A= 15 -> | --- ssss
A= 16 -> | --k ----
A= 32 -> | -k- ----
A= 128 -> X | --- ----
A= 255 -> X | kkk ssss
Repeating patterns:
mask = "| 7 66 555 4444 |"
zeros= " . .. ... .... "
ones = " 0 00 000 0000 "
A= 0 -> | . .. ... .... |
A= 1 -> | 0 .. ... .... |
A= 2 -> | . 00 ... .... |
A= 3 -> | 0 00 ... .... |
A= 4 -> | . .. 000 .... |
Update
The rules have been slightly simplified - the program must print one number only (not array/list of numbers as it was proposed initially).
6 Answers 6
Ruby, 48 bytes
->a,f,*b{f.gsub(/\d/){b[a[55-$&.ord]][$`.size]}}
The zeroes and ones parameters are treated as an array (*b) and with the zeroes parameter is stored in b[0] and the ones parameter stored in b[1].
The mask parameter f has each digit (/\d/) substituted with a character from the appropriate array. The special variable $`, which holds the text leading up to the current match, is (ab)used here to keep track of position.
Ruby's bit indexing calls 0 the least-significant bit, but the challenge calls 0 the most significant bit. ASCII subtraction from 55 (the '7' character) yields a usable Ruby bit index.
JavaScript (ES6), 57 bytes
(A,M,O,I)=>M.replace(/[\d]/g,(d,i)=>(A>>7-d)%2?I[i]:O[i])
f=
(A,M,O,I)=>M.replace(/[\d]/g,(d,i)=>(A>>7-d)%2?I[i]:O[i])
console.log( f(1, "0123 4567", "0000 0000", "1111 1111") )
console.log( f(3, "| 7654 3210 |", " ---- ---- ", " ssss ssss ") )
console.log( f(4, "| 7 66 555 4444 |", " . .. ... .... ", " 0 00 000 0000 ") )
Perl 6, 60 bytes
->\a,$_,\o,\z{S:g|\d|{substr (z,o)[a+>(7-$/)%2],$/.from,1}|}
Python, 97 bytes
lambda A,M,Z,O:"".join([[Z,O][1&(A>>7-int(d))][i] if d.isdigit() else d for i,d in enumerate(M)])
Mathematica, 131 bytes
""<>Table[(f/@{##2})[[x[[i]],i]],{i,Length[x=(f=Characters)@#2/.Table[ToString@i->2+Floor[#/2^(7-i)]~Mod~2,{i,0,7}]/._String->1]}]&
-
\$\begingroup\$
Length[x]can beLength@xand{#2,#3,#4}can be{##2}. \$\endgroup\$CalculatorFeline– CalculatorFeline2017年05月27日 16:16:58 +00:00Commented May 27, 2017 at 16:16 -
\$\begingroup\$ Also,
StringJoin@@can just beStringJoin@and#1is just#\$\endgroup\$CalculatorFeline– CalculatorFeline2017年05月27日 16:45:13 +00:00Commented May 27, 2017 at 16:45 -
\$\begingroup\$ I've simplified the rules slightly, see update. \$\endgroup\$Mikhail V– Mikhail V2017年05月27日 22:35:50 +00:00Commented May 27, 2017 at 22:35
q/kdb+, (削除) 86 (削除ここまで) 64 bytes
Solution:
f:{[A;M;Z;O]@[M;m;:;((-8#0b vs A)"I"$'M m)(Z;O)'m:(&)M in .Q.n]}
Examples:
q)f[1;"0123 4567";"0000 0000";"1111 1111"]
"0000 0001"
q)f[1;"| 7654 3210 |";" ---- ---- ";" ssss ssss "]
"| s--- ---- |"
q)f[15;"0 | 123 4567";" --- ----";"X kkk ssss"]
" | --- ssss"
q)f [0;"| 7 66 555 4444 |";" . .. ... .... ";" 0 00 000 0000 "]
"| . .. ... .... |"
Explanation:
Pull out indices where input mask M is a numeral, call it m this is where we will be modifying the input mask. Take the numerals out of the string, cast to integers and then index into our 8-bit array to get the correct ordering.
Use this 8-bit array to index into either O (if 1 is set) or Z (if 0 is set), and then index into these lists at the indices given by m.
Finally apply (:) this new list to the original mask at indices m.
{[A;M;Z;O] } / lambda function with 4 parameters
@[ ; ; ; ] / apply, applies 3rd parameter to 1st parameter at indexes from parameter 2 with parameter 4 :)
(-8#0b vs A) / convert input number to binary (64 bit), take the last 8 items
m:(&)M in .Q.n / returns indices where mask is in "0123..789", stores in variable m
"I"$'M m / index into mask at indices m, then cast these numbers to an integer array
( ) / we then index into our 8 bits a these offsets to get the output order
(Z;O) / 2-item list of the zeroes and ones mask
' / take each item on the left and right and apply them to (Z;O) (ie index in at 0 / 1 and then 123..67)
M m : / apply *this* list to M at each index given by m
Notes:
Could shave off a further 14 bytes if we were allowed to give the arguments in the form:
[A;M;(Z;O)]
as q allows for up to 3 arguments to be given to a function without being explicitly named (they are x, y and z respectively):
f:{@[y;m;:;((-8#0b vs x)"I"$'y m)z'm:(&)y in .Q.n]}
Adoes, since it is the same in all of the test cases \$\endgroup\$