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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I hope this picture looks familiar to you.

enter image description here

It's one of Pacman's ghosts in his "vulnerable" state, after Pacman has eaten a power pill.

The challenge

Picture our ghost in a little frame, using ASCII art. At normal scale (more about this later), each square in the above image should correspond to one character, and the frame should have a one-character separation up and down, and a two-character separation to the left and right of the ghost:

####################
#                  #
#       ####       #
#     ########     #
#    ##########    #
#   ############   #
#   ############   #
#   ###  ##  ###   #
#  ####  ##  ####  #
#  ##############  #
#  ##############  #
#  ##  ##  ##  ##  #
#  # ##  ##  ## #  #
#  ##############  #
#  ## ###  ### ##  #
#  #   ##  ##   #  #
#                  #
####################

But this doesn't look very pretty. # may not be the best choice for the active pixels. Besides, character cells are not square, which makes our friend look more ghostly than he already is.

So, to have more flexibility, the picture will change according to three input parameters:

  • Character to be used for active pixels;
  • Horizontal scale factor;
  • Vertical scale factor.

For example, with %, 4, 2 the ouput would be the better looking picture

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%                                                                        %%%%
%%%%                                                                        %%%%
%%%%                            %%%%%%%%%%%%%%%%                            %%%%
%%%%                            %%%%%%%%%%%%%%%%                            %%%%
%%%%                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                    %%%%
%%%%                    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                    %%%%
%%%%                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                %%%%
%%%%                %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                %%%%
%%%%            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%            %%%%
%%%%            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%            %%%%
%%%%            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%            %%%%
%%%%            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%            %%%%
%%%%            %%%%%%%%%%%%        %%%%%%%%        %%%%%%%%%%%%            %%%%
%%%%            %%%%%%%%%%%%        %%%%%%%%        %%%%%%%%%%%%            %%%%
%%%%        %%%%%%%%%%%%%%%%        %%%%%%%%        %%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%        %%%%%%%%        %%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%        %%%%%%%%        %%%%%%%%        %%%%%%%%        %%%%
%%%%        %%%%%%%%        %%%%%%%%        %%%%%%%%        %%%%%%%%        %%%%
%%%%        %%%%    %%%%%%%%        %%%%%%%%        %%%%%%%%    %%%%        %%%%
%%%%        %%%%    %%%%%%%%        %%%%%%%%        %%%%%%%%    %%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%        %%%%
%%%%        %%%%%%%%    %%%%%%%%%%%%        %%%%%%%%%%%%    %%%%%%%%        %%%%
%%%%        %%%%%%%%    %%%%%%%%%%%%        %%%%%%%%%%%%    %%%%%%%%        %%%%
%%%%        %%%%            %%%%%%%%        %%%%%%%%            %%%%        %%%%
%%%%        %%%%            %%%%%%%%        %%%%%%%%            %%%%        %%%%
%%%%                                                                        %%%%
%%%%                                                                        %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Rules

All builtins allowed.

Inputs are taken in any reasonable format and any order. The first input above (character for active pixels) is guaranteed to be a printable ASCII character (codes 32 to 126).

Trailing space after each line or trailing newlines after last line are acceptable.

Code golf, fewest bytes wins.

share|improve this question
up vote 29 down vote accepted

CJam, 53 51 49 bytes

