It's the end of the year, you and your friends have just received your grades and ranks for the GOLF101 class. On a chat group, everyone sends their grade and rank to see who's got the best one.
Problem: someone is lying.
Here is an excerpt from the chat:
<A> I'm ranked 1 with a grade of 85.
<B> Ranked 3, got 50.
<C> Ranked 1st, prof. gave me 65/100.
<D> Got ranked second with 70/100
Obviously here, student C is lying (at least) on their rank; they can't be 1st with a grade of 65 since both A and D got a better grade.
There can also be cases where someone is lying but we can't know who, specifically.
Rank | Grade
-------------
2 71
1 80
3 60
2 70
Here, one of the two rank-2 students is lying (since two students can't have the same rank while having different grades) but we can't know which one.
Challenge
Create a function or program that, when given a sequence of (rank, grade) tuples which contains exactly one lie, returns the index of the lie in the list or a sentinel value if is impossible to know.
A lie is a tuple that, when removed from the list, makes the list valid (i.e. without any conflicting ranks/grades).
A valid list contains all the possible ranks starting from 1 (or 0 if you use 0-indexing), so the rank sequence 1 2 3
is valid while 2 3 4
is not. The only way to not have every possible rank is when there are equal grades, in which case you can get sequences like 1 2 2
or 1 2 3 3 3
.
Multiple tuples may have the same grade, in which case they will have the same rank, and other tuples' ranks will not be affected. Two tuples having the second-best grade will lead to the sequence 1 2 2 4 ...
.
The input format is not fixed, you may use whatever is easier to parse for your language (a 2D int array, a list of tuples, a list of strings containing space-separated ints). The logic is more important than the parser's implementation details.
The output format is not fixed either. The "index" returned may be 0-based or 1-based, and the sentinel value can be anything that is clearly distinguishable from an index (if you're using 1-based indexing, 0 is a valid sentinel value).
Test Cases
Rank | Grade
-------------
2 71
1 80
3 60
2 70
Output: impossible to know
Rank | Grade
-------------
1 85
3 50
1 65
2 70
Output: third student
Rank | Grade
-------------
1 85
3 50
1 65
2 70
Output: third student
Additional cases, thanks to @tsh:
[(1, 100), (2, 60), (3, 90), (3, 90)]
-> invalid input because we can't remove a single item to get a valid list[(1, 100), (1, 100), (2, 90), (3, 90)]
-> fourth (if we remove the third we get an invalid list with ranks [1, 1, 3])
This is code-golf, so the lowest byte count for each language wins!
EDIT: printing multiple values is a valid sentinel as long as you specify it. 0-indexing for ranks is fine too.