93
\$\begingroup\$

Super simple challenge today, or is it?

I feel like we've heard a fair bit about double speak recently, well let's define it in a codable way...

Double speak is when each and every character in a string of text is immediately repeated. For example:

"DDoouubbllee  ssppeeaakk!!"

The Rules

  • Write code which accepts one argument, a string.
  • It will modify this string, duplicating every character.
  • Then it will return the double speak version of the string.
  • It's code golf, try to achieve this in the smallest number of bytes.
  • Please include a link to an online interpreter for your code.
  • Input strings will only contain characters in the printable ASCII range. Reference: http://www.asciitable.com/mobile/

Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

var QUESTION_ID=188988;
var OVERRIDE_USER=53748;
var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;function answersUrl(d){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+d+"&pagesize=100&order=asc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(d,e){return"https://api.stackexchange.com/2.2/answers/"+e.join(";")+"/comments?page="+d+"&pagesize=100&order=asc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(d){answers.push.apply(answers,d.items),answers_hash=[],answer_ids=[],d.items.forEach(function(e){e.comments=[];var f=+e.share_link.match(/\d+/);answer_ids.push(f),answers_hash[f]=e}),d.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(d){d.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),d.has_more?getComments():more_answers?getAnswers():process()}})}getAnswers();var SCORE_REG=function(){var d=String.raw`h\d`,e=String.raw`\-?\d+\.?\d*`,f=String.raw`[^\n<>]*`,g=String.raw`<s>${f}</s>|<strike>${f}</strike>|<del>${f}</del>`,h=String.raw`[^\n\d<>]*`,j=String.raw`<[^\n<>]+>`;return new RegExp(String.raw`<${d}>`+String.raw`\s*([^\n,]*[^\s,]),.*?`+String.raw`(${e})`+String.raw`(?=`+String.raw`${h}`+String.raw`(?:(?:${g}|${j})${h})*`+String.raw`</${d}>`+String.raw`)`)}(),OVERRIDE_REG=/^Override\s*header:\s*/i;function getAuthorName(d){return d.owner.display_name}function process(){var d=[];answers.forEach(function(n){var o=n.body;n.comments.forEach(function(q){OVERRIDE_REG.test(q.body)&&(o="<h1>"+q.body.replace(OVERRIDE_REG,"")+"</h1>")});var p=o.match(SCORE_REG);p&&d.push({user:getAuthorName(n),size:+p[2],language:p[1],link:n.share_link})}),d.sort(function(n,o){var p=n.size,q=o.size;return p-q});var e={},f=1,g=null,h=1;d.forEach(function(n){n.size!=g&&(h=f),g=n.size,++f;var o=jQuery("#answer-template").html();o=o.replace("{{PLACE}}",h+".").replace("{{NAME}}",n.user).replace("{{LANGUAGE}}",n.language).replace("{{SIZE}}",n.size).replace("{{LINK}}",n.link),o=jQuery(o),jQuery("#answers").append(o);var p=n.language;p=jQuery("<i>"+n.language+"</i>").text().toLowerCase(),e[p]=e[p]||{lang:n.language,user:n.user,size:n.size,link:n.link,uniq:p}});var j=[];for(var k in e)e.hasOwnProperty(k)&&j.push(e[k]);j.sort(function(n,o){return n.uniq>o.uniq?1:n.uniq<o.uniq?-1:0});for(var l=0;l<j.length;++l){var m=jQuery("#language-template").html(),k=j[l];m=m.replace("{{LANGUAGE}}",k.lang).replace("{{NAME}}",k.user).replace("{{SIZE}}",k.size).replace("{{LINK}}",k.link),m=jQuery(m),jQuery("#languages").append(m)}}
body{text-align:left!important}#answer-list{padding:10px;float:left}#language-list{padding:10px;float:left}table thead{font-weight:700}table td{padding:5px}
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn.sstatic.net/Sites/codegolf/primary.css?v=f52df912b654"> <div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td><a href="{{LINK}}">{{SIZE}}</a></td></tr></tbody> </table> 

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, [Other information] N bytes

where N is the size of your submission. Other information may include flags set and if you've improved your score (usually a struck out number like <s>M</s>). N should be the right-most number in this heading, and everything before the first , is the name of the language you've used. The language name and the word bytes may be links.

For example:

# [><>](http://esolangs.org/wiki/Fish), <s>162</s> 121 [bytes](https://esolangs.org/wiki/Fish#Instructions)
\$\endgroup\$
9
  • 5
    \$\begingroup\$ It will modify this string. Are you intentionally requiring pass-by-reference and modify in-place? And then return a copy or reference to that modified string? If so, languages like asm or C would need to accept an explicit-length string (pointer + length) where the length is either the current string length (with the buffer being twice that size), or it's the total size and you need to duplicate the low half. Thus you need to start from the end and work backwards, or allocate scratch space and then copy back. But there are answers in C and 8086 asm that totally violate all that. \$\endgroup\$ Commented Aug 3, 2019 at 1:49
  • 6
    \$\begingroup\$ @PeterCordes I do not care if it modifies the same object or builds a new one. \$\endgroup\$
    – AJFaraday
    Commented Aug 3, 2019 at 5:08
  • 4
    \$\begingroup\$ I'd suggest wording it as "modify (or produce a modified copy) of the string" to explicitly allow answers that do or don't modify in-place. Simplifying the wording to "return a string that's twice as long, with each character repeated" would be nice but then it's not clear if void foo(char *c, size_t len) is legal that takes one input/output buffer and a length, and doesn't have any return value, just a side-effect on the object it has a pointer to. \$\endgroup\$ Commented Aug 3, 2019 at 5:16
  • 1
    \$\begingroup\$ @cschultz2048 it says the string will only contain printable ascii characters, so that implies that they’ll always be populated. I’d expect that any code for this challenge would leave an empty string empty... anyway, I don’t think it’s a test case that I’d use for this. \$\endgroup\$
    – AJFaraday
    Commented Aug 6, 2019 at 22:36
  • \$\begingroup\$ Does this answer your question? Stretching Words Because when you make the two operands in any submission to that challenge equal, programs will obey the behavior described in this challenge. An example of this behavior is here. \$\endgroup\$
    – user85052
    Commented Jan 2, 2020 at 12:29

254 Answers 254

1 2 3
4
5
9
3
\$\begingroup\$

Keg, 11 7 6 4 3 bytes

(⑩,

Explanation

(   # Repeat length of stack times:
 ⑩  # Print without popping the top of the stack
  , # Print with popping

Try It Online!

\$\endgroup\$
7
  • \$\begingroup\$ I'm impressed! Could not have golfed it that much! About TIO for Keg: how would I go around doing that... I know that it is to be done via the chat room, but I don't know if a direct request from someone who has never had any involvement in the room would be perceived as rude. \$\endgroup\$
    – lyxal
    Commented Jul 31, 2019 at 10:37
  • \$\begingroup\$ Also, how would implicit input for Keg sound? \$\endgroup\$
    – lyxal
    Commented Jul 31, 2019 at 10:38
  • 3
    \$\begingroup\$ @Jono2906 That definitely wouldn't be rude! Leaving a ping to Dennis in talk.tryitonline.net with a link to the interpreter should be enough to get Keg on tio :) \$\endgroup\$
    – Mr. Xcoder
    Commented Jul 31, 2019 at 12:14
  • \$\begingroup\$ @A__ Try it online! \$\endgroup\$
    – lyxal
    Commented Aug 9, 2019 at 23:04
  • 2
    \$\begingroup\$ This doesn't output anything now? \$\endgroup\$
    – EdgyNerd
    Commented Nov 3, 2019 at 15:48
3
\$\begingroup\$

QBasic, 58 bytes

LINE INPUT s$
FOR i=1TO LEN(s$)*2
?MID$(s$,i/2+.1,1);
NEXT

Explanation

LINE INPUT reads all input characters until a newline into s$. We loop i from 1 up to twice the length of the string and output the i/2th character (rounded up) at each iteration. There's a slight hitch, in that QBasic rounds numbers with a fractional part of .5 up sometimes and down other times; adding a small amount like .1 is sufficient to round the halves up, while the whole numbers still get rounded back down.

\$\endgroup\$
3
\$\begingroup\$

Acc!!, 42 bytes

N
Count i while _/32 {
Write _
Write _
N
}

Try it online!

Reads one character at a time into the accumulator and outputs the accumulator twice for each character. Loops until it encounters something with an ASCII code less than 32 (newline or EOF).

\$\endgroup\$
3
\$\begingroup\$

Burlesque, 2 bytes

)J

Try it online!

) # Map (implicitly explode and apply to each character then concatenate)
J # Duplicate
\$\endgroup\$
3
\$\begingroup\$

Fortran (GFortran), 71 65 bytes

character(99)a
read*,a
print*,(a(i:i),a(i:i),i=1,len_trim(a))
end

Try it online!

Saved 6 bytes thanks to @roblogic pointing out that if the input is quoted it can be read as list-directed.

If we don't care about extra whitespace:

Fortran (GFortran), 56 bytes

character(99)a
read*,a
print*,(a(i:i),a(i:i),i=1,99)
end

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Nice, I tried to use "proper" syntax for 100 bytes. codegolf.stackexchange.com/a/189152/15940 \$\endgroup\$
    – roblogic
    Commented Jan 19, 2020 at 9:30
  • 1
    \$\begingroup\$ @roblogic I saw, that's what inspired me to beat it. To me, there's nothing wrong with implicit loops in very rare situations (Array assignment and printing), but in golf, anything goes. \$\endgroup\$ Commented Jan 19, 2020 at 10:10
  • \$\begingroup\$ the 56-byte solution will work correctly if you assume the input string is quoted. example \$\endgroup\$
    – roblogic
    Commented Jan 19, 2020 at 10:34
  • 1
    \$\begingroup\$ @roblogic Still prints out excess whitespace, but saves bytes on the main one. \$\endgroup\$ Commented Jan 19, 2020 at 10:56
3
\$\begingroup\$

Pip, 17 16 13 11 bytes

Fi,#aL2Oa@i

Try it online!

\$\endgroup\$
0
3
\$\begingroup\$

Brainetry, 85 bytes

Golfed version inspired in the program that comes after:

a b c d e f
a b c d e f g h
a b c d e f g
a b c d e f g
a b c d e f
a b c d e f g h i

To try this online, head over to this link, copy&paste the code in the btry/replit.btry file and hit the green "Run" button.

Golfed from this program:

This is almost a cat program.
This is a double speak Brainetry cat program:
For every single character of input gotten
I am supposed to output two characters.
Doing this in Brainetry is easy.
Can I get a more difficult challenge, please ?
\$\endgroup\$
3
\$\begingroup\$

MAWP, 8 bytes

|0~[!;;]

Clones each character, pops from stack twice.

Try it!

\$\endgroup\$
0
3
\$\begingroup\$

Python 3, 36 35 bytes

print(''.join(x*2for x in input()))

Try it online!

Edit 1: Saved a byte

\$\endgroup\$
2
  • 3
    \$\begingroup\$ I think you can save one byte removing the space in x*2 for. \$\endgroup\$ Commented Sep 18, 2020 at 15:24
  • \$\begingroup\$ @DomHastings Brilliant. Did the change. Thanks! \$\endgroup\$ Commented Jan 15, 2021 at 21:42
3
\$\begingroup\$

Scala, 21 bytes

_./:("")(_+"".+(_)*2)

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ You might want to flatMap \$\endgroup\$
    – user
    Commented Jan 18, 2021 at 15:35
  • \$\begingroup\$ @user here is already an answer using flatMap and when refactored into a lambda expression I think it has 22 bytes. \$\endgroup\$ Commented Jan 18, 2021 at 15:44
  • 1
    \$\begingroup\$ Oops, I didn't see that. I think you can still use flatMap, in fact you can make it 20 bytes that way. It's okay if you don't want to use it, though \$\endgroup\$
    – user
    Commented Jan 18, 2021 at 15:47
3
\$\begingroup\$

naz, 34 32 bytes

2x1v1x1f0a0x1x2f1r3x1v1e2o2f0x2f

Works for any null-terminated input string.

Try it online!

Explanation (with 0x instructions removed)

2x1v             # Set variable 1 equal to 0
1x1f0a           # Function 1
                 # Add 0 to the register
1x2f1r3x1v1e2o2f # Function 2
                 # Read a byte of input and goto function 1 if it equals variable 1
                 # Otherwise, output twice and call function 2
2f               # Call function 2
\$\endgroup\$
3
\$\begingroup\$

Python 3, 43 bytes

def d(s,o=""):
	for c in s:o+=c+c
	return o

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 32 bytes \$\endgroup\$
    – lyxal
    Commented Feb 15, 2021 at 2:14
  • \$\begingroup\$ FYI there's already a few Python 3 solutions. (although we don't prohibit posting your own attempts) codegolf.stackexchange.com/search?q=inquestion%3A188988+Python (I think there's also the graduation userscript that shows a leader board under every questions, but I don't use it myself) cc @Lyxal \$\endgroup\$
    – user202729
    Commented Feb 15, 2021 at 10:12
