20
\$\begingroup\$

Let's start by re-defining a reflection of a character in a 2-d array of characters:

Given a square 2-d array of characters with distinct lowercase alphabetical letters, define a reflection of a letter in the matrix as swapping it with the character directly across from it through the center of the square.

Thus, a reflection of the letter c in

abcde
fghij
klmno
pqrst
uvwxy

would result in the configuration

abwde
fghij
klmno
pqrst
uvcxy

because the c and the w have been switched.

Some more examples (with the same original configuration as above):

Reflecting the character e would form

 abcdu
 fghij
 klmno
 pqrst
 evwxy

Reflecting the character m would make

 abcde
 fghij
 klmno
 pqrst
 uvwxy

Reflecting the character b would form

 axcde
 fghij
 klmno
 pqrst
 uvwby

The Challenge

Given a 2-d array of characters with distinct lowercase letters, go through each character in a given string and "reflect" it in the matrix.

Clarifications: The letters in the string are from a-z, the letters are unique, and the array is at least 1x1 and at most 5x5 (obviously, as there are only 26 characters in the English alphabet.) The characters in the string are guaranteed to be in the 2-d array. The string is at most 100 characters long.

Input

An string s, an integer N, and then a NxN array of characters.

Example

Input:

ac
2
ab
cd

Output:

dc
ba

*Reason: First, reflect the a with the d. Then, reflect the c with the b because c is the second letter in the input string.


Scoring

  • Output can be given by any convenient method.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Current Winner

<style>body { text-align: left !important} #answer-list { padding: 10px; width: 290px; float: left; } #language-list { padding: 10px; width: 290px; float: left; } table thead { font-weight: bold; } table td { padding: 5px; }</style><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="language-list"> <h2>Shortest Solution by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr> </thead> <tbody id="languages"> </tbody> </table> </div> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr> </thead> <tbody id="answers"> </tbody> </table> </div> <table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table><script>var QUESTION_ID = 163084; var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe"; var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk"; var OVERRIDE_USER = 12012; var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page; function answersUrl(index) { return "https://api.stackexchange.com/2.2/questions/" + QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER; } function commentUrl(index, answers) { return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER; } function getAnswers() { jQuery.ajax({ url: answersUrl(answer_page++), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { answers.push.apply(answers, data.items); answers_hash = []; answer_ids = []; data.items.forEach(function(a) { a.comments = []; var id = +a.share_link.match(/\d+/); answer_ids.push(id); answers_hash[id] = a; }); if (!data.has_more) more_answers = false; comment_page = 1; getComments(); } }); } function getComments() { jQuery.ajax({ url: commentUrl(comment_page++, answer_ids), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { data.items.forEach(function(c) { if (c.owner.user_id === OVERRIDE_USER) answers_hash[c.post_id].comments.push(c); }); if (data.has_more) getComments(); else if (more_answers) getAnswers(); else process(); } }); } getAnswers(); var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/; var OVERRIDE_REG = /^Override\s*header:\s*/i; function getAuthorName(a) { return a.owner.display_name; } function process() { var valid = []; answers.forEach(function(a) { var body = a.body; a.comments.forEach(function(c) { if(OVERRIDE_REG.test(c.body)) body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>'; }); var match = body.match(SCORE_REG); if (match) valid.push({ user: getAuthorName(a), size: +match[2], language: match[1], link: a.share_link, }); else console.log(body); }); valid.sort(function (a, b) { var aB = a.size, bB = b.size; return aB - bB }); var languages = {}; var place = 1; var lastSize = null; var lastPlace = 1; valid.forEach(function (a) { if (a.size != lastSize) lastPlace = place; lastSize = a.size; ++place; var answer = jQuery("#answer-template").html(); answer = answer.replace("{{PLACE}}", lastPlace + ".") .replace("{{NAME}}", a.user) .replace("{{LANGUAGE}}", a.language) .replace("{{SIZE}}", a.size) .replace("{{LINK}}", a.link); answer = jQuery(answer); jQuery("#answers").append(answer); var lang = a.language; lang = jQuery('<a>'+lang+'</a>').text(); languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang.toLowerCase(), user: a.user, size: a.size, link: a.link}; }); var langs = []; for (var lang in languages) if (languages.hasOwnProperty(lang)) langs.push(languages[lang]); langs.sort(function (a, b) { if (a.lang_raw > b.lang_raw) return 1; if (a.lang_raw < b.lang_raw) return -1; return 0; }); for (var i = 0; i < langs.length; ++i) { var language = jQuery("#language-template").html(); var lang = langs[i]; language = language.replace("{{LANGUAGE}}", lang.lang) .replace("{{NAME}}", lang.user) .replace("{{SIZE}}", lang.size) .replace("{{LINK}}", lang.link); language = jQuery(language); jQuery("#languages").append(language); } }</script>

