# *Overwrit*labels

If you've ever tried adding labels to a really dense plot, then you'll realise that sometimes labels will overlap one another, making them hard to read. We're going to do something similar but in 1D.

Input will be a sequence of (label, x-coordinate) pairs, and output will be the result of drawing each point and label, in the given order. An asterisk * representing the point should be placed at the given x-coordinate and the label should follow. Any existing characters will be overwritten.

For instance, if the input was

Hello  0
World  8
Fizz   3
Buzz   5
PPCG   16
X      9


Then the following would happen:

*Hello
*Hello  *World
*He*Fizz*World
*He*F*Buzzorld
*He*F*Buzzorld  *PPCG
*He*F*Buz*Xrld  *PPCG


The final line should then be outputted.

## I/O rules

• Input may consist of any number of pairs. Each label will only consist of uppercase and lowercase letters, and label lengths will be at most 127 chars. Each x-coordinate will be between 0 and 127 inclusive.

• Input may be in any convenient list or string format such that the pairs are unambiguous and labels/x-coordinates alternate in the input. For example, a format like [("Hello", 0), ("World", 8) ...] or [0 "Hello" 8 "World" ...] is fine. However, you may not assume two separate lists of labels and x-coordinates.

• Functions and full programs are both okay.

• Any spots not covered by a label should be represented with a space. However, there may not be any extraneous leading or trailing whitespace aside from a single optional trailing newline.

## Examples

Input:

OneLabel   10


Output:

          *OneLabel


Input:

Heathrow   0
Edinburgh  2
London     4
Liverpool  6
Oxford     8


Output:

*H*E*L*L*Oxfordl


Input:

alpha     20
beta       4
gamma     57
delta      3
epsilon   22
zeta      32
eta       53
theta     27


Output:

   *delta           *a*epsi*thetazeta                *eta*gamma


Input:

abc  5
d    5
abc  10
ABCDEFGHIJKLMNOPQRSTUVWXYZ 127


Output:

     *dbc *abc                                                                                                                 *ABCDEFGHIJKLMNOPQRSTUVWXYZ


Note that labels and/or x-coordinates may be repeated.

• If the x coords are [0,127] and the strings are (0,127], can a label run off the far right end of the line, or is it protected? That is, does "foo 127" end the line with "*" or "*foo"? Just checking if the string should have a soft or hard ending. – PotatoOmeletteSandwich Oct 19 '15 at 13:25
• @PotatoOmeletteSandwich My intention was so that the total length fits within 255, so the maximal output length will occur when there is a length 127 label at x-coordinate 127. The final output should not be truncated in any way, except to remove trailing whitespace. – Sp3000 Oct 19 '15 at 13:28

# CJam, 2423 19 bytes

l~Sf.*'*f*:.{S^+1=}


This reads the input as a CJam array of coordinate-label pairs.

Try this fiddle in the CJam interpreter or verify all test cases at once.

Thanks to @MartinBüttner for helping me save 4 bytes!

### How it works

l~                   Read a line from STDIN and evaluate it.
Sf                 For each pair, push the pair and " "; then:
.*                 Perform vectorized repetition.
[X "label"] " " .* -> [(X spaces) "label"]
'*f*           Join each resulting pair, using '*' as separator.
:.{     }  Reduce by the following vectorized operator:
Push two characters (A and B).
S^        Compute the symmetric difference of B and " ".
This pushes "B " for a non-space B and "" otherwise.
+1=    Append and select the second character (with wrap).
This selects B for "AB " and A for "A".

• I just added a test case and thought I'd leave a comment saying that no, it didn't break this submission - CJam's interpreter output just word wraps. Just in case anybody gets confused. – Sp3000 Oct 19 '15 at 13:37

# Pyth, 20 bytes

V.Tmrj" *"d9Qpe+d-Nd


Try it online: Demonstration or Test Suite

### Explanation

V.Tmrj" *"d9Qpe+d-Nd
m        Q         map each pair d of the input to:
j" *"d             join d by the string " *"
r      9            range-length encode
(this gives x-coordinate spaces, a star and the label)
.T                   transpose this table
V                     for N in ^:
-Nd    remove spaces from N
+d       add a space at the beginning
e         take the last character
p          and print it (without newline)

• This is way better than what I had. – isaacg Oct 19 '15 at 20:43

# JavaScript ES6, 104 bytes

