Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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 its self, as *s or another char

So a sample run would look like this:

Input:

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

Output:

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

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
share|improve this question
2  
What assumptions should be made about where it's permissible to insert spaces and newlines without changing the semantics of the program? –  Peter Taylor May 5 at 23:11
    
@PeterTaylor in the output? –  TheDoctor May 5 at 23:16
1  
@PeterTaylor it seems there is no leeway for placing/separating the code, so I suppose semantics are ignored? –  Martin Büttner May 5 at 23:18
1  
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? –  Ilmari Karonen May 6 at 11:38
1  
@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? –  Rainbolt May 6 at 15:03

9 Answers 9

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.

share|improve this answer

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
.   . . .
..... . ...
share|improve this answer
1  
./ascii.rb: line 2: syntax error near unexpected token `(' ./ascii.rb: line 2: `puts gets($n).gsub(?*){c.slice!(0)||?.},c' –  Not that Charles May 6 at 3:27
    
@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 –  Chron May 6 at 3:33
    
weird. IDEONE worked fine. Anyway, you can save a char (the space) by replacing puts with $><< and changing the , at the end to a + –  Not that Charles May 6 at 3:43
    
@Charles Good call. Thanks! –  Chron May 6 at 3:47

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 ...
.   . . .
share|improve this answer

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

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

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)
share|improve this answer
    
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. –  nyuszika7h May 6 at 16:48
    
Thanks for input! Unfortunately your first advice doesn't work because it outputs dots as long as string length>0. –  avall May 7 at 6:27
    
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. –  nyuszika7h May 7 at 12:13
    
(l+['.']).pop(0) doesn't remove elements from l so only first character is printed but l condition works :) –  avall May 7 at 12:55

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 :)

share|improve this answer

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 <>;

share|improve this answer

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.

share|improve this answer

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);
}
share|improve this answer
    
You can use puts(s) instead of printf("%s",s) to save 7 bytes. –  nyuszika7h May 6 at 16:58
    
@nyuszika7h Thanks! But I don't know if the additional \n is a problem. –  MarcDefiant May 8 at 7:12

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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