q~"ǟ #/?Y__Fy_Nf ǟ"f{'Ƞ^2b_W%+S@+f=}fe*e*N*

Note that three of the characters are unprintable. Try it online!

Background

The right half of the unscaled output is identical to the left one, so it suffices to encode one of them. If we replace spaces with zeroes and non-spaces with ones, we get

1111111111
1000000000
1000000011
1000001111
1000011111
1000111111
1000111111
1000111001
1001111001
1001111111
1001111111
1001100110
1001011001
1001111111
1001101110
1001000110
1000000000
1111111111

where each line can be interpreted as a binary number. This yields

1023 512 515 527 543 575 575 569 633 639 639 614 601 639 622 582 512 1023

The easiest way to encode this information is to replace each integer with the Unicode character at that code point, but they would all require two bytes to be encoded with UTF-8.

By XORing the integers with 544, we keep all but two integers below 128 and avoid null bytes.

The result is

479 32 35 47 63 31 31 25 89 95 95 70 121 95 78 102 32 479

as integers or

ǟ #/?\x1f\x1f\x19Y__Fy_Nf ǟ

as an escaped string.

How it works

q~                e# Read and evaluate all input. This pushes the vscale factor V,
                  e# the hscale factor H, and the character C.
"ǟ #/?Y__Fy_Nf ǟ" e# Push that string.
f{                e# For each character, push C and the character; then:
'Ƞ^               e#   XOR the character with '\u0220' (544), casting to integer.
 2b               e#   Convert from integer to base 2.
 _W%              e#   Push a reversed copy of the binary digits.
 +                e#   Concatenate.
 S@+              e#   Append C to " ".
 f=               e#   Replace each binary digit with ' ' or C.
}                 e#
fe*               e# Repeat each character in each string H times.
e*                e# Repeat each string V times.
N                 e# Join the strings, separating by linefeeds.
share|improve this answer
5  
How quick, and short code! Impressive! – Luis Mendo Feb 23 at 17:35

Perl, 113 105 104 100 97 96

Added +2 for -ap

Suggestions by dev-null save 9 bytes Fixed wrong count as noticed by Dennis

Run using echo "2 4 %" | perl -ap pacman.pl

pacman.pl:

}for(map+(unpack(aXBXB8Xb8XBXa),$/)x"@F","\xff\x00\x03\x0f\x1f\x3f\x3f\x39\x79\x7f\x7f\x66\x59\x7f\x6e\x46\x00\xff"=~/./g){s%%($&?$F[2]:$")x$F[1]%ge

except that the string "\xff\x00\x03\x0f\x1f\x3f\x3f\x39\x79\x7f\x7f\x66\x59\x7f\x6e\x46\x00\xff" should be written in binary form with single quotes

Space as replacement character becomes the empty string and leads to short lines. But it will all look blank anyways

share|improve this answer

Dyalog APL, 64 bytes

{/∘⍉/⍺,⊂' '⍵[1+,∘⌽⍨1⍪⍨1⍪1,0⍪⍨0⍪0,0,⍉(7/2)⊤⎕AV⍳'Äâ\⊥⊥∘)⍞⍞┬#⍞`⍒']}

This takes the scale factor as its left argument and the character as its right argument, i.e:

      2 1{/∘⍉/⍺,⊂' '⍵[1+,∘⌽⍨1⍪⍨1⍪1,0⍪⍨0⍪0,0,⍉(7/2)⊤⎕AV⍳'Äâ\⊥⊥∘)⍞⍞┬#⍞`⍒']}'%'
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
 %%                                    %% 
 %%              %%%%%%%%              %% 
 %%          %%%%%%%%%%%%%%%%          %% 
 %%        %%%%%%%%%%%%%%%%%%%%        %% 
 %%      %%%%%%%%%%%%%%%%%%%%%%%%      %% 
 %%      %%%%%%%%%%%%%%%%%%%%%%%%      %% 
 %%      %%%%%%    %%%%    %%%%%%      %% 
 %%    %%%%%%%%    %%%%    %%%%%%%%    %% 
 %%    %%%%%%%%%%%%%%%%%%%%%%%%%%%%    %% 
 %%    %%%%%%%%%%%%%%%%%%%%%%%%%%%%    %% 
 %%    %%%%    %%%%    %%%%    %%%%    %% 
 %%    %%  %%%%    %%%%    %%%%  %%    %% 
 %%    %%%%%%%%%%%%%%%%%%%%%%%%%%%%    %% 
 %%    %%%%  %%%%%%    %%%%%%  %%%%    %% 
 %%    %%      %%%%    %%%%      %%    %% 
 %%                                    %% 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

Explanation:

  • ⍉(7/2)⊤⎕AV⍳'Äâ\⊥⊥∘)⍞⍞┬#⍞`⍒': The left half of the ghost, without the border. (It is symmetric.) Each character has its high bit set, to prevent selecting non-printing characters from ⎕AV, but only the first 7 bytes are used.

  • 0,⍪⍨0⍪0,0,: add a border of blanks on the left, top, and bottom

  • 1⍪⍨1⍪1,: add the frame on the left, top, and bottom
  • ,∘⌽⍨: join it with its vertical mirror
  • 1+: add 1, because arrays are 1-indexed by default
  • ' '⍵[...]: use that matrix as an index into the string ' '⍵, so each 0 gets mapped to a blank and each 1 gets mapped to .
  • ⍺,⊂: enclose the matrix and join it to the scale factors
  • /: right fold with the following function:
  • /∘⍉: transpose and scale horizontally
share|improve this answer

MATL, 71 bytes

32hO511-3-12-16-32O6-64-6O25 13-38 17 40 70-511Nq$hYs10H$Bt!P!hi1$lX*Q)

Try it online!

Explanation

The image is horizontally symmetric, so only the left half needs to be coded. Each 10-pixel row is binary coded as a number between 0 and 1023. Active pixels are coded as 0 rather than 1, so the first row is number 0 rather than 1023.

Since consecutive rows differ by a few pixels only, the numbers are further encoded differentially. So each row will be decoded as the cumulative sum of all numbers up to that row, followed by conversion to binary.

The needed numbers are then

0 511 -3 -12 -16 -32 0 6 -64 -6 0 25 13 -38 17 40 70 -511

0 is introduced in MATL using the O function, which avoids a separator with neighbouring numbers. Also, negative signs do not imply extra bytes as they serve as separators.

Once the array has been created, it is cumulatively summed, binary-decoded, and horizontally mirrored. The resulting 2D array is used to index a two-char string to produce the result. This string is of the form '% ', where '%' is an input char.

As noted by @Conor, the code also works with two chars as input. In this case the final string indexed into will be of the form '%_ ', where the input is a two-char string '%_'. The space will simply be ignored, because the indexing array only addresses the first two chars.

32                                             % space (ASCII)
h                                              % concat horizontally with 1st input: char
O511-3-12-16-32O6-64-6O25 13-38 17 40 70-511   % push these numbers
Nq$h                                           % concat all those numbers
Ys                                             % cumulative sum
10H$B                                          % convert to 10-digit binary numbers
                                               % gives 2D array, each number in one row
t                                              % duplicate
!P!                                            % flip horizontally
h                                              % concat horizontally
i                                              % take 2nd input: array [V H]
1$l                                            % matrix oh V×H ones  
X*                                             % Kronecker product to increase vertical
                                               % and horizontal scales by V and H resp.
Q                                              % add 1. Converts array of 0,1 into 1,2
)                                              % uses those 1,2 as indices into string
share|improve this answer
7  
    
