17
\$\begingroup\$

Task:

There are a lot of answers on this site that are arranged into ascii art, like this one. Usually the arrangement is done manually, but wouldn't a program help with that? :)

Your program will take 3 inputs:

  • The code, as one single line
  • The number of lines in the pattern (can be omitted if not necessary)
  • The pattern itself, as *s or another char

Rules:

  • You have to write a program (not a function) that reads from stdin
  • The text is placed left-to-right per line
  • If there is not enough text to fill the pattern, put .s in the remaining spaces
  • If there is too much text to fill the pattern, print it out after the output
  • , so the shortest code, in bytes wins

Sample Runs:

Input (Exact Fit test):

qwertyuiopasdfghjklzxcvbnm
4
***** * ***
*   * * *
*   * * *
***** * ***

Output:

qwert y uio
p   a s d
f   g h j
klzxc v bnm

Input (Extra characters test):

qwertyuiopasdfghjklzxcvbnm12345
4
***** * ***
*   * * *
*   * * *
***** * ***

Output:

qwert y uio
p   a s d
f   g h j
klzxc v bnm
12345

Input (Insufficient Characters test):

qwertyuiopasdfg
4
***** * ***
*   * * *
*   * * *
***** * ***

Output:

qwert y uio
p   a s d
f   g . .
..... . ...
\$\endgroup\$
  • 2
    \$\begingroup\$ What assumptions should be made about where it's permissible to insert spaces and newlines without changing the semantics of the program? \$\endgroup\$ – Peter Taylor May 5 '14 at 23:11
  • 1
    \$\begingroup\$ @PeterTaylor it seems there is no leeway for placing/separating the code, so I suppose semantics are ignored? \$\endgroup\$ – Martin Ender May 5 '14 at 23:18
  • 1
    \$\begingroup\$ Do the "can be omitted" and "or another char" parts of the spec mean that we're free to, say, specify that the number of lines must be omitted and that the asterisks should be replaced by, say, Xes for our program to work? \$\endgroup\$ – Ilmari Karonen May 6 '14 at 11:38
  • 1
    \$\begingroup\$ @Bakuriu I don't understand your comment. If you write a program in ASCII, then each character is a byte. If you write in UTF-32, then each character is 4 bytes. The shortest code in bytes, not characters, wins according to the current spec. It sounds like you want the encoding to become a requirement, but I don't see why it is necessary. Did I misunderstand your comment? \$\endgroup\$ – Rainbolt May 6 '14 at 15:03
  • 1
    \$\begingroup\$ Based on some answers missing some of the rules, I've added two examples and moved the entire example block below the rules block for additional clarity. \$\endgroup\$ – Veskah Apr 29 at 12:36

15 Answers 15

5
\$\begingroup\$

GolfScript, 30 characters