c=>(a=Array(255).fill(" "))&&c.map(([u,v])=>a.splice(u,v.length+1,..."*"+v))&&a.join.replace(/ +$/,"")  ## Example Usage Input into a compliant console: t = [[0,"Hello"],[8,"World"],[3,"Fizz"],[5,"Buzz"],[16,"PPCG"],[9,"X"]]; (c=>(a=Array(255).fill(" "))&&c.map(([u,v])=>a.splice(u,v.length+1,..."*"+v))&&a.join.replace(/ +$/,""))(t);


Output from the last statement:

"*He*F*Buz*Xrld  *PPCG"


## Explanation

This creates an anonymous function from c to three expressions that have been logically-ANDed together. The first two statements are always truthy, and the JS short-circuit rules say that whenever the first is truthy, return the entire value on the right hand side (without coercing to boolean): so this is formally equivalent to

(function (c) {
a = Array(255).fill(" ");                    // global variable a overwritten
c.map(function (x) {                         // only side-effects are used here.
var u = x[0], v = x[1];                   // ES6 destructuring
a.splice(u, v.length + 1, ..."*" + v));   // main logic
});
return a.join("").replace(/ +$/, ""); // postprocessing and trim })  The first statement has to be wrapped in parentheses above because the assignment operator = has lower precedence than the logical-AND operator &&. The "rest parameter" assembly ..."*"+v is also part of ES6; it concatenates a leading * to the string and then interprets it as a list-like parameter, splitting it into a bunch of arguments which are provided to Array.prototype.splice, which takes (m, n, ...rest) and modifies its array at position m to remove n elements and then insert all of the rest arguments. To accomplish this before ES6 you would use the more cumbersome: [].slice.apply(a, [u, v.length + 1].concat(("*" + v).split("")))  The array then gets concatenated with the empty string and trailing whitespace is deleted. ## Python 2, 67 bytes z='' for a,b in input():z=(z+' '*b)[:b]+'*'+a+z[len(a)-~b:] print z  Takes input like [('Heathrow', 0), ('Edinburgh', 2), ('London', 4), ('Liverpool', 6), ('Oxford', 8)] and prints the result. Python doesn't allow strings to be modified, and converting to and from a list is expensive. So, this recreates the string z to add in a new word. We take the b characters before the word, padding with spaces if needed, then the new text with an asterisk, then the part of z after the new word. Note that trailing spaces are never added. The reduce version is 3 chars longer (70): lambda I:reduce(lambda z,(a,b):(z+' '*b)[:b]+'*'+a+z[len(a)-~b:],I,"")  # Ruby, 9481 75 bytes Golfed: s=" "*128;$<.map{|l|w,p=l.split;p=p.to_i;s[p..w.size+p]="*"+w};$><<s.rstrip  Here's the ungolfed code: s = " "*128$<.map{|l|                 # for each line entered via stdin, ctrl+D to stop
w,p = l.split            # had to move the chomp down here
p = p.to_i               # there's no 'to_i!'...
s[p..w.size+p] = "*"+w   # in the range of *foobar, replace the string
}
$><<s.rstrip # output suggested by w0lf  Thanks @w0lf for the suggestions on mapping the input! Thanks @w0lf and @Not that Charles for the thought on removing a variable. • See the Ruby golfing tips. In this case you could apply the$<.map{|l|...} is shorter than while l=gets;...;end tip and probably replace puts  with $><< (which does not require the extra space). – Cristian Lupascu Oct 19 '15 at 14:25 • also, I think .chomp can be removed. – Cristian Lupascu Oct 19 '15 at 14:32 • In this case, now that you mention it, I think it's likely very safe to remove, as .to_i will catch that. Good thought. Thanks @w0lf! – PotatoOmeletteSandwich Oct 19 '15 at 14:34 • You're welcome! Here's a shorter version in which I applied the tips above and a few more: ideone.com/BiOvV5. Feel free to post it in your answer if you like it. – Cristian Lupascu Oct 19 '15 at 14:38 • @PotatoOmeletteSandwich Upgrade your Ruby. 1.8.7 is end-of-lifed! also, you should be able to use the s[int, int] form instead of s[range] for 1 char savings. – Not that Charles Oct 19 '15 at 16:04 # Javascript 121 chars Using non-standard features, works on Firefox. x=Array(255).fill(" ");eval(prompt()).map(s=>{s[0].split.map((n,i)=>x[s[1]+i+1]=n);x[s[1]]="*"});x=x.join.trimRight() Older version: x=Array(255).fill(" ");eval(prompt()).map(s=>{s[0].split.map((n,i)=>x[s[1]+i+1]=n);x[s[1]]="*"});x=x.join.replace(/ +$/,"")