As of version 16.0.0 of the language, replace commas by spaces – Luis Mendo Apr 4 at 0:53

Batch, 740 bytes

@echo off
setlocal enabledelayedexpansion
set h=%3
set w=
set s=
for /l %%a in (1,1,%2) do set w=%1!w!&set s= !s!
call :l ####################
call :l #                  #
call :l #       ####       #
call :l #     ########     #
call :l #    ##########    #
call :l #   ############   #
call :l #   ############   #
call :l #   ###  ##  ###   #
call :l #  ####  ##  ####  #
call :l #  ##############  #
call :l #  ##############  #
call :l #  ##  ##  ##  ##  #
call :l #  # ##  ##  ## #  #
call :l #  ##############  #
call :l #  ## ###  ### ##  #
call :l #  #   ##  ##   #  #
call :l #                  #
call :l ####################
exit/b
:l
set l=%*
set l=!l: =%s%!
for /l %%a in (1,1,%h%) do echo !l:#=%w%!
share|improve this answer

JavaScript (ES6), 167 bytes

(s,w,h)=>[...`NJ56:*

\fLJJSlJ[s5NJ`].map(c=>`${t=(c.charCodeAt()^565).toString(2)}${[...t].reverse().join``}
`.replace(/./g,b=>` ${s}`[b].repeat(w)).repeat(h)).join``

Based on @Dennis's answer. I guess you could shave off another byte by using a literal FF instead of \f, but I doubt I can paste one in here. When trying this out you may also want to use \u01CA instead of the NJ character.

Sadly prepending a space to the character argument costs a whole 6 bytes.

share|improve this answer

Seriously, 116 bytes

