21
\$\begingroup\$

The Art of Word Shaping

Given a binary matrix, and a string of letters, replace all 1's in the matrix from left, to right with the letters of the string. Once the letters have been formed into the shape of the matrix, print the matrix, replacing 0's with spaces. It's probably easier to just give an example or two.


Case: Base case...

Input One:

[0,0,1,0,0]
[0,1,0,1,0]
[1,0,0,0,1]
[0,1,0,1,0]
[0,0,1,0,0]

"PPCGPPCG"

Output One:

  P    
 P C  
G   P
 P C 
  G  

Case: If the input string is longer than the number of ones...

Input Two:

[1,0,0]
[0,1,0]
[1,0,1]

lambda

Output Two:

l  
 a 
m b

Case: If the input string is shorter than the number of ones...

Input Three:

[1,1,1]
[1,0,1]
[1,1,1]

PPCG

Output Three:

PPC
G P
PCG

Available Assumptions

  • You may assume the input string is never empty.
  • You may assume the matrix will never be empty.
  • You may not assume that the binary matrix will never be all zeros.

Rules

  • If the string is shorter than the number of ones, repeat the string; all ones must be replaced.
  • If the string is longer than the number of ones, only use what is needed.
  • You may use True/False in place of integers/bits for the input.
  • Trailing spaces ARE REQUIRED, all zeros must be replaced with spaces.
  • A single trailing newline is acceptable.
  • This is code-golf, lowest byte count wins.
\$\endgroup\$
  • \$\begingroup\$ Does the matrix have to be input as an array or can I use a multiline-string? \$\endgroup\$ – Titus Nov 14 '16 at 15:32
  • \$\begingroup\$ @Titus that's fine, Martin Ender already did. \$\endgroup\$ – Magic Octopus Urn Nov 14 '16 at 15:34
  • \$\begingroup\$ The base case is not left to right. Do you mean top to bottom, then left to right? \$\endgroup\$ – edc65 Nov 14 '16 at 16:02
  • 1
    \$\begingroup\$ If the matrix is, for example, a 2x2 grid of zeroes, should we output a single space or a 2x2 grid of spaces? \$\endgroup\$ – artificialnull Nov 14 '16 at 16:28
  • \$\begingroup\$ @pieman2201 cleared up test case #4 to be better. \$\endgroup\$ – Magic Octopus Urn Nov 14 '16 at 16:43

20 Answers 20

3
\$\begingroup\$

MATL, 11 bytes

yz:)1Gg!(c!

Inputs are a numeric matrix (with ; as row separator) and a string.

Try it online! Or verify test cases: 1, 2, 3.

y       % Take the two inputs implicitly. Duplicate the first
        % STACK: [1,0,0; 0,1,0; 1,0,1], 'lambda', [1,0,0; 0,1,0; 1,0,1]
z       % Number of nonzeros
        % STACK: [1,0,0; 0,1,0; 1,0,1], 'lambda', 4
:       % Range
        % STACK: [1,0,0; 0,1,0; 1,0,1], 'lambda', [1 2 3 4]
)       % Reference indexing (select values)
        % STACK: [1,0,0; 0,1,0; 1,0,1], 'lamb'
1Gg     % Push first input as a logical matrix; will be used as index
        % STACK: [1,0,0; 0,1,0; 1,0,1], 'lamb', [1,0,0; 0,1,0; 1,0,1]
!       % Transpose. This is necessary because MATL uses column-major order
        % (down, then accross)
