Reverse a Rubik's Cube Algorithm

20

2

Whenever you make a move on a Rubik's Cube, there is a reverse move which undoes the first move. Because of this, every algorithm (set of moves) has a reverse algorithm which undoes the first algorithm.

The goal of this challenge is to find the reverse of a given algorithm.

Specification:

The input consists of an array of individual moves. Each move is a string of length 1 or 2. Of course, you can use whatever input format makes the most sense in your language. Each move consists of the structure X or X' or X2, where X is an uppercase or lowercase letter.

To reverse X, simply replace it with X'. Likewise, X' becomes X. X2 on the other hand does not get changed.

To create the output, reverse each move, and then reverse the array.

Examples (strings separated by spaces):

R => R'

D U' => U D'

S T A C K => K' C' A' T' S'

A2 B2 => B2 A2

Scoring:

This is code-golf, so the fewest amount of bytes win. Standard loopholes are not allowed.

Julian Lachniet

Posted 2017-07-06T17:41:11.870

Reputation: 3 216

Is R2 -> R2' or B -> B3 allowed? – CalculatorFeline – 2017-07-06T18:01:44.800

R2 has to become R2. Although B3 makes sense for actual algorithms, it is not within the scope of the challenge. – Julian Lachniet – 2017-07-06T18:04:37.397

2Having to handle X3 or X1 would have been a nice addition to the challenge. – Shaggy – 2017-07-06T18:32:56.897

1"Because of this, every algorithm (set of moves) has a reverse algorithm which undoes the first algorithm" is this true for every algorithms?? Cause I think the hashing algorithms are one way. Means it doesn't have any reverse algorithms, right? please let me know – Avishek Saha – 2017-07-07T04:21:12.613

4@AvishekSaha : For Rubik's Cube problems, "algorithm" is restricted to the meaning "a sequence of moves you can do on the Cube". In this sense, there is no such thing as a one-way hashing algorithm on the Cube. – Ross Presser – 2017-07-07T04:35:42.540

oh! I was talking about algorithms in general, not the rubik's cube algorithms though. – Avishek Saha – 2017-07-07T04:37:55.010

@AvishekSaha It is not true for general algorithms. If an algorithm takes both A and B to C, then a reverse algorithm ran on C would on one hand have to return A, and on the other it would have to return B. The theory of reversibke computing is interesting, but quite different from your usual computer science.

– Wojowu – 2017-07-07T17:41:45.703

5Should have had D2R2 as a test case... – Neil – 2017-07-29T15:49:42.037

Can we assume that the input only contains valid Rubik's Cube moves? For example, if the input RL produced the output L'R', but the input RLK also produced the output L'R', would the answer be valid? – MD XF – 2018-01-24T05:40:09.127

Answers

7

Python 2, 71 57 54 53 bytes

-15 bytes thanks to ovs! -3 bytes thanks to Rod.

lambda l:[i.strip("'")+" '"[len(i):]for i in l[::-1]]

Try it online!

String I/O, 70 bytes

lambda s:' '.join(i.strip("'")+"'"*(len(i)<2)for i in s.split()[::-1])

Try it online!

totallyhuman

Posted 2017-07-06T17:41:11.870

Reputation: 15 378

153 bytes – ovs – 2017-07-06T18:11:33.850

7

Retina 0.8.2, 27 26 bytes

\w
$&'
''