\$\endgroup\$
11
  • 12
    \$\begingroup\$ Half an hour is not really enough time to get any meaningful use out of the sandbox. \$\endgroup\$
    – Grain Ghost
    Apr 23 '18 at 4:22
  • 3
    \$\begingroup\$ No problem, it looks good. \$\endgroup\$
    – DELETE_ME
    Apr 23 '18 at 5:12
  • 1
    \$\begingroup\$ (also we have a Stack snippet leaderboard) \$\endgroup\$
    – DELETE_ME
    Apr 23 '18 at 5:12
  • 8
    \$\begingroup\$ 50 hours is a bit too short of a time span to accept a winner; typically you'd want to wait a week or so. However, on PPCG, it's common practice to not accept any answers because that discourages future answers, and we want to keep challenges open forever. \$\endgroup\$
    – hyper-neutrino
    Apr 23 '18 at 5:25
  • 3
    \$\begingroup\$ All you examples have the characters in alphabetical order. I assume that's not an assumption we can make? Also, do we have to take N as an input if we don't need it? \$\endgroup\$ Apr 23 '18 at 7:43

11 Answers 11

4
\$\begingroup\$

Python 2, 76 bytes

lambda s,a:[a[[i,~i][(s.count(c)+s.count(a[~i]))%2]]for i,c in enumerate(a)]

Try it online!

Takes input:

  • s: string
  • N: ignored
  • a: joined string of chars

Returns a flat list of chars


If I have to take the array as a list:

Python 2, 111 108 107 104 bytes

lambda s,n,a:[[x[sum(map(s.count,x))%2]for i in range(n)for x in[[a[j][i],a[~j][~i]]]]for j in range(n)]

Try it online!

Takes input:

  • s: string
  • n: int
  • a: 2D lists of chars

Returns a 2D list of chars

\$\endgroup\$
3
\$\begingroup\$

Octave, 85 68 66 bytes

Using eval, with a loop inside it saved a lot of bytes! I got the inspiration from this answer by Luis Mendo!

@(c,N,A)eval"for C=c,A(flip(k))=A(k=[x=find(A==C),N^2+1-x]);end,A"

Try it online!

Explanation:

f=@(c,N,A)          % Anonymous function that takes the three input variables
eval"...          % Evaluate the string and run it:
 for C=c,          % Loop over the character list 'c'
  .. x=find(A==C)   % Find the index where the character C is in A, and store it as 'x'
  .. k=[x,N^2+1-x]  % Create a vector with the index of C, and the index of its reflection
   A(flip(k))=A(k)  % Swap the elements in these positions
  end               % End loop
  A"                % Display the new 'A'
\$\endgroup\$
2
\$\begingroup\$

Jelly, 15 14 bytes

FW;Ṛi,C$¥¦/ṁḷY

Try it online!

Full program.

Explanation:

FW;Ṛi,C$¥¦/ṁḷY       Main link. Input: ['ab','cd'] (left), 'ac' (right).
FW                   Flatten and Wrap it in a list. Current value = ['abcd'].
  ;                  Concatenate it with right argument. ['abcd','a','c']
          /          Reduce from left:
   Ṛ     ¦             Apply everse at...
    i   ¥              the index (of right argument in left argument)...
     ,C$               and its complement index.

