# Will you be my Weaver?

I've been recently playing through 'The Weaver' and I think it presents an interesting challenge for .

# Premise:

The Weaver is a game wherein you are given a number of ribbons coming from 2 directions 90 degrees apart and your goal is to swap them at certain intersections to achieve a desired output.

Like this:         This is a swap:         This isn't:

# Input:

3 arrays:

• Top ribbons (left to right)
• Left ribbons (top to bottom)
• The coordinates of the intersections to swap

# Output:

2 arrays:

• Bottom ribbons (left to right)
• Right ribbons (top to bottom)

# Examples:

I'll use the above image as the first example:

Input: [r, y, b], [r, y, b], [(0, 1), (2, 1), (2, 2)]

What happens:

   r   y   b
r   y   b
r r r r•y y y y
r   r   b
y y y y y y y y
r   r   b
b b b b•r r•b b
r   b   r
r   b   r


Where • represents a swap.

Output: [r, b, r], [y, y, b]

Input: [a, b, c], [d, e, f], [(0, 0), (2, 1)]

What happens:

   a   b   c
a   b   c
d d•a a a a a a
d   b   c
e e e e e e e e
d   b   c
f f f f•b b b b
d   f   c
d   f   c


Output: [d, f, c], [a, e, b]

Input: [a, b], [a, b, c], [(0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 1)]

What happens:

   a   b
a   b
a a a a•b b
a   a
b b•a a•a a
b   a
c c•b b•a a
c   b
c   b


Output: [c, b], [b, a, a]

# Notes:

• The examples show coordinates given as (row, column) though you may take them as (column, row).
• The top row and left column may have ribbons of the same color
• The board can be rectangular
• All coordinates will be non-negative (>=0) (or strictly positive (>=1) if you choose 1-indexing)
• Ignore any swaps that are outside the board
• You may choose to work with letters ([a-zA-Z]), integers ([0-9]) or both
• The ribbons in your output must match the ribbons in the input exactly (a -> a)
• You may assume the list of swaps is sorted in any way you want, as long as it's consistent (if you do, please specify how it should be sorted)
• You may take the swap coordinates as 0 or 1-indexed
• Default loopholes are forbidden

# More examples:

Input:
[b], [r], []
Output:
[b], [r]

Input:
[b], [r], [(0, 0)]
Output:
[r], [b]

Input:
[r, p, y], [r, y, p], [(0, 0), (1, 2), (2, 1), (3, 2)]
Output:
[r, p, y], [r, y, p]

Input:
[b, y, o, r],
[r, o, b, y],
[(0, 0), (2, 0), (3, 2)]
Output:
[b, y, y, r],
[b, o, r, o]


The last example relates to this case (if that makes it easier to visualize):

This is so the shortest answer in bytes for each language wins.

• Re "Ignore any swaps that are outside the board" - does that mean we cannot assume that all swap coordinates are on the board, and we need to filter them for validity (ignore the invalid ones), or does that mean that we can ignore the case of coordinates being outside of the board because the input will always be valid? – Bergi Apr 19 '18 at 21:05
• @Bergi it means that the input may include swaps outside the board and you have to filter or ignore them. (The 3rd example includes such a swap) – Asone Tuhid Apr 19 '18 at 21:10
• Oh. I think the challenge would have been more interesting if the swaps would only have had valid coordinates, but that we could not assume they were sorted in an order that fits our solution. – Bergi Apr 19 '18 at 21:13
• @Bergi You're probably right, well, it's too late to change now. And no, all coordinates will be positive, I'll update the question. – Asone Tuhid Apr 19 '18 at 21:34
• @AsoneTuhid If coords are (row,col), it makes more sense to i/o the left ribbons first and the top ribbons second. Is that allowed? – ngn Apr 23 '18 at 5:27

# Python 3, 74 bytes

def g(a,b,l):
for x,y in l:
if x<len(a)and y<len(b):a[x],b[y]=b[y],a[x]


Try it online!

Requires l to be sorted in lexicographical order. a and b are lists of characters representing (left ribbon, top ribbon).

Returns by modifying the list a and b.

# Jelly, 3735 30 bytes

ṙ"z0U1¦Zḟ€0ṙ"N}
<Ạ¥ÐfL€}⁹ṭṚç/Y