╩' "3ff 200 203 20f 21f 23f 23f 239 279 27f 27f 266 259 27f 26e 246 200 3ff"s`24╙(¿¡╜'1(Æ' '0(Æ"╛*"£M;R@+εj2└@n`M'
j

That newline is important. Hexdump:

00000000: ca27 2022 3366 6620 3230 3020 3230 3320  .' "3ff 200 203
00000010: 3230 6620 3231 6620 3233 6620 3233 6620  20f 21f 23f 23f
00000020: 3233 3920 3237 3920 3237 6620 3237 6620  239 279 27f 27f
00000030: 3236 3620 3235 3920 3237 6620 3236 6520  266 259 27f 26e
00000040: 3234 3620 3230 3020 3366 6622 7360 3234  246 200 3ff"s`24
00000050: d328 a8ad bd27 3128 9227 2027 3028 9222  .(...'1(.' '0(."
00000060: be2a 229c 4d3b 5240 2bee 6a32 c040 6e60  .*".M;R@+.j2.@n`
00000070: 4d27 0d0a 6a                             M'..j

Same strategy as Dennis's CJam answer, but the values are encoded in hex, rather than XORed with 544, and string manipulation is a lot harder in Seriously.

Try it online!

share|improve this answer

Python 2, 838 828 618 bytes

Saved 210 bytes by using a string instead of an array, thanks to Dennis for that suggestion, I know I can make even better, but for now its a good improvement.

This is the best I can do, I'm not very good with graphics in command line.

I took the small ghost as base.

I'm using the ascii 219 by default, because with that char, the ghost looks pretty awesome!!!

Golfed

def g(c,s,w,h,l=""):
 x="c-20,c-1,s-18,c-1,c-1,s-7,c-4,s-7,c-1,c-1,s-5,c-8,s-5,c-1,c-1,s-4,c-10,s-4,c-1,c-1,s-3,c-12,s-3,c-1,c-1,s-3,c-12,s-3,c-1,c-1,s-3,c-3,s-2,c-2,s-2,c-3,s-3,c-1,c-1,s-2,c-4,s-2,c-2,s-2,c-4,s-2,c-1,c-1,s-2,c-14,s-2,c-1,c-1,s-2,c-14,s-2,c-1,c-1,s-2,c-2,s-2,c-2,s-2,c-2,s-2,c-2,s-2,c-1,c-1,s-2,c-1,s-1,c-2,s-2,c-2,s-2,c-2,s-1,c-1,s-2,c-1,c-1,s-2,c-14,s-2,c-1,c-1,s-2,c-2,s-1,c-3,s-2,c-3,s-1,c-2,s-2,c-1,c-1,s-2,c-1,s-3,c-2,s-2,c-2,s-3,c-1,s-2,c-1,c-1,s-18,c-1,c-20"
 for r in x.split(","):
  d=r.split("-");l+=d[0].replace("s",s).replace("c",c)*int(d[1])*w
  if len(l)==20*w:print(l+"\n")*h,;l=""

Try it on repl.it

Ungolfed

def pacmanGhost(char = "█", sep = " ", width = 1, height = 1):
    coords = [[[char, 20]], [[char, 1], [sep, 18], [char, 1]],[[char, 1], [sep, 7], [char, 4], [sep, 7], [char, 1]], [[char, 1], [sep, 5], [char, 8], [sep, 5],
         [char, 1]], [[char, 1], [sep, 4], [char, 10], [sep, 4], [char, 1]], [[char, 1], [sep, 3], [char, 12], [sep, 3], [char, 1]], [[char, 1], [sep, 3],
         [char, 12], [sep, 3], [char, 1]], [[char, 1], [sep, 3], [char, 3], [sep, 2], [char, 2], [sep, 2], [char, 3], [sep, 3], [char, 1]], [[char, 1],
         [sep, 2], [char, 4], [sep, 2], [char, 2], [sep, 2], [char, 4], [sep, 2], [char, 1]], [[char, 1], [sep, 2], [char, 14], [sep, 2], [char, 1]],
         [[char, 1], [sep, 2], [char, 14], [sep, 2], [char, 1]], [[char, 1], [sep, 2], [char, 2], [sep, 2], [char, 2], [sep, 2], [char, 2], [sep, 2],
         [char, 2], [sep, 2], [char, 1]], [[char, 1], [sep, 2], [char, 1], [sep, 1], [char, 2], [sep, 2], [char, 2], [sep, 2], [char, 2], [sep, 1], [char, 1],
         [sep, 2], [char, 1]], [[char, 1], [sep, 2], [char, 14], [sep, 2], [char, 1]], [[char, 1], [sep, 2], [char, 2], [sep, 1], [char, 3], [sep, 2],
         [char, 3], [sep, 1], [char, 2], [sep, 2], [char, 1]], [[char, 1], [sep, 2], [char, 1], [sep, 3], [char, 2], [sep, 2], [char, 2], [sep, 3],
         [char, 1], [sep, 2], [char, 1]], [[char, 1], [sep, 18], [char, 1]], [[char, 20]]]
    for coord in coords:
        line = ""
        for element in coord:
            line = "{}{}".format(line, element[0] * element[1] * width)
        for i in range(height):
            print(line)
    return

Test

enter image description here

share|improve this answer
    
You would achieve a much better score if you simply saved the uncompressed, unscaled image in a string. Also, you are wasting bytes on default arguments and the return statement. – Dennis Feb 26 at 17:27

BBC BASIC, 239 236 232 214 bytes

0DEFPROCM(A,B,C)C=C-32:FORU=0TO18*A-1:FORV=0TO20*B-1:Y=U DIVA:X=V DIVB:V.32-C*FNC((X<10)*-X-(X>9)*(19-X),Y):N.:P.:N.:E.
1DEFFNC(X,Y)Z=Y*10+X:=((ASCMI."#Cb^2aC*[#1CF<;)C$;I9I$;EYLb&#",Z/6+1)-35)AND(2^(Z MOD6)))=0

Calling PROCM(1,1,35) produces the ghost made of # symbols. The arguments to PROCM are: horizontal scale, vertical scale, ASCII value of character.

This program will work both for Brandy Basic, and BASIC 2 on an original Model B.

share|improve this answer

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.