The last operation needs more explanation. Denote f = Ṛi,C$¥¦, then for value ['abcd','a','c'] it computes ('abcd' f 'a') f 'c', which expands to:

Ṛi,C$¥¦    Function f. Assume left argument = 'abcd' and right argument = 'a'
Ṛ          First, compute the reverse. Get 'dcba'.
 i   ¥     To compute the indices to apply to, first the index of 'a' in 'abcd'
             is ('abcd' i 'a') = 1. (first index)
  ,C$      Then pair with (1 C) = 0. (last index)
      ¦    Apply 'dcba' to 'abcd' at indices 0 and 1:

              abcd
              dcba
              ^1 ^0
              ====
              dbca
\$\endgroup\$
0
2
\$\begingroup\$

R, 74 61 bytes

-13 bytes thanks to Giuseppe.

function(s,n,m){for(x in s)m[v]=rev(m[v<-(i=x==m)|rev(i)]);m}

Try it online!

Inputs a vector of characters to search as s, size of the matrix as n and matrix itself as m. If it is absolutely necessary to take the first argument as string, that would pretty much spoil the fun.

\$\endgroup\$
1
  • \$\begingroup\$ Using logical rather than numeric indices, I golfed down to 61 bytes \$\endgroup\$
    – Giuseppe
    Apr 23 '18 at 13:07
2
\$\begingroup\$

Java 10, 126 123 116 114 bytes

(s,n,m)->{for(var c:s)for(int N=n*n,i,j;N-->0;)if(m[i=N/n][j=N%n]==c){m[i][j]=m[n+~i][n+~j];m[n+~i][n+~j]=c;N=0;}}

Modifies the input character-matrix instead of returning a new one to save bytes.

Try it online.

Explanation:

(s,n,m)->{     // Method with the three parameters and no return-type
  for(var c:s) //  Loop over the characters given:
    for(int N=n*n,i,j;N-->0;)
               //   Inner loop over the cells of the matrix:
      if(m[i=N/n][j=N%n]==c){
               //    If the current character and matrix-value are equals:
        m[i][j]=m[n+~i][n+~j];m[n+~i][n+~j]=c;
               //     Swap the values in the matrix at indices [i, j] and [n-i-1, n-j-1]
        N=0;}} //     And stop the inner loop (go to next iteration of the outer loop)
\$\endgroup\$
0
2
\$\begingroup\$

Java (JDK), 95 93 bytes

(x,s,N)->{for(var c:s)for(int i=-1;++i<N;){var t=x[i];if(t==c){x[i]=x[N+~i];x[N+~i]=t;i=N;}}}

Try it online!

Java (JDK), 131 bytes

(x,s,n)->{for(var c:s)for(int i=~0;++i<n*n;){int a=i/n,b=i%n;var t=x[a][b];if(t==c){x[a][b]=x[n+~a][n+~b];x[n+~a][n+~b]=t;break;}}}

Java (JDK), 138 135 bytes

(x,s,n)->s.forEach(c->{for(int i=~0,a=i/n,b=i%n;++i<n*n;){var t=x[a][b];if(t==(char)c){x[a][b]=x[n+~a][n+~b];x[n+~a][n+~b]=t;break;}}})

Java (JDK), 112 bytes

(x,s,N)->{for(var c:s)for(var v:x.entrySet())if(v.getValue()==N-x.get(c))x.put(v.getKey(),x.put(c,N-x.get(c)));}

Try it online!

Java (JDK), 70 bytes

(x,X,s,N)->{for(var c:s)x.put(X.get(N-x.get(c)),x.put(c,N-x.get(c)));}

Try it online!