3
\$\begingroup\$

Labyrinth, 9 8 bytes

 ,
.:@
:

Try it online!

Wins over Jonathan Allan's answer.

How it works

,    Start at the first meaningful instruction; push a char from stdin
:    Duplicate; on EOF, top is -1 so turn left and exit (@)
     otherwise, top is positive (printable ASCII) so turn right
.:.  Pop-print as char, dup, pop-print as char. Top is still the input char
:    Duplicate; turn to (,) since top is nonzero
,    This is a dead end so it runs again from the start, until EOF
\$\endgroup\$
3
\$\begingroup\$

Taxi, 390 342 335 bytes

Go to Post Office:w 1 l 1 r 1 l.Pickup a passenger going to Chop Suey.[A]Go to Chop Suey:n 1 r 1 l 4 r 1 l.Switch to plan B i.Pickup a passenger going to Cyclone.Go to Zoom Zoom:n 1 l 3 r.Go to Cyclone:w.[C]Pickup a passenger going to Post Office.Switch to plan B i.Switch to plan C.[B]Go to Post Office:s 1 l 2 r 1 l.Switch to plan A.

Try it online!

Explanation/Ungolfed

    [Take input string]
Go to Post Office: west 1st left, 1st right, 1st left.
Pickup a passenger going to Chop Suey.

