Splitting up ASCII

Given the 95 printable characters in ASCII plus newline, break it apart into two equal, 48 character groups (hereafter called group A and group B). Create a one-to-one mapping of your choice (you have total discretion) between the two groups. In other words, A might map to a, and vice versa, but A might also map to > and vice versa, if that's what you need for your program.

Once you've broken up ASCII into two groups, write two programs and/or functions, using only the characters in each group, respectively. In other words, write one program / function that only uses the characters in group A, and another program / function that only uses the characters in group B.

These programs must be able to receive one character as input. The program written with the characters in Group A should output / return the same character if the input was a group A character, and the mapped group A character if it received a group B character; the Group A program should always output a group A character. Similarly, the Group B program should output the same character if it's a group B character, and the mapped group B character if the input is a group A character.

That might not be so clear, so here's an example. If you assume that all capital letters are in group A, and all lowercase letters are in group B, and you've chosen that your one-to-one mapping for these letters are from one to the other, then: then here are some sample input/outputs:

Program A:

Input    Output
A        A
D        D
a        A
q        Q


Program B:

Input    Output
A        a
D        d
a        a
q        q


Other rules:

• The two programs do not need to be in the same language.
• They don't need to be both programs or both functions; one could be a program, the other a function, that is fine.
• They don't need to work the same way, be of similar length, anything like that; they simply must meet the the other rules above.
• Yes, only one of your programs may use newlines, and only one can use spaces (this could be the same, or a different program).
• You do not need to use all 48 characters in each program.

Standard loopholes are banned, as normal. All programs must be self contained, no files containing the mapping you choose.

Scoring criteria: . Specifically, the sum of the bytes of the text of the two programs.

Language - # bytes + Language - # bytes = # bytes

An unambiguous description of your mapping. If it's complicated, use a chart like this:

ABCDEFGHIJKLMNOPQRSTUVWXYZ (etc.)
zyxwvutsrpqonmlkjihgfedcba (etc.)


Or, you can just explain it (first 48 maps to last 48 in sequence), followed by your answer as normal.

• I'm going to try using the same language for both. :) Sep 5, 2015 at 0:32
• I honestly think you should change the rules, restricting it to "both programs have to be the same language." Otherwise it's probably WAY too easy/broad. Sep 5, 2015 at 1:29
• I actually wonder if this is possible in Self-modifying Brainfuck. You just have to have one program using + and >, and the other using - and <. Then you have to try to generate the missing operators, such as a , or . in the program that cannot use them. Sep 5, 2015 at 1:37
• @Ruslan Try using SQL. It's not case sensitive and uses keywords (begin and end) for code blocks. If you use SQL Server 2014, you can use DBCC Bulk Insert for one program, and a procedure for the other one. In the first one, you can avoid using parentheses. Then use a select case when statement for both programs. Also, I believe it's possible in Java by using the \u trick for a program replacing every character with unicode values and using a function for the other that doesn't use the letter u, a backslash, or numbers. Sep 5, 2015 at 18:07
• Hardest. Challenge. Ever. Sep 5, 2015 at 18:19

CJam - 464426 11 bytes + GolfScript - 14212511593684740 36 bytes = 47 bytes

Thanks to Peter Taylor for golfing 6 bytes off the GolfScript program (and paving the way for many more.)

Thanks to Dennis for golfing 15 bytes off the CJam program and 4 bytes off the GolfScript program.

Group A: all characters with even character code.
Group B: all characters with odd character code, plus newline.

I'm using the obvious mapping between the two, i.e. pair those characters which only differ in the least significant bit, as well as ~ and \n. Here is the complete map (the columns):

 "$&(*,.02468:<>@BDFHJLNPRTVXZ\^bdfhjlnprtvxz|~ !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\n  Program A (CJam, test it here): lX~f&"~"|X<  Program B (GolfScript, test it here): {1}'{-'{)}%'115)%11-[9)ie'9/{))}%++%  Explanation Program A (Outdated, will update tomorrow.) This program should turn odd character codes into even ones, i.e. set the least significant bit to 0. The obvious way to do this is bitwise AND with 126 (or 254 etc), but it's shorter to set it to 1 (via bitwise OR with 1) instead and then decrement the result. Finally, we need to fix newlines manually: "r"( e# Push the string "r" and pull out the character. (~ e# Decrement to q and eval to read input. ( e# Pull out the character from the input string. 2(|( e# (input OR (2-1))-1 == input AND 126 0$    e# Copy the result.
