Alex is sometimes right
Ruby, 80 76 + 2 = 78
With command-line flags p0
, run
gsub$1,$2%p=$`[/e/]while~/(.) = (?!\1)(.)/
$_="Alex is #{p ?:wrong: :right}"
Explanation:
This uses pure string manipulation. p0
reads the full input as a single string into the variable $_
. Then, we repeatedly match that string against the regular expression /(.) = (?!\1)(.)/
, which finds all strings of the form "X = Y" where X and Y aren't the same letter, and assigns X to $1 and Y to $2. When such a match is found, gsub$1,$2
replaces all instances of X with Y in the string. We also check whether this match occurred before or after the "therefore" with
$`[/e/]
If it occurred after, it's an unjustified claim and Alex is wrong. We track whether any such occurrences have happened using p=
. The use of p
as a tracking variable prevents things from breaking if the loop never hits even once, since p
will return nil if it's never been assigned to.
As of this post, the CJam solution is longer. A proud, if no doubt fleeting moment.
Edit: Yup, quickly dethroned. Also, to finish the explanation, with the p
flag the final value of $_
is output at the end of execution, so the last line is the output.
CJam, 49
"Alex is "qN%S{f{)er}(_el-}h;{)#},"wrong""right"?
Inspired from histocrat's Ruby solution. Try it online
3 bytes obliterated thanks to jimmy23013 :)
Explanation:
For each premise, the program replaces the first variable with the 2nd variable in the rest of the text. It then checks if there's any conclusion with different variables.
"Alex is " first push the part we know
qN% read the input and split into lines
S push a space (initial no-op replacement string, see below)
{…}h do-while
f{…} for each line and the replacement string
) take out the last character
er replace the remaining character(s) with that character
( afterwards, take out the first line
_el duplicate and convert to lowercase
- remove all the resulting characters from the line
this removes all lowercase letters and non-letters
"X = Y" becomes "XY" (new replacement string)
and "therefore" becomes "" (ending the loop)
this is the loop condition and is left on the stack every time
; after the loop, pop the empty string (from "therefore")
{…}, filter the remaining (conclusion) lines using the condition block
) take out the last character
# find its index in the remaining string
this is 0 (false) iff the first character is the same as the last
afterwards, we have an array of lines with non-equal variables
"wrong" push "wrong"
"right" push "right"
? choose "wrong" if the array was not empty, else choose "right"
Old version, 85
"Alex is "26,:A;{:i{{_A=_@-}g}%$~}:F;0q"= "-'t/Nf%~\{A\Ft:A;}/1>{F=}%-"right""wrong"?
This uses a union-find algorithm. Try it online
CJam, 83 75 68 67 64 bytes
Thanks to Dennis for saving 1 byte.
"Alex is "q_elN--N/:$La/~{)-},\{__m*{:&},::^|}5*-"wrong""right"?
Test suite. The test cases are too long for a permalink, so simply copy them in from the question. Note that this is fairly slow - it takes a minute or two in the online interpreter. You can make it much faster by changing 5*
to 2*
in which case it will finish almost instantly and solve all but one test case.
Explanation
(Slightly outdated.)
The idea is to do a sort of "flood fill" of possible equalities and then remove all the equalities we obtained from the conclusion list. It can be shown that we need no more than 5 steps of the flood fill, because those would cover a distance (in the initial graph of inequalities) of 25 = 32
but the maximum distance is 25.
"Alex is " e# Push the string.
q e# Read the input.
_elN- e# Make a copy, convert to lower case, remove linefeeds. This gives us a string
e# with all the characters we don't want from the input.
- e# Remove them from the input. This leaves two upper-case letters on each line
e# and an empty line between premises and conclusions.
N/ e# Split into lines.
La/ e# Split around the empty line.
~ e# Dump both halves on the stack.
{)-}, e# Remove any "A = A"-type equalities from the conclusions.
\ e# Swap with the premises.
{ e# Extend the premises 5 times...
_Wf% e# Duplicate the premises and reverse each one, because = is symmetric.
| e# Set union with the original premises.
__m* e# Make two copies and get an array of every possible pair of premises.
{:&}, e# Select those which have at least one character in common.
::^ e# For each such pair, take the mutual set difference, i.e. those characters
e# that are in only one of the strings.
| e# Set union with the original premises.
}5*
- e# Remove all the equalities we've obtained from the conclusions. If all
e# conclusions were valid, the result will now be a empty array, which is falsy.
! e# Logical not.
"wrong""right"?
e# Select "wrong" or "right", respectively.