All of these code snippets function in essentially the same way since only difference between them is the type of the variable x. The first has it set as char[], the second as char[][] and the third as List<Object>. The fourth and fifth are quite unique solutions, and so I'll go over the specific details of them last. As somewhat of a side note, the first of these three entries inputs the total quantity of elements in the initial array (i.e., N = n * n).

Here's how the first three entries work:

(array, reflect, size) -> {            // Initializes lambda expression
    for (char c: reflect)              // Loops through soon-to-be reflected characters
        for (int i = 0; i < size; i++) // Loops through elements in array
            if (array[i] == c)         // Checks if this element should be reflected
            {
                var temp = array[i];   // Reflects elements
                array[i] = array[size - 1 - i];
                array[size - 1 - i] = temp;
                break;                 // Goes on to reflect next character
            }
};

I feel like these entries can be further golfed with use of nested functions and lambda expressions, but I have been unable to do so thus far. I instead went on to create the fourth entry, as shown below in all of its golfed glory:

(x,s,N)->{
    for(var c:s)
        for(var v:x.entrySet())
            if(v.getValue()==N-x.get(c))
                x.put(v.getKey(),x.put(c,N-x.get(c)));
}

The fifth is quite similar. These particular lambda expressions are unique, in the sense that s is an Object[] and N is one less than the total quantity of elements in the initial array. But most importantly, x is a LinkedHashMap<Object, Integer>. Well, what's so special about all of that? The idea behind changing all of these things was to allow for a short for loop going over the elements of s, thus ridding the program of tightly packing for loops with ugly garbage. It essentially simplified things for the code and I. Unfortunately, doing so would mean indexing the initial array to find the index of each element, contradicting its intended purpose.

It was at that moment that I realized that replacing the array input with some Map subclass would allow me to use the elements to be reflected as a way to index the elements in the array directly. So I did the only logical solution: map half of the array elements to their corresponding pairs to simplify reflection. Didn't work, big surprise. But I didn't give up and mapped each element to its corresponding array index and the idea was looking good. Next problem: given an element in the array, finding its reflective pair couldn't be done without more for loops, if statements and precious bytes altogether. But a more immediate problem came from this, too: printing the array. In retrospect, it would've been possible to instead input a copy of the array and use the original's elements to get the key-value pairs, but I found a better solution: the LinkedHashMap. This class contains the nested class Entry, which allows for much simpler key-value pairing, which just so happened to be at the root of both problems.

So now that I've gone over why I made these changes and how the base of this setup should work, I'll use what we've learned to give the code some more context:

(x,s,N)->{ // Initializing lambda expression
    for(var c:s) // Looping over elements to be reflected
        for(var v:x.entrySet()) // Looping over key-value pairs...
            if(v.getValue()==N-x.get(c)) // ...until element opposite current is found
                x.put(v.getKey(),x.put(c,N-x.get(c))); // Swapping elements
}

You should note that the line involving the actual reflection has a nested put method, because it returns the key that was changed, thus removing an extra variable initialization for the swapping process.

But what about my fifth entry? Am I taking this simple challenge too seriously? Yes! This solution has a very low byte count, because it's the same as the fourth, but with an extra input: X. Unlike x, which is the array converted to a LinkedHashMap<Object, Integer>, X is the reverse: a LinkedHashMap<Integer, Object>. This allows us to skip searching for any element's index and instead just look it up in X, thus removing a lot of code.

As a final side note, the only entries that allow more characters to be reflected than there are in the initial array are the fourth and fifth. Will this be the end?

Thanks to @KevinCruijssen for the inspiration and for saving two bytes from my first entry.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to Code Golf! You may want to check out our Tips for golfing in Java. \$\endgroup\$ Dec 11 '20 at 19:49
  • 1
    \$\begingroup\$ You can save 2 bytes in your top answer by changing break; to i=N;. \$\endgroup\$ Jan 15 at 8:10
2
\$\begingroup\$

C, 84 86 83 bytes

+2 bytes to use a temporary variable instead of chained XOR when swapping variables, allowing for the central letter to be swapped with itself