[loop]
    [If string as a passenger, split it]
Go to Chop Suey: north 1st right, 1st left, 4th right, 1st left.
    [At the end of the string, end the program]
Switch to plan end_loop if noone is waiting.
        [any character after end_loop is fine]
    [Duplicate first character left]
Pickup a passenger going to Cyclone.
Go to Zoom Zoom: north 1st left, 3rd right.
Go to Cyclone: west.
    [Pickup character twice]
[two]
Pickup a passenger going to the Post Office.
Switch to plan end_loop if noone is waiting.
Switch to plan two.
    [Prints characters or crashes program, you can't drive that way]
[end_loop]
Go to the Post Office: south 1st left, 2nd right, 1st left.
Switch to plan loop.

Comment

It does not even matter whether we tank at Zoom Zoom or Fueler Up, both are 335 bytes.

By tanking at Fueler Up we pay so much that we don't earn enough and are out of gas for string of length 86 or more. However, even tanking at Zoom Zoom does not allow to drive infinitely, it probably stops at strings of a length around 129, I didn't test or solve this because it's an old answer.

Go to Post Office:w 1 l 1 r 1 l.Pickup a passenger going to Chop Suey.[A]Go to Fueler Up:n 1 r 1 l.Go to Chop Suey:n 3 r 1 l.Switch to plan B i.Pickup a passenger going to Cyclone.Go to Cyclone:n 1 l 3 l.[C]Pickup a passenger going to Post Office.Switch to plan B i.Switch to plan C.[B]Go to Post Office:s 1 l 2 r 1 l.Switch to plan A.

Try it online! (With a long string)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You can save four bytes by removing the quotation marks in the "Switch to plan" commands. \$\endgroup\$
    – Dorian
    Commented Nov 12, 2019 at 10:12
3
\$\begingroup\$

Dis, 3 bytes.

}{{

Try it online!

How it works

} ( a=getchar;if a==EOF a=59048;)
 { ( if a==59048 exit; else putchar a%256; )
   { ( again)
( then keep program counter+=1 until 59048 where each cell from i=3 to 59048 is NOP;
   then pc=0 if pc is 59048) 
\$\endgroup\$
3
\$\begingroup\$

Julia 1.0, 20 18 bytes

!s=join([s...].^2)

Try it online!

\$\endgroup\$
0
3
\$\begingroup\$

Vyxal, 4 2 bytes

2•

Try it Online!

Removed implicit input and output. Thanks @emanresu A

Doesn't beat Y but works nonetheless.

\$\endgroup\$
1
  • \$\begingroup\$ Nice! You don't need the ? or , due to implicit input/output. \$\endgroup\$
    – emanresu A
    Commented Sep 16, 2021 at 9:01
3
\$\begingroup\$

Q, 7 bytes:

(,/)2#'

Explanation

      '          // Each operator
    2#           // Take two
(,/)             // Join over (aka raze)

q/kdb+ CLI

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Golf! Nice answer. \$\endgroup\$
    – rydwolf
    Commented Oct 27, 2021 at 2:34
3
\$\begingroup\$

Lexurgy, 28 bytes

The "canonical" way of duplicating characters (gemination in linguistics terms) in Lexurgy: capture a character and an empty string, and replace both with itself. The $$ matches the space literal between words on a newline-separated input.

a:
[]$1 *=>$1 $1
$$=>$$ $$
\$\endgroup\$
3
\$\begingroup\$

TI-Basic, 52 37 39 bytes

For(I,1,2length(Ans),2
sub(Ans,1,I)+sub(Ans,I,1-I+length(Ans
End
Ans

Input is taken in Ans. Output is stored in Ans and displayed.

\$\endgroup\$
3
\$\begingroup\$

Javascript(Node.js), 64 57 55 bytes

-7 bytes thanks to Radvylf Programs
-2 bytes thanks to pxeger
This is my first code golf answer, so I know this could be improved.

s=>{eval("e='';for(var i in s){e+=s.at(i).repeat(2)};e")}

Attempt this online

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Welcome to code golf! You can save some bytes by replacing (s) with s, shortening end to a single letter, and removing the {} around the for loop. You can also use a trick where instead of s=>{...;return end}, you do s=>eval("...;end") to save another byte. \$\endgroup\$
    – rydwolf
    Commented Mar 31, 2022 at 2:35
  • \$\begingroup\$ The eval() tip Radvylf mentioned requires you to remove the {} around the function. Also, you can avoid the problem of having an extra 20 bytes on ATO by putting the running code in the Header and Footer: ato.pxeger.com/… \$\endgroup\$
    – pxeger
    Commented Mar 31, 2022 at 7:49
  • \$\begingroup\$ 33 bytes \$\endgroup\$
    – Shaggy
    Commented Nov 23, 2022 at 9:53
3
\$\begingroup\$

C (clang), 43 chars

The function f is double speaking its string input.

f(char*a){*a&&f(a+!!putchar(putchar(*a)));}

Edit : saved 1 char by reusing the putchar output to eliminate a division, by ceilingcat.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Suggest printf("%c%1$c",*a)-1 instead of !!putchar(putchar(*a)) \$\endgroup\$
    – ceilingcat
    Commented Apr 9, 2022 at 20:26
3
\$\begingroup\$

Curry (PAKCS), 16 bytes

(>>=(\x->[x,x]))

Try it online!

very similar to haskell.

\$\endgroup\$
3
\$\begingroup\$

Rust, 114 bytes

fn main(){let mut b=format!("");std::io::stdin().read_line(&mut b).unwrap();for l in b.chars(){print!("{}{0}",l)}}

Rust is not a great golfing language given its focus on explicitness, but here's an answer anyway!

Normally one allocates a string using String::new(), but format!("") is two bytes shorter. I also use that the print macro can accept the index of the variable to print, so I avoid writing print!("{}{}",l,l), saving one byte.

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Python 3, 32 bytes

lambda s:''.join(c+c for c in s)

Try it online!

\$\endgroup\$
3
\$\begingroup\$

BRASCA, 6 bytes

As of writing, there's no online interpreter yet.
EDIT: There is now.

,[:oo]

Try it online!

Explanation

<implicit input>      - Push STDIN to the stack
,                     - Reverse stack
 [   ]                - While non-zero:
  :oo                 -     Output the current character twice
\$\endgroup\$
3
\$\begingroup\$

MUMPS, 36 bytes

a(s) f %=1:1:$l(s) w $e(s,%),$e(s,%)

Try it online!

Explanation:

  • a(s) labels this line as a subroutine a with one parameter s.
  • $l is short for $length and returns the length of a string.
  • f is short for for. f %=1:1:$l(s) loops from 1 to $l(s) in steps of 1 with the variable % storing the current value.
  • $e is short for $extract. $e(s,%) gets the character of s at position % (one-indexed).
  • w is short for write and prints the expression that follows it.
\$\endgroup\$
3
\$\begingroup\$

CellTail, 128 94 90 bytes

N,k&N..,N:1,k,[k];(k,b),N,N:1,k,b;(k,b),c&N..,1|N:1,k,b+[c];(_,a&N..,1)|(1,a&N..,_):1,a,1;

Since both the input and output need to be plain characters it was a bit tricky to prevent spiraling into a endless duplication loop. This version uses 1 as a marker to indicate it's neighbors don't need to split themselves further.

Try the online demo

\$\endgroup\$
3
\$\begingroup\$

yup, 9 7 bytes

*{:@@*}

Try it online.

Explanation:

*        # Push the first input-character
 {    }  # Loop as long as the top of the stack is NOT 0 (without popping):
         # (the initial `*` is to start the loop)
  :      #  Duplicate the character so there are two on the stack
   @@    #  Pop both, and print them as characters
     *   #  Push the next input-character for the next iteration
         #  (which will push 0 if there are no more input(-character)s left)
\$\endgroup\$
3
\$\begingroup\$

Piet + ascii-piet, 18 bytes (3×6=18 codels)

Technically, we can create a trivial 5 codel (4 ops + 4 no-ops) answer that will never terminate. This non-trivial no-error implementation is a lot more interesting.

Piet image with codel size 25

Codel size 1: Piet image with codel size 1

rfnf Tk??k?Ttilj t

Try visual Piet online! or Try npiet online!

This improves the answer by @gastropner with 2 codels. Instead of a 5×4 image, this uses a 3×6 image. If you count the number of bytes using ascii-piet, you will find that the previous answer was 18 bytes as well and this is not an improvement but an alternative.

We use the fact that invalid instructions get ignored and got lucky that the whole program is a cycle, just like the previous answer. The main loop is a total of 10 operations, which is an improvement of 1 compared to the previous answer. This improvement was possible by moving the termination point to the right instead of bottom left. In order, the operations are:

1.  Output the top value on the stack as character,
2.  Pop the top value from the stack (0 for all but the first loop),
3.  Push 1 to the stack,
4.  Use a `not` operation to turn it into 0,
5.  Push the input character to the stack,
6.  Duplicate the input character
      (OR 0 in case there was no input character),
7.  Duplicate it again,
8.  Use a `not` operation to turn the top value into
      a 0 if there was a (non-null) character and
      a 1 if there wasn't,
9.  Exit the loop if the top value from the stack is 1,
10. Output the top value on the stack as character.

I don't think it's possible to remove popping 0 from the stack, because you need the 0 on the stack which requires steps 3 and 4. If you remove step 2, your program could technically become 9 steps total at the expense of an ever growing stack, however, loops must always use an even number of codels. With 9 operations you would thus need a 2 codel block to make up for the odd number. If you could get the program to work in 8 steps, that's probably the minimum as I believe you will necessarily need 8 operations: INC DUP DUP NOT OUTC OUTC DP+/CC+ PUSH. Using the same DUP and OUTC commands will be very difficult with so little space, but I think that would be the only option for reducing the size. Lastly, I do think you need the ninth NOT to contrast the sentinel with the input character, because you cannot check for the difference between a successful command and an ignored command without having a different truth value for both.

Note that this also fixes a small bug in the previous answer. The problem with that code is that the Codel Chooser switches between left and right for each iteration. This means that half the time, no 1 is added to the stack and then the previous value on the stack is used in the NOT operation. Then if it reaches the DP+ operation with a 1 (a quarter of the time) and this is the end of the string it will act as if this is the input character and print two <SOH> characters. This bug only occurs for strings of length 𝟤+𝟦𝑘.

\$\endgroup\$
1
  • \$\begingroup\$ You can save 2 bytes in ascii-piet by halting with a white loop instead (like this). It's part of Piet specification, but IIRC npiet doesn't implement it. Also rotate the cycle a bit to get 14 in ascii-piet (20 codels). \$\endgroup\$
    – Bubbler
    Commented Jun 20 at 0:08
1 2 3
4
5
9

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.