x=Array(255).fill(" ");      //Creates an array with spaces
eval(prompt())               //Gets some input, has to look like [["Hello",4],["Hi",14],["Oi",0]]
.map(s=>{s[0].split.map((n,i)=>x[s[1]+i+1]=n);x[s[1]]="*"}); //Main "logic"
x=x.join.replace(/ +$/,"") //Gets rid of the trailing spaces  • / +/  makes much more sense than \s disappointed I missed that! Could you save bytes using x=' '.repeat(255); and avoiding the .join? – Dom Hastings Oct 19 '15 at 19:21 • @DomHastings: JS strings are immutable so you would have to .split('') it into a mutable data structure, but at that point Array(255).fill(' ') is shorter. In my version most of my savings come from (a) using the "you can give either a function or program" rule to delete eval(prompt()) in exchange for c=> and (b) using the builtin Array.prototype.slice method with a rest parameter to shorten the logic part a little bit. – CR Drost Oct 19 '15 at 20:07 • @ChrisDrost ah of course... I forget it's just an accessor! Shame[].map.call(s[0], doesn't save any either... – Dom Hastings Oct 19 '15 at 20:24 ## Python, 85 bytes def g(p): z=[' ']*256 for a,b in p:z[b:b+len(a)+1]='*'+a return''.join(z).rstrip()  Try it online • You should be able to do 'z'[2::5] (backticks instead of apostrophes) instead of ''.join(z) to save one byte, and moving z=[' ']*256 to the parameters should save another. Also, I think you can change return to print. – Kade Oct 19 '15 at 15:59 • I think you can save chars by writing a program with p=input() (Python 2) rather than a function, which avoids indentation. Also, b+len(a)+1 can be b-~len(a) – xnor Oct 19 '15 at 19:27 • Actually, a program just lets you do for a,b in input():. – xnor Oct 19 '15 at 19:41 ## Perl, 66 bytes 63 bytes script + 3 bytes for -p $}||=$"x128;/\s+/,substr$},$',1+length$,"*$"}{$_=$};s/\s+$/
/


Nothing too special, utilising the variables $ and $' which are 'before the match' and 'after the match' respectively, instead of splitting the string. I used a $} for the string variable as originally it was saving me a byte, but isn't any more! ### Example run: $perl -p overwritlabels.pl <<< 'Hello  0
World  8
Fizz   3
Buzz   5
PPCG   16
X      9'
*He*F*Buz*Xrld  *PPCG


## Perl, 65 bytes

62 bytes script + 3 bytes for -p

Another version that prints out each line (for one less byte!). (Yes, I made this because I didn't read the question properly...)

$}||=$"x128;/\s+/;substr$},$',1+length$,"*$";$_=$};s/\s+$/ /  ### Example run: $perl -p overwritlabels.pl <<< 'Hello  0
World  8
Fizz   3
Buzz   5
PPCG   16
X      9'
*Hello
*Hello  *World
*He*Fizz*World
*He*F*Buzzorld
*He*F*Buzzorld  *PPCG
*He*F*Buz*Xrld  *PPCG


# PHP -- 84 bytes

<? foreach(array_chunk(array_slice($argv,1),2) as$p) echo "␣[".($p[1]+1)."G*$p[0]";
^ ESC character (\x1b)


Uses ANSI escape codes to position the cursor (\x1b[XG, featuring the Escape character and X being the 1-based coordinate), followed by the * then the input string for that row. Accepts input on the command line of the form:

php filename.php Heathrow 0 Edinburgh 2 London 4 Liverpool 6 Oxford 8
php filename.php abc 5 d 5 abc 10 ABCDEFGHIJKLMNOPQRSTUVWXYZ 127


Accepts multi-word entries if they're in quotes, since they're command line arguments.

# C++11, 95 bytes

Why not?

As a function, receive input as a map<int, string> named v containing the position and the string.

string t(255,' ');for(auto&m:v){int i=m.first;t[i++]='*';for(auto&c:m.second)t[i++]=c;}cout<<t;


Usage

#include <iostream>
#include <map>
using namespace std;
int main(){
map<int,string> v{{0,"Heathrow"},{2,"Edinburgh"},{4,"London"},{6,"Liverpool"},{8,"Oxford"}};
string t(255,' ');for(auto&m:v){int i=m.first;t[i++]='*';for(auto&c:m.second)t[i++]=c;}cout<<t;
}
`

Check it Running Here