n/(\(;n*'*'/{@.!'.'*+([]+@+}*\

Run online.

Examples:

> qwertyuiopasdfghjklzxcvbnm
> 4
> ***** * ***
> *   * * *
> *   * * *
> ***** * ***

qwert y uio
p   a s d
f   g h j
klzxc v bnm

> qwertyuiopasdfghjklzxcvbnm
> 1
> ***** * ***

qwert y uio
pasdfghjklzxcvbnm

> qwerty
> 2
> ***** * ***
> *   * * *

qwert y ...
.   . . .
\$\endgroup\$
10
\$\begingroup\$

Perl 6: 60 characters EDIT: 38 points (see bottom)

  #C#O     D#E#G#O       #L#
#F    #.#S#       T#A#C#K
  get\     .subst(       "*"
,{    shift       BEGIN [
  get\     .comb,\       "."
xx    * ]},       :g)\ .\
  say\     xx get\       ()\
#E    #X#C#       H#A#N#G
  #E#.     #C#O#M#       #!#

If you don't appreciate my terrible art skills, here's the golf:

get.subst("*",{shift BEGIN [get.comb,"."xx*]},:g).say xx get

This one does weird things with evaluation times.

First, the BEGIN keyword forces [get.comb, "." xx *] to be evaluated first, putting into an array the list of characters that make up "the code", followed by an infinite amount of "."s.

Next, the get at the end is evaluated, getting the number of lines of the ASCII art template. The xx operator repeats the first part of the program this many times. This makes more sense when you realize that code() xx count() is basically sugar for code() for 1..count(): count() should be evaluated first.

Finally, the get in the beginning of the program gets a line of the ASCII art template and substitutes every "*" with a value shifted off of the beginning of the array we made before everything else ({shift BEGIN …}).

EDIT:

Golfed down to 37 characters, plus one for the command line switch:

perl6 -pe's:g[\*]=shift BEGIN [get.comb,"."xx*]'

This is the same concept as the original, the -p switch iterating over each line (after the BEGIN has read in "the code"), and substituting all *s with the next letter from "the code" before printing it. The input format for this shouldn't include the number of lines of the format.

\$\endgroup\$
5
\$\begingroup\$

Ruby 2.0, 53 52 characters

c=gets.chop
$><<gets($n).gsub(?*){c.slice!(0)||?.}+c

As per the spec, doesn't use the 'number of lines' paramater.

Example run:

qwertyuiopasd
***** * ***
*   * * *
*   * * *
***** * ***

Output:

qwert y uio
p   a s d
.   . . .
..... . ...
\$\endgroup\$
  • 1
    \$\begingroup\$ ./ascii.rb: line 2: syntax error near unexpected token `(' ./ascii.rb: line 2: `puts gets($n).gsub(?*){c.slice!(0)||?.},c' \$\endgroup\$ – Not that Charles May 6 '14 at 3:27
  • \$\begingroup\$ @Charles I can't seem to get that error in any version of Ruby I have installed. Here's the code running on IDEONE: ideone.com/3HG3Fb \$\endgroup\$ – Paul Prestidge May 6 '14 at 3:33
  • \$\begingroup\$ weird. IDEONE worked fine. Anyway, you can save a char (the space) by replacing puts with $><< and changing the , at the end to a + \$\endgroup\$ – Not that Charles May 6 '14 at 3:43
  • \$\begingroup\$ @Charles Good call. Thanks! \$\endgroup\$ – Paul Prestidge May 6 '14 at 3:47
2
\$\begingroup\$

PowerShell, 63 86 83 82 bytes

+20 bytes thanks @Veskah

param($s,$p)-join($p|% *ht($s|% Le*)'*'|% t*y|%{if($_-eq42){$_=$s[$i++]}"$_."[0]})

Try it online!

Less golfed:

param($string,$pattern)

$chars = $pattern |
    % PadRight ($string|% Length) '*' |
    % toCharArray |
    % {
        if($_-eq42){$_=$string[$i++]}    # $_ can become $null
        "$_."[0]                         # $_ or '.' if $_ is $null
    }
-join($chars)
\$\endgroup\$
2
\$\begingroup\$

Japt, 18 bytes

sVè-)iVr-@t°J1 ª'.

Try it

\$\endgroup\$
  • \$\begingroup\$ sVl)iVr-@t°J1 ª'. works for 17 \$\endgroup\$ – Embodiment of Ignorance Apr 29 at 16:57
  • 1
    \$\begingroup\$ @EmbodimentofIgnorance, that would fail on the 4th rule.a \$\endgroup\$ – Shaggy Apr 29 at 17:00
2
\$\begingroup\$

T-SQL, 142 bytes

@h is the input text

@ is the pattern

DECLARE @h varchar(max)='qwertyuiopasdfg'
DECLARE @ varchar(max)='
***** * ***
*   * * *
*   * * *
***** * ***'

WHILE @ like'%*'SELECT @=left(@,charindex('*',@)-1)+left(@h+'.',1)+stuff(@,1,charindex('*',@),''),@h=substring(@h,2,999)PRINT
concat(@,'
'+@h)

Try it online

\$\endgroup\$
2
\$\begingroup\$

Perl 5 -plF, 51 bytes

$_=join'',<>;s/\*/@F?shift@F:'.'/ge;$\=$/.join'',@F

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ You're right; I missed that requirement. It's fixed now. \$\endgroup\$ – Xcali Apr 30 at 14:41
1
\$\begingroup\$

JavaScript - 199

text="qwertyuiopasdfghjklzxcvbnm";
pattern="***** * ***\n*   * * *\n*   * * *\n***** * ***";

function p(a,c){z=c.length,y=a.length,x=0;for(i=z;i-->0;)if(c[i]=="*")x+=1;if(x-y>0)for(i=x-y;i-->0;)a+=".";for(;i++<x;)c=c.replace(new RegExp("[*]"),a[i]);console.log(c);console.log(a.substring(x))}

p(text,pattern);

Outputs extra characters in text input if not used in pattern, uses padded "." if there's not enough.

EDIT: modified to be a function accepting text and pattern

\$\endgroup\$
  • 4
    \$\begingroup\$ Nice... but this uses hard-coded input. \$\endgroup\$ – TheDoctor May 6 '14 at 1:53
  • \$\begingroup\$ I wasn't sure how to handle stdin from JS, especially with the newlines. Suggestions? \$\endgroup\$ – Matt May 6 '14 at 3:14
  • \$\begingroup\$ @Matt Node? Spidermonkey? \$\endgroup\$ – Not that Charles May 6 '14 at 3:19
  • \$\begingroup\$ Perhaps making it a function... \$\endgroup\$ – TheDoctor May 6 '14 at 3:24
  • 4
    \$\begingroup\$ 136 : function p(a,c){x=c.split(s='*').length-1;for(i=x-a.length;i--;)a+='.';for(;i++<x;)c=c.replace(s,a[i]);console.log(c+'\n'+a.substring(x))} \$\endgroup\$ – Michael M. May 6 '14 at 9:05
1
\$\begingroup\$

JavaScript (ES6) -96 87

r=(c,p)=>{c=0+c;console.log(p.replace(/\*/g,t=>(c=c.substr(1),c[0]||'.'))+c.substr(1))}

Note: As suggested by the OP, I am using a function. But if its required to have a program, here's a 93 chars solution.

c=0+(x=prompt)();p=x();console.log(p.replace(/\*/g,t=>(c=c.substr(1),c[0]||'.'))+c.substr(1))

EDIT1: Major change, I don't know why I didn't realize this for the first time :P Saved 40 chars.


Usage:

// r(code, pattern)
r("qwertyuiopasdfghjklzxcvbnm", "***** * ***\n*   * * *\n*   * * *\n***** * ***\n** ** **)

Test Input: (without unneeded optional number as per spec)

qwertyuiopasdfghjklzxcvbnm
***** * ***
*   * * *
*   * * *
***** * ***
** ** **

Output:

qwert y uio
p   a s d
f   g h j
klzxc v bnm
.. .. ..      // not much text was there to fill *s - replaced with dots as per spec

Ungolfed Code:

function run(code, pattern){
  code = "0" + code;  // prepend a zero; useful for the substring operation ahead

  pattern = pattern.replace(/\*/g, function(){  // replace the dots
    // by removing the first letter of code
    // and replacing dot with the first-letter of leftover code 
    // and if it isn't there (code finished)
    // return a dot

    code = code.substr(1); 
    return c[0] || '.';
  });
  }

  // after this operation; code contains the last letter of the org. code

  console.log(  p +  // the pattern has now code
                "\n" +   // and a newline
                c.substr(1) // if there is more than one letter of code left; display it
             );
}

It would be very nice to hear of any suggestions from users :)

\$\endgroup\$
1
\$\begingroup\$

Perl, 70 characters

@_=split'',<>=~s/\n//r;<>;print/\*/?shift@_||'.':$_ for map{split''}<>

Or, without boundary check, 56 characters

@_=split'',<>;<>;print/\*/?shift@_:$_ for map{split''}<>

Note, this code is not using second line as in spec, and can be shortened by three characters <>;

\$\endgroup\$
1
\$\begingroup\$

Bash, 166 156 111 106

Reads from standard input, doesn't take a line count. First line of input is the code you want to put into ascii art, all subsequent lines are the ascii art, consisting of the @ character. Input has a maximum length of 999 chars, and is not permitted to contain forward slashes. (I chose not to use * or # because they have special meanings in Bash).

read -n999 -d/ i p
while [[ $p =~ @ && -n $i ]];do
p="${p/@/${i:0:1}}"
i=${i:1}
done
tr @ .<<<"$p"
echo $i

WARNING: This program uses a file called p. After executing the program, delete p - it will confuse the program the second time you run it.

Most of the work here is done by

p="${p/@/${i:0:1}}"
i=${i:1}

The first line substitutes the first @ in the art with the first character of the code. The second line removes the first character of the code.

If there is not enough code to fill the shape, a newline is printed after the main ascii art output by echo $i.

\$\endgroup\$
1
\$\begingroup\$

C, 98, 91 characters

Here a pretty straight-forward C solution in under 100 characters. This doesn't use the line count input. (Else a second unneeded gets() would be needed).

char b[999],*s;c;main(){gets(s=b);while(~(c=getchar()))putchar(c^42?c:*s?*s++:46);puts(s);}

ungolfed:

char b[999],*s;c;
main(){
    gets(s=b);
    while(~(c=getchar()))
        putchar(c^42?c:*s?*s++:46);
    puts(s);
}
\$\endgroup\$
  • \$\begingroup\$ You can use puts(s) instead of printf("%s",s) to save 7 bytes. \$\endgroup\$ – nyuszika7h May 6 '14 at 16:58
  • \$\begingroup\$ @nyuszika7h Thanks! But I don't know if the additional \n is a problem. \$\endgroup\$ – MarcDefiant May 8 '14 at 7:12
1
\$\begingroup\$

Python 2.7, 165 155 150 138 119 characters

Okay, pretty much but I guess it's the tiniest way to do it with Python.

import sys
r=raw_input
l=list(r())
w=sys.stdout.write
for c in"\n".join([r()for _ in[1]*input()]):w(c=='*'and(l and l.pop(0)or'.')or c)
w("".join(l))

Edit: new functional 1.0.1 version with even less bytes used:

Edit2: map(r,['']*input()) instead of [r()for _ in[1]*input()] and removed unused import

Edit3: '>'*input() instead of ['']*input() saving one character and adding prompt character for pattern :)