N&    e# Set intersection with a string containing a newline.
"~"   e# Push "~".
"@@"( e# Push "@@" and pull out one @.
(|    e# Decrement to ?, set union with the other string to give "@?".
~     e# Eval to select either the computed character or "~" if it was a newline.


Program B

(Outdated, will update tomorrow.)

This program can simply set the least significant bit to 1 via bitwise OR with 1 now. But it has to check for both \v (character code 0x0B) and <DEL> (character code 0xFF) manually and set them to ~ instead. In GolfScript I didn't have access to eval, but instead you can add a string to a block (which then becomes part of the code in that block), which I could map onto the input with %:

{1}    # Push this block without executing it.
'{--'  # Push this string.
{)}%   # Increment each character to get '|..'.
')1)7?=[11=+9)?ie'
# Push another string...
7/     # Split it into chunks of 7: [')1)7?=[' '11=+9)?' 'ie']
{))}%  # For each chunk, split off the last character and increment it.
+      # Add the array to the string, flattening the array: '|..)1)7?=\11=+9)@if'
+      # Add it to the block: {1|..)1)7?=\11=+9)@if}
%      # Map the block onto the input, i.e. apply it to the single character.


And as for the generated code in the block:

1|..   # Bitwise OR with 1, make two copies.
)1)7?= # Check if the result is one less than 2^7 == 128 (i.e. if it's <DEL>).
\11=   # Check with the other copy if it's equal to 11 (i.e. if it's \v).
+      # Add them to get something truthy either way.
9)     # Push a 10 (i.e. \n).
@      # Pull up the original value.
if     # Select the correct result.


Java - 1088 bytes + Java - 1144 bytes = 2232 bytes

Thanks to @durron597 for helping to golf 1090 bytes from the first program.

Proof that it is possible to do in one language (and a non-esolang at that).

Use the unicode trick to convert the first one to all unicode characters. The second one uses reflection to get access to System.out in order to print to std. out. It couldn't use the u because that was used in the first program. I know this can be golfed more, but I wanted to post a valid solution first.

The groups are fairly arbitrarily mapped, but basically, the first one required only u,\, and the hexadecimal digits (in any case).

The groups:

!#7$&89'0123456>fB@UXZ\^AKCDEGH_JLNOkQRxzVWYu~\n "%()*+,-./:;<=?FIMPST[]abcdeghijlmnopqrstvwy{|}  First program: \u0076\u006F\u0069\u0064 k\u0028\u0069\u006E\u0074 x\u0029\u007B\u0069\u006E\u0074\u005B\u005Du\u003D\u007B33\u002C33\u002C35\u002C35\u002C36\u002C55\u002C38\u002C39\u002C36\u002C38\u002C56\u002C57\u002C39\u002C48\u002C49\u002C50\u002C48\u002C49\u002C50\u002C51\u002C52\u002C53\u002C54\u002C55\u002C56\u002C57\u002C51\u002C52\u002C53\u002C54\u002C62\u002C62\u002C64\u002C65\u002C66\u002C67\u002C68\u002C69\u002C102\u002C71\u002C72\u002C66\u002C74\u002C75\u002C76\u002C64\u002C78\u002C79\u002C85\u002C81\u002C82\u002C88\u002C90\u002C85\u002C86\u002C87\u002C88\u002C89\u002C90\u002C92\u002C92\u002C94\u002C94\u002C95\u002C96\u002C65\u002C75\u002C67\u002C68\u002C69\u002C102\u002C71\u002C72\u002C95\u002C74\u002C107\u002C76\u002C96\u002C78\u002C79\u002C107\u002C81\u002C82\u002C120\u002C122\u002C117\u002C86\u002C87\u002C120\u002C89\u002C122\u002C117\u002C126\u002C10\u002C126\u007D\u003B\u0053\u0079\u0073\u0074\u0065\u006D\u002E\u006Fu\u0074\u002E\u0070\u0072\u0069\u006E\u0074\u0028x>10\u003F\u0028\u0063\u0068\u0061\u0072\u0029u\u005Bx\u002D32\u005D\u003A'\u005C\u006E'\u0029\u003B\u007D  Equivalent to void k(int x){int[]u={33,33,35,35,36,55,38,39,36,38,56,57,39,48,49,50,48,49,50,51,52,53,54,55,56,57,51,52,53,54,62,62,64,65,66,67,68,69,102,71,72,66,74,75,76,64,78,79,85,81,82,88,90,85,86,87,88,89,90,92,92,94,94,95,96,65,75,67,68,69,102,71,72,95,74,107,76,96,78,79,107,81,82,120,122,117,86,87,120,89,122,117,126,10,126};System.out.print(x>10?(char)u[x-32]:'\n');}  Second program: void n(int r)throws Throwable{int p=(int)Math.PI;int q=p/p;int t=p*p+q;int w=q+q;int[]g={t*p+w,t*p+w,t*p+q+p,t*p+q+p,t*(q+p),t*p+t-p,t*(q+p)+q,t*(q+p)+q+p,t*(q+p),t*(q+p)+q,t*(q+p)+w,t*(q+p)+p,t*(q+p)+q+p,t*(q+p)+p+w,t*(q+p)+p+p,t*(q+p)+t-p,t*(q+p)+p+w,t*(q+p)+p+p,t*(q+p)+t-p,t*(p+w)+t-w,t*(p+w)+t-q,t*(p+p),t*(p+p)+q,t*p+t-p,t*(q+p)+w,t*(q+p)+p,t*(p+w)+t-w,t*(p+w)+t-q,t*(p+p),t*(p+p)+q,t*(p+p)+p,t*(p+p)+p,t*(t-p)+t-p,t*(t-q)+t-p,t*(t-p)+p,t*(t-q)+t-q,t*t,t*t+q,t*(t-p),t*t+p,t*t+q+p,t*(t-p)+p,t*t+p+p,t*(t-q)+t-w,t*t+t-w,t*(t-p)+t-p,t*(t+q),t*(t+q)+q,t*(t-w),t*(t+q)+p,t*(t+q)+q+p,t*(t-w)+p,t*(t-w)+q+p,t*(t-w),t*(t+q)+t-w,t*(t+q)+t-q,t*(t-w)+p,t*(t+w)+q,t*(t-w)+q+p,t*(t-q)+q,t*(t-q)+q,t*(t-q)+p,t*(t-q)+p,t*t+p+w,t*t+t-q,t*(t-q)+t-p,t*(t-q)+t-w,t*(t-q)+t-q,t*t,t*t+q,t*(t-p),t*t+p,t*t+q+p,t*t+p+w,t*t+p+p,t*(t+q)+w,t*t+t-w,t*t+t-q,t*(t+q),t*(t+q)+q,t*(t+q)+w,t*(t+q)+p,t*(t+q)+q+p,t*(t+q)+p+w,t*(t+q)+p+p,t*(t+w)+p,t*(t+q)+t-w,t*(t+q)+t-q,t*(t+q)+p+w,t*(t+w)+q,t*(t+q)+p+p,t*(t+w)+p,t*(t+w)+q+p,t*(t+w)+p+w,t*(t+w)+q+p};java.io.PrintStream o=(java.io.PrintStream)System.class.getFields()[p/p].get(p);o.print((r<=t)?"}":(char)g[r-t*p-w]);}  Try them out here: https://ideone.com/Q3gqmQ • There are no characters you can pull out of the first program that don't need to be unicode escaped? Can't you pull out some of the numbers? What if you did void x(int z), those are characters in the first charset too Sep 6, 2015 at 2:56 • I'm sure it's possible. I could rename some variables and replace all spaces with new lines or tabs. I'll do that when I get home. I just wanted to prove a single language solution first. Sep 6, 2015 at 3:00 CJam - 11 bytes + CJam - 25 bytes = 36 bytes Characters are selected in alternating groups of 16:  !"#$%&'()*+,-./@ABCDEFGHIJKLMNOabcdefghijklmno
0123456789:;<=>?PQRSTUVWXYZ[\]^_pqrstuvwxyz{|}~\n


