Linear combination of two vectors
MATL, 48 bytes
tZyyX:UX>*Yat48-tt0>*3#fbbhb~2#fh-*s7M+'X'wZ}4$(
The background character is space. Input is a 2D char array with rows separated by semicolons. So the tests cases have respective inputs:
[' 2'; ' 0 '; ' 3 ']
[' 1 '; ' '; '1 0']
['0 1 1']
[' 2 0 1 ']
[' 3'; ' '; ' 0 '; ' '; ' '; '2 ']
['90'; ' 8']
The output includes a significant amount of padding whitespace.
Try it online!
Python 3, 374 355 bytes
Not too refined python solution that is very generous with padding (uses maximum chessboard distance). Input is a single line where rows are separated with pipes | (although the algorithm can easily use anything not alphanumerical that isn't a newline or a EOF). Anything non alphanumeric or | works for input padding, output padding uses periods. Feedback and improvement from more seasoned python golfers is appreciated.
Edit: Some improvements thanks to @TheBikingViking. Also added even more margins since I wasn't quite generous enough with padding.
s=input()
l=[len(s),1+s.find('|')]['|'in s]
P=sorted([int(c),i%l,i//l]for i,c in enumerate(s)if c.isalnum())
L=X=Y=0
P[0][0]=-sum(p[0]for p in P)
for w,x,y in P:L=max(abs(x),abs(y),L);X+=x*w;Y+=y*w
P+=[['X',P[0][1]+X,P[0][2]+Y]]
P[0][0]=0
L=2*max(abs(X),abs(Y),L)
S=[2*L*["."]for _ in[0]*2*L]
for w,x,y in P:S[L+y][L+x]=str(w)
for s in S:print(''.join(s))
JavaScript, 534 528 502 bytes
n="indexOf"
J="join"
B=X=>X.split(O)
O='\n'
w=i[n](O)+1
h=B(i).length
Z=(X,Y,R)=>{C[R]+=X-1;return Array(X)[J](Y)}
C=[0,0,0]
G=(X,E,T,U,R)=>X>0&E>=0?Z(X+E+1+T,U,R):""
o=i[n]("0")
L=X=>Math.floor(X/(w-1))
l=L(o)
c=o%w
x=y=0
j=i
for(z="1";z<="9";z++){while(p=~j[n](z)){j=j.replace(z," ")
x+=~p%w-l
y+=L(~p)-c}}
I=B(i).map(X=>G(-x,-l,0," ",0)+X+G(x,l-w+2,0," ",2))
N=Z(I[0].length+1," ",2)
A=B(G(-y,-c,0,N+O,1)+I[J](O)+G(y,c-h,1,O+N,2))
M=y+c+C[1]
O=""
m=B(A[M])
m[x+l+C[0]/h]="x"
A[M]=m[J]("")
A[J]("\n")
Note that the padding is optimal. This program assumes that i contains the raw string, with the lines separated by \n
characters. The padding is done with spaces, and the result character is a lowercase x
.
This is my first attempt at code-golfing.
Technical stuff: - The program's size roughly doubled (and its complexity went up dramatically) to just take into account the result character, mostly because JavaScript strings are immutable.
Line by line explanation:
n="indexOf"
J="join"
B=X=>X.split(O)
I use those a lot, so storing them in strings saved me some space. You can see below that for the split
function, I have simply created an alias; this is because I only needed one argument, the other one being constant. For indexOf
and join
, it would however have been longer.
O='\n'
w=i[n](O)+1
h=B(i).length
Nothing complicated here, I'm reading the width and height of the initial array. Note the use of i[n]
to access indexOf
, while split
is handled differently.
Z=(X,Y,R)=>{C[R]+=X-1;return Array(X)[J](Y)}
This is getting interesting. This function basically creates concatenates J-1 times the string X and returns it. This is used to generate strings of spaces for the padding.
C=[0,0,0]
This array will contain the number of lines and columns added by the padding (off by a factor h in the first case). The last cell is a junk one, and prevents me from having an additional argument in the function below.
G=(X,E,T,U,R)=>X>0&E>=0?Z(X+E+1+T,U,R):""
This function alone handles the padding (both lines and columns); it determines, based on a coordinate of the result vector (X), and the number of lines/columns to generate (E), whether it is necessary to create one. the X+E+1+T
is just a trick to save some space, U
is the filling string (a space for columns, and an entire line for lines), and we'll come back to R
. This function basically returns, in the case of a line, the padding required at the beginning or the end of said line, and, in the case of a column, it returns the padding lines required either before or after the original lines.
o=i[n]("0")
L=X=>Math.floor(X/(w-1))
l=L(o)
c=o%w
Here we read the position of the origin, and we retrieve its coordinates. L is a function to convert an index into a line number.
x=y=0
j=i
for(z="1";z<="9";z++){
while(p=~j[n](z)){
j=j.replace(z," ")
x+=~p%w-l
y+=L(~p)-c
}
}
I added some whitespace to make this easier to read. What happens here is that for each possible number, we keep looking for it in the original string. The ~
trick is relatively common in Javascript; it is the bitwise NOT operator, but all that matters here is that ~-1==0
, which allows me to test for the end of the loop. I then erase the character in the string (which is why I made a copy), this allowing me to continue the search as long as needed. I then add the coordinates of the vector to (x, y)
, using a simple substraction.
I=B(i).map(X=>G(-x,-l,0," ",0)+X+G(x,l-w+2,0," ",2))
I here split the original string into lines, and for each line, I call G
which will generate the padding before and after the lines. The l-w+2
and so on come from a simple index calculation which allows me to test whether I need to add padding or not. For example, if x>0
and x+l-w+1>0
, then (x+l-w+1)+1
spaces must be added after the line. The +x
is being removed due to it being the first parameter, and the X+E+1+T
used in the definition of G
.
A similar thing is done for the first characters, and then for the columns. There is a lot of factorization here allowing me to use only one function. Note the last parameter; in the first case, I want to write to C[0]
to be able to know later how many columns I added at the beginning of each line; this allows me to retrieve the final position of the result character. I do however not care about the columns added after the original line, which is why the second call to G
writes to the junk cell C[2]
which is unused.
N=Z(I[0].length+1," ",2)
Here I simply read the new length of the lines, and create a line of spaces from it. This will be used to create the vertical padding.
A=B(G(-y,-c,0,N+O,1)+I[J](O)+G(y,c-h,1,O+N,2))
This is exactly the same as two lines above. The only difference is writing to C[1]
this time, and using the separators N+O
and O+N
. Remember that O
is a newline, and N
is a line of spaces. I then apply B
on the result to split it again (I need to retrieve the line containing the result character to edit it).
M=y+c+C[1]
This is the vertical index of the resulting character.
O=""
m=B(A[M])
m[x+l+C[0]/h]="x"
Here I am forced to modify O
to be able to split the appropriate line into an array of characters. This is because JavaScript strings are immutable; the only way to edit a string is to convert it into an array (which is what I'm doing here), edit at the right position, and join the string again. Also note the h
factor, which is because the G
function was called once per initial line.
A[M]=m[J]("")
A[J]("\n")
I finally replace the new string in the array, and join it again into a string. Woohoo!