r=raw_input
l=list(r())
print''.join(map(lambda c:c=='*'and(l and l.pop(0)or'.')or c,"\n".join(map(r,'>'*input())))+l)
\$\endgroup\$
  • \$\begingroup\$ You can use (['.']+l).pop(0) instead of (len(l)and l.pop(0)or'.') to save 9 bytes. And input() instead of int(r()) to save 1 byte. \$\endgroup\$ – nyuszika7h May 6 '14 at 16:48
  • \$\begingroup\$ Thanks for input! Unfortunately your first advice doesn't work because it outputs dots as long as string length>0. \$\endgroup\$ – avall May 7 '14 at 6:27
  • \$\begingroup\$ I see why my suggestion isn't correct. Try (l+['.']).pop(0) instead, but if that doesn't work either, you can still save 4 bytes by using l and instead of len(l)and. \$\endgroup\$ – nyuszika7h May 7 '14 at 12:13
  • \$\begingroup\$ (l+['.']).pop(0) doesn't remove elements from l so only first character is printed but l condition works :) \$\endgroup\$ – avall May 7 '14 at 12:55
1
\$\begingroup\$

C# (Visual C# Interactive Compiler), 122 bytes

var n=ReadLine();int k=0;foreach(var z in In.ReadToEnd())Write(z>33?(n+new string('.',999))[k++]:z);Write(n.Substring(k));

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Due to lack of specifics and other answers doing it, you can probably ditch the "\n"+ to append the extra characters to the same line \$\endgroup\$ – Veskah Apr 30 at 12:07
0
\$\begingroup\$

05AB1E, 18 17 15 bytes

s0¢.$«0¹S.;0'.:

Takes the code as first input, pattern as second (with 0 instead of #).

Try it online or verify all test cases.

18 15 bytes alternative by taking the inputs in reversed order:

0¢.$¹ì0IS.;0'.:

Try it online.

Explanation:

s                # Swap with implicit inputs, so the stack order is now: [code, pattern]
 0¢              # Count the amount of "0" in the pattern
   .$            # Remove that many leading characters from the code
     «           # Append it to the (implicit) pattern input
      0¹S.;      # Replace every "0" one by one with the characters of the first code input
           0'.: '# Then replace any remaining "0" with "."
                 # (after which the result is output implicitly as result)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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