(       % Assignment indexing (fill with values). Since the original matrix
        % is numeric, the new values are introduced as their ASCII codes
        % STACK: [108, 0, 109; 0, 97, 0; 1, 0, 98]
c       % Convert to char
        % STACK: ['l m'; ' a '; '  b']
!       % Transpose back. Implicitly display
        % STACK: ['l  '; ' a '; 'm b']
\$\endgroup\$
  • \$\begingroup\$ MATL basically redefines how I've always seen collections... \$\endgroup\$ – Magic Octopus Urn Nov 14 '16 at 16:45
  • \$\begingroup\$ @carusocomputing Like in Matlab, the main data type is "rectangular" arrays: matrices or their n-dimensional analogues. They can contain numbers, chars or Boolean values. There are also cell arrays, that can contain arbitrary things, like Python's lists \$\endgroup\$ – Luis Mendo Nov 14 '16 at 19:13
  • \$\begingroup\$ Best answer selected after 2 weeks open. \$\endgroup\$ – Magic Octopus Urn Nov 30 '16 at 22:41
8
\$\begingroup\$

Vim, 44 42 bytes

qqy$P0xjf1"_xP{@qq@q:s/0/ /g^M:s/,/^V^M/g^M{D

Saved 2 bytes thanks to @DjMcMoylex!

Here, the ^M is a literal newline, and the ^V is CTRL-V

Takes the input in this format:

PPCG
00100,01010,10001,01010,00100

Disclaimer: If the string is longer than ~40 chars long, your computer might run out of ram.

Explanation:

qq             @qq@q                            # Start recording a recursive macro.
  y$P0x                                         # Duplicate the string and cut out the first character
       jf1"_xP{                                 # Find the first 1, and replace it with the cut character from the string.
                                                # Now we have replaced all the 1's with their respective character, but we still have the array in the original format, and we have the string massivly duplicated at the first line, so we need to clean it up:
                    :s/0/ /g^M                  # Replace all 0's with a space
                              :s/,/^V^M/g^M     # Replace all ,'s with a newline. The ^V acts like a backslash, it escapes the newline so that the command isn't run too soon
                                           {D   # Delete the first line

Here's a gif of me "running" the "program":

Me typing the keys

\$\endgroup\$
  • 1
    \$\begingroup\$ Hahaha, love the disclaimer. \$\endgroup\$ – Magic Octopus Urn Nov 14 '16 at 17:18
  • \$\begingroup\$ You could use { in place of gg to take a couple off. \$\endgroup\$ – DJMcMayhem Nov 14 '16 at 17:52
  • \$\begingroup\$ Ok, the gif is really neat, but do you think you could include it via link only? It lags my chrome every time I try to scroll past :( \$\endgroup\$ – wnnmaw Nov 15 '16 at 14:14
6
\$\begingroup\$

Retina, 41 33 bytes

0

+1`(.)(.*)(\D+)1
$2$1$3$1
A1`

Try it online!

The input string is given on the first row of the input, followed by the matrix. Since Retina has no concept of lists (or really anything except strings), there are no separators in the binary matrix except for linefeeds to separate rows.

Explanation

0

Turns zeros into spaces.

+1`(.)(.*)(\D+)1
$2$1$3$1

Repeatedly replace the first 1 with the first character of the input string while also rotating that character to the end of the input string. This takes care cases where there are more 1s than characters in the input string.

A1`

Discard the first line, i.e. the input string.

\$\endgroup\$
  • 2
    \$\begingroup\$ (.)(.*) - Teehee... \$\endgroup\$ – Magic Octopus Urn Nov 14 '16 at 21:06
6
\$\begingroup\$

JavaScript ES6, 67 53 50 49 bytes

Saved 3 bytes thanks to @ETHproductions Saved 1 more thanks to @Neil

(a,b,i)=>a.replace(/./g,c=>+c?b[++i]||b[i=0]:' ')

f=
(a,b,i)=>a.replace(/./g,c=>+c?b[++i]||b[i=0]:' ')

G=_=>h.innerHTML = f(`00100
01010
10001
01010
00100`,z.value)
h.innerHTML = G()
<input id=z oninput="G()" value="PPCG"></input>
<pre id=h>

Old code before I knew that string matrices are a valid input format:

(a,b)=>a.map(c=>c.map(d=>d?b[i++%b.length]:' ').join``,i=0).join`
`

f=
(a,b)=>a.map(c=>c.map(d=>d?b[i++%b.length]:' ').join``,i=0).join`
`

G=_=>h.innerHTML = f([[0,0,1,0,0],[0,1,0,1,0],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0]],z.value)
h.innerHTML = G()
<input id=z oninput="G()" value="PPCG"></input>
<pre id=h>

\$\endgroup\$
  • \$\begingroup\$ I'd suggest c=>' '[c]||b[i++%b.length], but sadly it's a byte longer... \$\endgroup\$ – ETHproductions Nov 14 '16 at 15:51
  • 1
    \$\begingroup\$ However, there's another way to save 3 bytes: (a,b,i)=>a.replace(/\d/g,c=>+c?b[++i]||b[i=0]:' ') \$\endgroup\$ – ETHproductions Nov 14 '16 at 15:54
  • \$\begingroup\$ I think that will start at the second character of the string. A snippet update would be nice. \$\endgroup\$ – Titus Nov 14 '16 at 16:22
  • 1
    \$\begingroup\$ @Titus At first, i is undefined, so ++i returns NaN. Since b has no NaN property, b[++i] returns undefined, and the || operator runs its right-side argument, setting i to 0 and returning the first char in b. \$\endgroup\$ – ETHproductions Nov 14 '16 at 16:39
  • 1
    \$\begingroup\$ Why are you testing for \d? Surely . suffices, since you only have to deal with 0s and 1s (. doesn't match newlines). \$\endgroup\$ – Neil Nov 15 '16 at 1:44
5
\$\begingroup\$

Perl, 40 bytes

36 bytes of code + -i -p flags.

@F=$^I=~/./g;s/1/$F[$i++%@F]/g;y;0; 

(note the final space and the lack of final newline).

To run it, write the input string after -i flag, and supply the matrix in the input :

perl -iPPCGPPCG -pe '@F=$^I=~/./g;s/1/$F[$i++%@F]/g;y;0; ' <<< "00100
01010
10001
01010
00100"

If your Perl is a bit old, you might need to add a final semicolon (after the space).

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

Python 2, 114 71 bytes

Turns out I was re-inventing the wheel, a simple double replace on a multiline string works quite well. The string has the additional benefit of being able to count zeros directly rather than having to do the really ugly s*len(L)*len(L[0]) for a nested list

lambda S,s:S.replace("0"," ").replace("1","{}").format(*s*S.count('0'))

Old solution:

lambda s,L:"\n".join(["".join(map(lambda n:chr(n+32),l)).replace("!","{}")for l in L]).format(*s*len(L)*len(L[0]))

First we convert everything + 32 with chr (all zeros become spaces), then we replace all of the ! with {} to allow using the format function.

If NULL can be counted as a space If I decide to cheat and use NULL instead of space, I can skip the addition of 32 to save 12 bytes. (print displays '\x00' as a space)

lambda s,L:"\n".join(["".join(map(chr,l)).replace('\x01','{}')for l in L]).format(*s*len(L)*len(L[0]))
\$\endgroup\$
  • \$\begingroup\$ Wouldn't it be shorter to use the NULLs, and replace them with space at the end? \$\endgroup\$ – nedla2004 Nov 15 '16 at 12:53
  • \$\begingroup\$ @nedla2004, How do you suggest I do that? Just adding a .replace('\x00',' ') on the end adds 20 bytes \$\endgroup\$ – wnnmaw Nov 15 '16 at 14:04
  • \$\begingroup\$ But then I think you could get rid of this: map(lambda n:chr(n+32),l) \$\endgroup\$ – nedla2004 Nov 15 '16 at 14:10
  • \$\begingroup\$ The second solution works with NULLs the whole time, which saves me 12 bytes, swapping to spaces at the end will cost me more than that \$\endgroup\$ – wnnmaw Nov 15 '16 at 14:11
  • \$\begingroup\$ I thought you could remove more than you actually can. \$\endgroup\$ – nedla2004 Nov 16 '16 at 1:32
3
\$\begingroup\$

APL, 18 bytes

{(⍴⍺)⍴X\⍵⍴⍨+/X←,⍺}

This is a function that takes a boolean matrix as its left argument and a string as its right argument.

      (↑(1 0 0)(0 1 0)(1 0 1)) {(⍴⍺)⍴X\⍵⍴⍨+/X←,⍺}'lambda'
l  
 a 
m b

Explanation:

APL has a built-in that does something like this, \ (expand). However, it only works on vectors, and it requires each character to be actually used.

  • X←,⍺: flatten the matrix and store the result in X.
  • ⍵⍴⍨+/X: reshape the character vector so that it has the required amount of elements (this also takes care of lengthening the string by repeating characters if necessary).
  • X\: take one of the characters for each 1 and a space for each 0 in X.
  • (⍴⍺)⍴: reshape the result so that it has the shape of the original matrix.
\$\endgroup\$
3
\$\begingroup\$

PHP, 110 91 97 88 82 81 80 75 bytes

saved 6 bytes thanks to @user59178

while(""<$c=$argv[1][$i++])echo$c<1?$c?:" ":($s=$argv[2])[$k++%strlen($s)];

Run with -r. Expects matrix as multiline string in first argument, string in second argument.

\$\endgroup\$
  • 1
    \$\begingroup\$ An 80 byte version based on your 82 bytes version: foreach(str_split($argv[1])as$c)echo$c<1?$c?:" ":($s=$argv[2])[$k++%strlen($s)]; I swapped the order of the two ternaries and thus dropped the brackets from the second by using <1 rather than >0 \$\endgroup\$ – user59178 Nov 14 '16 at 16:27
  • 1
    \$\begingroup\$ you could save 4 bytes by using for(;""!=$c=$argv[1][$i++];) instead of the foreach(...) \$\endgroup\$ – user59178 Nov 14 '16 at 17:30
3
\$\begingroup\$

PowerShell v2+, 70 bytes

param($a,$b)$b|%{-join($_|%{if($_){$a[$n++];$n%=$a.length}else{' '}})}

Takes input word as $a and the matrix as an array-of-arrays as $b (see examples below). Loops through $b, then loops through the elements of each row $_|%{...}. Inner loop is an if/else condition, where we either output $a[$n++] and take mod-equal to the length of the string, or output a space ' '. Those are -joined together back into a string. Each of the strings is left on the pipeline, and implicit output with newlines between happens via Write-Output at program completion.

PS C:\Tools\Scripts\golfing> .\the-art-of-word-shaping.ps1 'PPCGPPCG' @(@(0,0,1,0,0),@(0,1,0,1,0),@(1,0,0,0,1),@(0,1,0,1,0),@(0,0,1,0,0))
  P  
 P C 
G   P
 P C 
  G  

PS C:\Tools\Scripts\golfing> .\the-art-of-word-shaping.ps1 'lambda' @(@(1,0,0),@(0,1,0),@(1,0,1))
l  
 a 
m b

PS C:\Tools\Scripts\golfing> .\the-art-of-word-shaping.ps1 'PPCG' @(@(1,1,1),@(1,0,1),@(1,1,1))
PPC
G P
PCG
\$\endgroup\$
2
\$\begingroup\$

Groovy, 63

{a,b->i=0;a.replaceAll("1",{b[i++%b.size()]}).replace("0"," ")}
\$\endgroup\$
2
\$\begingroup\$

Python 3, 104 (or 83) Bytes

import itertools as i
def f(s,L):s=i.cycle(s);return'\n'.join(' '.join(next(s)*e for e in l)for l in L)

There is shorter option (83 Bytes), but it will fail if string is more than 999 times shorter than needed:

def f(s,L):s=list(s)*999;return'\n'.join(' '.join(s.pop(0)*e for e in l)for l in L)
\$\endgroup\$
  • \$\begingroup\$ Second solution doesn't work for me, because you can't call next on a list. If you do s=iter(list(s)*999) it does (89 bytes) \$\endgroup\$ – L3viathan Nov 15 '16 at 11:38
  • 1
    \$\begingroup\$ @L3viathan sorry, I meant it to be s.pop(0). Seems that I copied wrong version, fixed that. \$\endgroup\$ – Alissa Nov 15 '16 at 12:36
  • \$\begingroup\$ s[i++%s.length()] is a good methodology, though I don't know python. \$\endgroup\$ – Magic Octopus Urn Nov 15 '16 at 20:01
  • \$\begingroup\$ It would be cool, but there is no such thing as i++ in Python \$\endgroup\$ – Alissa Nov 16 '16 at 12:19
1
\$\begingroup\$

Pyth, 12 bytes

jms?R@z~hZ\ 

Try it online: Demonstration

Explanation:

jms?R@z~hZ\ dQ   implicit d and Q at the end
                 I use the variable Z, which is initialized with 0 by default
 m           Q   map each line d of the Q (input matrix) to:
   ?R       d       map each number d of the line either to
     @z~hZ             input[Z++] (increase Z, but lookup in input string with old value)
          \            or space
  s                 join chars to a string
j                print each string on a separate line
\$\endgroup\$
1
\$\begingroup\$

ES6, 78 bytes

  (a,b,x=0)=>(b.map(r=>r.map(i=>i?a[x++%a.length]:' ')+'\n')+'').replace(/,/g,'')

I tried

\$\endgroup\$
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ – Erik the Outgolfer Nov 15 '16 at 14:04
1
\$\begingroup\$

Common Lisp, 152 bytes

(defun m(g w)(let((a 0))(loop for r in g do(loop for e in r do(format t"~[ ~;~c~]"e(char w a))(if(= e 1)(setf a(mod(1+ a)(length w)))))(format t"~%"))))

Usage:

* (m (list (list 1 0 1)
           (list 0 1 0)
           (list 1 0 1)) "ppcg")
p p
 c 
g p

This function loops through each element of each row of the grid. The format control string either prints a space if the element is a 0 or consumes the character argument if the element is 1. A newline gets printed after every row of the grid. If the string is too short, it repeats from the beginning; if it's too long, only the appropriate part gets outputted.

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

Pip, 18 bytes

17 bytes of code, +1 for -l flag.

Yb{a?y@++vs}MMa^s

Takes the array as the first command-line argument like this: 100 010 101 (needs to be quoted in shells) and the string as the second command-line argument. Try it online!

Explanation

                   a and b are cmdline args, s is space, v is -1
Yb                 Yank b into global variable y
              a^s  Split a on space into list of rows
  {        }MM     Map this function to the items of the items of a (i.e. each character):
   a               Function argument
    ?              Ternary operator (truthy if 1, falsey if 0)
       ++v         If truthy, increment v...
     y@            ... and use it to index into y (cyclically)
                   I.e.: each time we hit a 1, replace it with the next character of y
          s        If falsey, space
                   The result is a list of lists of characters; -l concats sublists and
                   newline-separates the main list
\$\endgroup\$
1
\$\begingroup\$

Java, 237 233 Bytes

Edit: saved 4 Bytes thanks to Mukul Kumar

Golfed:

String T(int[][]m,String b){int l=m.length,a=0;String o="";for(int i=0;i<l;i++){for(int j=0;j<l;j++){if(m[i][j]==1&&a<b.length()){o+=Character.toString(b.toCharArray()[a]);a++;if(a== b.length()-1)a=0;}else o+=" ";}o+="\n";}return o;}

Ungolfed:

public String T(int[][] m, String b) {
    int l = m.length,a=0;
    String o = "";
    for(int i = 0; i < l; i++)
    {
        for(int j = 0; j < l; j++)
        {
            if(m[i][j] == 1 && a < b.length())
            {
                o += Character.toString(b.toCharArray()[a]);
                a++;

                if(a == b.length() - 1)
                    a = 0;
            }
            else
             o += " ";
        }
        o += "\n";
    }
    return o;
}

Testing:

  int[][] matrix = new int[][]
  {{ 0, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0 },
  { 1, 0, 0, 0, 1 },{ 0, 1, 0, 1, 0 },
  { 0, 0, 1, 0, 0 },};
  TheArtOfWordShaping taows = new TheArtOfWordShaping();
  System.out.println(taows.T(matrix, "PPCGPPCG"));

  matrix = new int[][] {{1,0,0}, {0,1,0}, {1,0, 1}};
  taows = new TheArtOfWordShaping();
  System.out.println(taows.T(matrix, "lamda"));

  matrix = new int[][] {{1,1,1},{1,0,1},{1,1, 1}};
  taows = new TheArtOfWordShaping();
  System.out.println(taows.T(matrix, "PPCG"));

  P  
 P C 
G   P
 P C 
  P  

l  
 a 
m d

PPC
P P
CPP
\$\endgroup\$
  • \$\begingroup\$ You can declare all int in one line..... \$\endgroup\$ – Mukul Kumar Nov 15 '16 at 5:17
1
\$\begingroup\$

Pyke, 12 bytes

.FdRIKQoQl%@

Try it here!

Outputs a matrix of characters

Or 9 bytes, noncompetitive.

.FdRIKQo@

Try it here!

  • Add wrapping on indexables where the index asked for is bigger than the length of the indexable. ​ .F - deep_for(input) I - if ^: Qo@ - Q[o++] dR - else " "

Even more noncompetitive, 8 bytes

.FIQo@(P

Try it here!

  • print_grid now aligns empty strings properly
  • deep_for now does type-guessing on falsies of a different type to the truthies

.F    (  -  deep_for(input)
 I       -   if ^:
  Qo@    -    input[o++]
       P - pretty_print(^)
\$\endgroup\$
1
\$\begingroup\$

Java,122 bytes

String g(int[][]a,char[]b){String r="";int e=0;for(int[]c:a){for(int d:c){r+=d==0?' ':b[e++%b.length];}r+='\n';}return r;}
\$\endgroup\$
0
\$\begingroup\$

Mathematica, 76 bytes

""<>(s=#2;f:=(s=RotateLeft[s];Last[s]);Map[If[#1,f," "]&,#,{2}]~Riffle~"\n")&

Unnamed function of two arguments, the first of which (#) is an array of Trues and Falses, and the second of which (s) is a list of characters. The helper function

f:=(s=RotateLeft[s];Last[s])

is defined, which puts the moves the first character of s to the end and then returns that just-moved character. Calling f several times will cyclically return the characters of s in order.

The core function is

Map[If[#1,f," "]&,#,{2}]

which calls f on every True value in the input array and returns a space on every false input. (The {2} tells Map to work on elements of the array's component lists, rather than those lists themselves.)

Those 60 bytes return an array of characters-of-s and spaces. The wrapper

    ""<>(...~Riffle~"\n")&

puts newlines between each of that array's lists and then concatenates everything.

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

C++, 61 bytes

for(auto&i:m){for(int&j:i)cout<<(j?s[k++%l]:' ');cout<<'\n';}
\$\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.