-3 bytes thanks to ceilingcat.

f(s,n,a,i,j,t)char*s,*a,*i;{for(;*s;*i=t)i=index(a,*s++),t=a[j=a-i+n*n-1],a[j]=*i;}

Try it online!

Un-golfed:

f(s,n,a,i,j,t)
    char*s,*a,*i;
{
    for(;*s;*i=t) { //Loop while end of s hasn't been reached
        i=index(a,*s++); //i = pointer to char in a with value *s, then get next char s
        t=a[j=a-i+n*n-1]; //j = index of char in a which is opposite i, then swap i and a[j]
        a[j]=*i;
    }
}
\$\endgroup\$
0
1
\$\begingroup\$

Python 3, 122 111 bytes

lambda l,n,A:[[[A[a][b],A[~b][~a]][sum(map(l.count,[A[a][b],A[~b][~a]]))%2]for b in range(n)]for a in range(n)]

Try it online!

Returns a 2D array of chars.

\$\endgroup\$
1
  • \$\begingroup\$ You should be able to golf this further.. No way modifying the input matrix is shorter in Java than in Python.. ;p To get you started (and making it 1 byte shorter instead of 1 byte longer than my Java answer): Removing the a and b and using n+~x and n+~y directly saves 2 bytes: a,b=n+~x,n+~y;A[x][y],A[a][b]=A[a][b],A[x][y] to A[x][y],A[n+~x][n+~y]=A[n+~x][n+~y],A[x][y] \$\endgroup\$ Apr 23 '18 at 9:43
1
\$\begingroup\$

Retina 0.8.2, 96 bytes

+`^(.)(.*¶(.|¶)*)((.)((.|¶)*))?\1(?(4)|(((.|¶)*)(.))?)((?<-3>.|¶)*$(?(3).))
$2$11$9$1$6$5$12
1A`

Try it online! Takes the string s and the array of characters as a newline-delimited string without the integer N. Explanation: Each character c of s is processed in turn. The regex matches two positions equidistant from the ends of the array, of which one is c and the other is its mirror m. These characters are swapped and c is removed from s.

+`

Processes each character of s in turn.

^(.)

$1 captures c.

(.*¶(.|¶)*)

$3 captures a stack of characters in the array prefixing one of c or m. $2 captures the rest of s plus all of these characters.

((.)((.|¶)*))?

If m precedes c, $4 has a value, $5 captures m and $6 captures the characters between m and c. $7 captures $6 as a stack but its value is not used.

\1

c is now matched in the array itself.

(?(4)|(((.|¶)*)(.))?)

If m wasn't already matched, then $8 optionally captures a value, in which case $9 captures the characters from c to m, $10 captures $9 as a stack which is unused and $11 captures m. The value is optional in case c and m are the same character.

((?<-3>.|¶)*$(?(3).))

$12 captures the characters suffixing the other of c and m. A balancing group is used to ensure $12 is as long as $3 was deep, i.e. the prefix and suffix are the same length.

$2$11$9$1$6$5$12

The pieces are then put back together - first the rest of s and the prefix of the array, then if c preceeded m then m then the middle, then c, then if m preceeded c then the middle then m, then the suffix.

1A`

Now that s is empty it is deleted.

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

JavaScript, 85 bytes

Takes string S and an array A as joined string.

([...S],[...A])=>S.map(c=>[A[j],A[i]]=[A[i=A.indexOf(c)],A[j=A.length+~i]])&&A.join``

f=
([...S],[...A])=>S.map(c=>[A[j],A[i]]=[A[i=A.indexOf(c)],A[j=A.length+~i]])&&A.join``

console.log(
  f('abcd','ac')
)

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

Perl 5 -lpF, 97 bytes

$i=0|<>;$_=join'',<>;s/\W//g;for$k(@F){/$k/g;$t=substr$_,-pos,1;eval"y/$t$k/$k$t/"}s%.{$i}%$&$/%g

Try it online!

\$\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.