It's cool that a few of the mappings can be obtained with the shift key :)

Program A:

lL,H-f&'o+c


Try it online

Program B:

q_S<\_0=16|_127<\S0=42^??


Try it online

Explanation:

Program A:

l      read a line from the input, this is a 1-character string
or the empty string if the input was a newline
L,     get the length of an empty string/array (0)
H-     subtract 17, obtaining -17 (~16)
f&     bitwise-"and" each character (based on the ASCII code) with -17
'o+    append the 'o' character
c      convert to (first) character
the result is the "and"-ed character, or 'o' for newline


Program B:

q_       read the whole input and duplicate it
S<\      compare with " " and move the result before the input
_0=      duplicate the input again, and get the first (only) character
16|      bitwise-"or" with 16 (based on the ASCII code)
_127<    duplicate and compare (its ASCII code) with 127
\        move the result before the "or"-ed character
S0=      get the space character (first character of the space string)
42^      xor with 42, obtaining a newline character
stack: (input<" ") (input) ("or"-ed char<127) ("or"-ed char) (newline)
?        if the "or"-ed character is less than 127, use the "or"-ed character
else use the newline character
?        if the input was smaller than space (i.e. it was a newline),
use the input, else use the character from the previous step

• Nice! Glad to see that "even/odd" isn't the only answer. Sep 8, 2015 at 18:15
• Still a 1 bit toggle... Impressive sizes! 2nd program w/input of 'o' doesn't seem to output the \n... bug in program or online cjam? Sep 9, 2015 at 4:32
• @BrianTuck it does output a newline (not a literal \n), it's just not easy to see without inspecting the html. You can append an i at the end of the program to see the ASCII code instead (or ci to also deal with a newline input, since it outputs a newline string rather than a character in that case) Sep 9, 2015 at 7:07
• Oh, or you/I could change _0= to 0=_ so that it always outputs a character Sep 9, 2015 at 7:20

FIXED! Pyth - 23 bytes + Pyth - 30 bytes = 53 bytes

oops Fixing error --- please be patient

same ASCII split as Martin's:

1: "\$&(*,.02468:<>@BDFHJLNPRTVXZ\^bdfhjlnprtvxz|~
2:!#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\n


Prog#1: Test Online

.xhft<zT.Dr\¡b:Z140 2\~


Prog#2: Test Online

C?%KCwy1K?qy5Ky5?qy+1y31Ky5+1K