'2'
2
O$^`.'?2?

Try it online! Link includes test cases. Explanation: The first stage adds an apostrophe after every alphanumeric. This results in double apostrophes (with or without an inclusive 2) which need to be removed. The final stage reverses the moves.

Neil

Posted 2017-07-06T17:41:11.870

Reputation: 95 035

Could this be improved with the release of Retina 1.0?

– MD XF – 2018-01-24T05:41:37.013

@MDXF It seems that O$^ is in fact still the best way of reversing a list of matches, so the byte count is actually unchanged in Retina 1. – Neil – 2018-01-24T10:56:21.123

7

V, 13 10 bytes

æGÇä/á'Ó''

Try it online!

3 bytes saved thanks to @nmjmcman pointing out my favorite feature. Explanation:

æG          " Revere the order of every line
  Ç         " On every line not containing...
   ä/       " a digit:
     á'     "   Append an '
       Ó    "   Remove every instance on this line
        ''  "     Of two single quotes

James

Posted 2017-07-06T17:41:11.870

Reputation: 54 537

Does ä like represent a regex when compiled to vim? – Downgoat – 2017-07-06T21:14:59.953

@Downgoat Yes! It does. Translated into vim, this solution is :g!/\d/norm A'<CR>:%s/''//g<CR>gg:g/^/m0<CR> More information on how V compresses regular expressions can be found here

– James – 2017-07-06T21:18:41.223

@DJMcMayhem Aren't implicit endings like your favorite feature? Try it online!

– nmjcman101 – 2017-07-07T16:43:34.210

3I know this is quite late, but this doesn't work for me. It turns an R2 into a 2R, which isn't valid – Jamie Sanborn – 2017-07-30T03:15:02.457

5

JavaScript (ES6), 45 bytes

s=>s.map(([a,b])=>b?+b?a+b:a:a+"'").reverse()

Shortest solution is to take Array IO. Simple and appropriate use of argument destruction.

String output is +8 bytes for .join` `.

String input, Array output: 69 bytes

(s,k=[])=>s.replace(/\S\S?/g,([a,b])=>k.unshift(b?+b?a+b:a:a+"'"))&&k

f=

(s,k=[])=>s.replace(/\S\S?/g,([a,b])=>k.unshift(b?+b?a+b:a:a+"'"))&&k

;

console.log(["R", "D U'", "S T A C K", "A2 B2"].map(e => `${e} => ${f(e)}`));
<textarea oninput="out.value=(f(this.value)||[]).join` `" placeholder="input here"></textarea>
<textarea id="out" readonly></textarea>

Conor O'Brien

Posted 2017-07-06T17:41:11.870

Reputation: 36 228

Nice one. Why do I never think to destructure function parameters?! :( – Shaggy – 2017-07-06T18:31:34.593

You should be able to replace .reverse() with ::reverse saving 1 byte but making ES7 – Downgoat – 2017-07-06T21:13:19.080

@Downgoat Any place where I can test ES7? – Conor O'Brien – 2017-07-07T02:03:29.350

@ConorO'Brien you can use babel online REPL (tick execute and all the preset boxes for all feature): https://babeljs.io/repl

– Downgoat – 2017-07-07T02:35:07.597

4

JavaScript (ES6), 46 bytes

Takes input as an array of moves.

a=>a.map(m=>m[1]?+m[1]?m:m[0]:m+"'").reverse()

Test it

Enter a comma separated list of moves.

o.innerText=(f=
a=>a.map(m=>m[1]?+m[1]?m:m[0]:m+"'").reverse()
)((i.value="S,T,A,C,K").split`,`);oninput=_=>o.innerText=f(i.value.split`,`)
<input id=i><pre id=o>


Explanation

a=>

Anonymous function taking the array of moves as an argument via parameter a.

a.map(m=>                       )

Map over the array, passing each string through a function, where m is the current string.

 m[1]?

Check if the string contains a second second character ("'" or "2").

+m[1]?

If it does try to cast that character string to an integer. If the string is "2", it becomes 2, which is truthy. If the string is "'", it becomes NaN, which is falsey.

m

If the previous test is truthy, simply return m.

:m[0]

Otherwise, return the first character of m.

:m+"'"

If the string does not contain a second character then return m appended with a '.

.reverse()

Reverse the modified array.

Shaggy

Posted 2017-07-06T17:41:11.870

Reputation: 24 623

Sorry, I just saw this. My own answer is similar to yours :P – Conor O'Brien – 2017-07-06T18:13:08.790

4

Jelly, 11 bytes

ḟ;ċ?”'ḣ2µ€Ṛ

A monadic link taking an returning a list of lists of characters (an "array" of "strings").

Try it online! (The footer avoids smashing the output, displaying the list split with spaces.)

How?

ḟ;ċ?”'ḣ2µ€Ṛ - Link: list of lists of characters             e.g. ["F'", "D2" , "R"]
        µ€  - perform the chain to the left for €ach turn instruction:
    ”'      -   literal "'" character
   ?        -   if:
  ċ         -     count (number of "'" in the instruction) i.e.:  1   , 0    , 0
ḟ           -   then: filter out                                  "F"
 ;          -   else: concatenate                                       "D2'", "R'"
      ḣ2    -   head to index 2                                   "F" , "D2" , "R'"
          Ṛ - reverse                                            ["R'", "D2" , "F"]

Jonathan Allan

Posted 2017-07-06T17:41:11.870

Reputation: 67 804

10 bytes with new Jelly. – user202729 – 2018-06-08T09:49:30.390

2

Python 3, 91 89 72 70 69 65 bytes

lambda s:[i[0]+(len(i)-2and"'"or"2"*("2"==i[1]))for i in s[::-1]]

Try it online! (With testcases)

Apparantly you don't need to take input and output as strings, so a 69 byte solution is possible

sagiksp

Posted 2017-07-06T17:41:11.870

Reputation: 1 249

AFAIK you can delete the space after len(i)==1 – Stephen – 2017-07-06T17:50:44.170

@StepHen Huh, didn't know that was allowed (Knew that some interpreters allowed it, just didn't know it's allowed in codegolf) – sagiksp – 2017-07-06T17:54:13.020

2Languages are defined by their interpreters here so, if it works in any one interpreter, it's valid. – Shaggy – 2017-07-06T17:55:11.720

If the interpreter allows it, you can do it. That's all code-golf cares about ;) – Stephen – 2017-07-06T17:55:30.310

len(i)-2 is shorter than len(i)==1 (remember 0 is falsey) – Stephen – 2017-07-06T17:56:30.167

2

Python,  51  48 bytes

lambda a:[(v+"'")[:2-("'"in v)]for v in a[::-1]]

An unnamed function taking and returning lists of strings.

Try it online!

Reverses the input list with a[::-1]; appends a ' to every entry with v+"'"; heads each one to 1 or 2 characters depending on whether the original had a ' in or not with [:2-("'"in v)].

Jonathan Allan

Posted 2017-07-06T17:41:11.870

Reputation: 67 804

1

Haskell, 43 bytes

map f.reverse
f[x]=x:"'"
f[x,c]=x:[c|c>'1']

Try it online! Declares an anonymous function map f.reverse. Bind to g and use as g["S","T","A","C","K"].

Laikoni

Posted 2017-07-06T17:41:11.870

Reputation: 23 676

1

PHP, 81 bytes

<?foreach(array_reverse($_GET)as$v)$r[]=$v[1]?$v[1]<2?$v[0]:$v:"$v'";print_r($r);

Try it online!

Jörg Hülsermann

Posted 2017-07-06T17:41:11.870

Reputation: 13 026

1

05AB1E, 13 bytes

RεÐ1èQ''si«ëK

Try it online!

Explanation

RεÐ1èQ''si«ëK
R             # Reverse input array
 ε            # Map over each element...
  Ð1èQ         # Is the second char in the element the first one? (Uses the fact that in python indexing loops)
      ''       # Push '
        s      # Swap top items of stack
         i     # If the question above is true...
          «     # Concatenate
           ë   # Else
            K   # Push element without '  

Datboi

Posted 2017-07-06T17:41:11.870

Reputation: 1 213

1

J, 25 bytes

J handles this one well, other than the unfortunate escape sequence needed to represent a single quote:

|.,&''''`}:@.(''''={:)&.>

We need to represent the list using boxed data, since it's a mix of one and two character items, hence:

  • &.> - "under unbox", which means unbox each element, perform the operation that follows (ie, the symbols explained below) and then rebox when done
  • (''''={:) "if the 2nd character is a single quote"....
  • @. (J's agenda verb, a kind of generalized ternary statement, or a case statement) "then perform the 2nd item on the agenda list, otherwise perform the first"
  • }: (the 2nd item on the agenda list), "remove the last character", ie, the single quote
  • ` (J's tie verb) You can think of this as the agenda item separator
  • ,&'''' (first item on agenda list) "add a single quote to the end"
  • |. "reverse"

Try it online!

Jonah

Posted 2017-07-06T17:41:11.870

Reputation: 8 729

0

R, 51 bytes

function(u)sub("((2)|')'","\\2",paste0(rev(u),"'"))

Try it online!

Scarabee

Posted 2017-07-06T17:41:11.870

Reputation: 131

0

Java 8, 141 128 126 bytes

a->new StringBuffer(a.replaceAll("(.)","$1'").replace("'''","").replaceAll("(.)'","'$1").replaceAll("'(.)'2","2$1")).reverse()

Takes input as single String without spaces (i.e. RUR'URU2R'U).

Explanation:

Try it online.

a->new StringBuffer(           // Method with String parameter and StringBuffer return-type
  a.replaceAll("(.)","$1'")    //1  Add an apostrophe after every character
   .replace("'''","")          //2  Remove all occurrences of three adjacent apostrophes
   .replaceAll("(.)'","'$1")   //3  Reverse letter+apostrophe to apostrophe+letter
   .replaceAll("'(.)'2","2$1") //4  Reverse letter+2 to 2+letter and remove aphostrophes
  ).reverse()                  //5 Reverse everything

Example of the steps above, with as given input: RUR'URU2R'U

  1. RUR'URU2R'UR'U'R'''U'R'U'2'R'''U'
  2. R'U'R'''U'R'U'2'R'''U'R'U'RU'R'U'2'RU'
  3. R'U'RU'R'U'2'RU''R'UR'U'R'U'2R'U
  4. 'R'UR'U'R'U'2R'U'R'UR'U'R2UR'U
  5. 'R'UR'U'R2UR'UU'RU2R'U'RU'R'

Kevin Cruijssen

Posted 2017-07-06T17:41:11.870

Reputation: 67 575

0

Ruby, 44 bytes

->a{a.reverse.map{|i|i[1]?i.tr(?',''):i+?'}}

Try it online!

Asone Tuhid

Posted 2017-07-06T17:41:11.870

Reputation: 1 944