Try it online!

Dyadic program, take 0-indexing list of swap indices as left argument (sorted in reverse lexicographical order) and (left ribbon, top ribbon) as right argument. Returns (right ribbon, bottom ribbon).

Jelly is a tacit language. There is (almost) no variable to work with, so doing anything involves more than two variables at once is a mess.

The first link takes [l,t] as its left argument, [x,y] (0-indexing) as its right argument, and return [l,t] with l[x] and r[y] exchanged.

ṙ"z0U1¦Zḟ€0ṙ"N}
ṙ"               Zipwith rotate. Current value: [l ṙ x, t ṙ y]
(so l[x] and r[x] becomes l[0] and r[0] respectively)
z0             Zip, fill with 0. Elements at corresponding (new) indices are
paired together, with 0 as the filler.
U1¦          Reverse the pair at index 1 (first index).
Zḟ€0      Zip again and filter out the 0s, effectively undo the z0.
ṙ"N}  Zipwith rotate by negative shift amount, reverse of ṙ".


So basically "U1¦ under ṙ"z0".

The second link simply filter out OoB indices (<Ạ¥Ðf L€), append the second argument (⁹ṭ), reverse (Ṛ), and reduce over ç (similar to Haskell's foldl)

# Python 2, 193 bytes

def f(t,l,s):
m=[[x,y]for y in[0]+l for x in[0]+t];L=len(t)+1
for i in range(len(m)):
if i%L:m[i]=[m[i-L][0],m[i-1][1]][::[1,-1][(i/L,i%L)in s]]
s=sum(m,[]);print s[2-L*2::2],s[4*L-1::2*L]


Try it online!

Takes 1-indexed swap coordinates

# APL (Dyalog Classic), 31 30 bytes

{⊃{⌽@(0 1,¨⍺)⊢⍵}/(⍵∩,⍳≢¨⍺),⊂⍺}


Try it online!

The left argument is a pair of character vectors - left ribbons and top ribbons. The right argument is a vector of coordinate pairs - swap locations. Returns a pair of right ribbons and bottom ribbons. (Note that unlike in the examples, I use the order left-top and right-bottom for the ribbons in order to be consistent with the row-col axis order in the coordinates.)

Swaps must be sorted so that a swap to the upper-left of another comes before after it. If two swaps are to the lower-left/upper-right of each other, their order doesn't matter.

EDIT: saved one byte (⌽) by requiring reverse order of swaps in the input

# Javascript, 8776 62 bytes

(c,r,s)=>{for([i,j]of s)if(r[i]&&c[j])[r[i],c[j]]=[c[j],r[i]]}


Try it online!

Same trivial algorithm as the Python 3 answer. Uses arrays as coordinate tuples. Requires ribbon colors to be designated by truthy values. Requires coordinates to be partially ordered so that x1,y1 comes before x2,y2 if either x1 < x2 && y1 = y2 or x1 = x2 && y1 < y2. Returns by modifying input arrays.

• I'm pretty sure you can delete ;return[r,c] and call it a return by modification – Asone Tuhid Apr 19 '18 at 22:35
• if(r[i]&&c[j]) would save some more bytes. – Neil Apr 19 '18 at 23:44
• I know that my condition is too strong, but your condition is self-contradictory. Consider x1=1,x2=2,y1=2,y2=1. Because x1<x2, (x1,y1) comes before (x2,y2); but because y2<y1, (x2,y2) comes before (x1,y1). I think "x1 < x2 and y1 < y2" suffices. – user202729 Apr 20 '18 at 1:25
• @AsoneTuhid Hm, I think that's cheating. Modifying the input objects is not the same as output by reference parameters. – Bergi Apr 20 '18 at 10:33
• Q: "Does this mean that in languages that allow it, the seven characters for return can simply be replaced with an assignment?" A: "Yes, provided the changed value will then be accessible in the context that called the function.". Seems pretty clear to me. – Asone Tuhid Apr 20 '18 at 10:41

# Ruby, 56 54 bytes

->t,l,s{s.map{|i,j|a=t[j];t[j]&&=l[i]||a;a&&l[i]&&=a}}


Try it online!

A port of user202729's Python 3 answer with some ruby tricks

Coordinates have to be lexicographically sorted