Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Mark a UKMT IMC Paper

I did the IMC this year. Did anyone else here do it?

In a UKMT Intermediate Maths Challenge paper, there are twenty-five questions. The first fifteen questions give you five marks if you get them right. For the other ten questions, you get six marks for getting them right. In the last ten questions, you lose marks if you get them wrong! For questions sixteen to twenty, you lose one marks and for the last five questions, you lose two marks. If you leave a question blank, no marks are awarded or deducted. No marks are deducted for getting any of the first fifteen questions wrong. The paper is multiple choice; you can choose any answer out of A, B, C, D and E for each question. There is always just one right answer for each question.

Create a program/function that takes two strings and outputs a score. The first string will be your answers to the paper. If you skip a question, use a space, a null byte or an underscore. Otherwise, use the letter A, B, C, D or E for the answer. You can either have the inputs uppercase or lowercase. The second string will be the correct answers for each question in the paper. Your program/function will then output a score. Make your code short.

Test cases:

DDDDDDDDDDDDDDDDDDDDDDDDD
ABCDEABCDEABCDEABCDEABCDE
15

BDBEACCECEDDBDABBCBDAEBCD
BDBEACCECEDDBDABBCBDAEBCD
135

DBACBDCDBAEDABCDBEECACDC_
DBADBDCDBAEDABCDBEEDACDCA
117

_________________________
DABDABDABDABDABDABDABDABD
0

DBADBDCDBAEDABCD_E__A__C_
DBADBDCDBAEDABCDBEEDACDCA
99

_______________BBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAA
-15
share|improve this question
    
Should "For questions fifteen to twenty" be "For questions sixteen to twenty"? – Greg Martin 22 hours ago
1  
Can we use a null byte to represent skipped questions? – betseg 22 hours ago
2  
And shouldn't the first score be 27-12=15? – Greg Martin 21 hours ago
1  
Has anyone seen/done the UKMT papers? They are really fun. Check out the puzzles at ukmt.org.uk. I get most of my ideas for challenges from maths questions. – J843136028 19 hours ago
1  
Your test cases should probably include a submission with a negative score. – Dennis 17 hours ago

10 Answers 10

C, 88 87 86 81 bytes

c,d;i(char*a,char*b){for(c=d=0;*b;c++,a++)d+=*a^*b++?*a?-c/15-c/20:0:5+c/15;d=d;}

Try it online!

share|improve this answer
1  
Since ABCDE are all below the point 95, I think you can use *a<95. – TuukkaX 18 hours ago
2  
Since the question allows taking null byte instead of underscores, -(c/15+c/20)*(*a<95) can become *a?-c/15-c/20:0. – Dennis 15 hours ago

Jelly, 26 23 22 bytes

=s5ị"“HHHQP‘D¤_2Fæ.n⁶¥

Try it online!

How it works

=s5ị"“HHHQP‘D¤_2Fæ.n⁶¥  Main link. Argument: t (answer to test), s (answer sheet)

=                       Test the characters of t and s for equality.
 s5                     Split into chunks of length 5.
             ¤          Combine the two preceding links into a niladic chain.
     “HHHQP‘              Yield the code points, i.e., [72, 72, 72, 81, 80].
            D             Decimal; yield [[7, 2], [7, 2], [7, 2], [8, 1], [8, 0]].
   ị"                   Index zipwith; use the Booleans in each chunk to index into
                        the corresponding pair. Indexing is 1-based and modular, so
                        1 gives the first element and 0 the last.
              _2        Subtract 2 from each result.
                F       Flatten the resulting 5x5 matrix.
                     ¥  Combine the two preceding links into a dyadic chain.
                   n⁶     Test the characters of t for inequality with space.
                 æ.     Take the dot product of the integers to the left and the
                        Booleans to the right.
share|improve this answer

JavaScript (ES6), 70 68 66 bytes

Saved 2 bytes thanks to Neil
Saved 2 bytes thanks to ETHproductions

Takes applicant answers a and correct answers c in currying syntax (a)(c). Expects skipped questions to be marked with a space.

a=>c=>a.replace(/\S/g,(a,i)=>s+=a==c[j=i>14,i]?5+j:-j^i>19,s=0)&&s

Test cases

let f =

a=>c=>a.replace(/\S/g,(a,i)=>s+=a==c[j=i>14,i]?5+j:-j^i>19,s=0)&&s

console.log(f
  ("DDDDDDDDDDDDDDDDDDDDDDDDD")
  ("ABCDEABCDEABCDEABCDEABCDE")
);
console.log(f
  ("BDBEACCECEDDBDABBCBDAEBCD")
  ("BDBEACCECEDDBDABBCBDAEBCD")
);
console.log(f
  ("DBACBDCDBAEDABCDBEECACDC ")
  ("DBADBDCDBAEDABCDBEEDACDCA")
);
console.log(f
  ("                         ")
  ("DABDABDABDABDABDABDABDABD")
);
console.log(f
  ("DBADBDCDBAEDABCD E  A  C ")
  ("DBADBDCDBAEDABCDBEEDACDCA")
);
console.log(f
  ("               BBBBBBBBBB")
  ("AAAAAAAAAAAAAAAAAAAAAAAAA")
);

share|improve this answer
    
If you change the skipped question to a non-word character (e.g. space) then you can use /\w/g to save you two bytes. – Neil 19 hours ago
    
I think -j-(i>19) is the same as -j^i>19, though I'm not certain. – ETHproductions 16 hours ago
    
@ETHproductions Indeed. This is parsed as (-j)^(i>19) so, yes, this works. – Arnauld 11 hours ago

Mathematica, 114 bytes

Tr@(m=MapThread)[#/.True->#2/.False->-#3&,{Tr/@Partition[m[Equal,#/."_"->u]/.u==_->0,5],{5,5,5,6,6},{0,0,0,1,2}}]&

Pure function taking an ordered pair of lists of characters and returning an integer. m[Equal,#/."_"->u] returns a list of booleans, except for unevaluated entries of the form u=="B" in places where the answer equaled "_"; then right away, u==_->0 turns those unevaluated entries into 0s. Tr/@Partition[...,5] adds these entries up 5 at a time, resulting in a list like {4False+True, 4False+True, 4False+True, 4False+True, 4False+True} for the first test case or {5True, 5True, 5True, 2True, 2True} for the last test case. Then in each coordinate, True and False are mapped to the appropriate scores, and the results are added together.

share|improve this answer

Python 2, 93 91 bytes

f=lambda a,b,n=0:a>""and((a[0]==b[0])*(5+n/15)or-(n/15*n/10)*(a[0]<"^"))+f(a[1:],b[1:],n+1)

Try it online!

-2 bytes thanks to @KritixiLithos


Input:

  • a : Answers of the student as a string, _ for skipped question
  • b : correct answers
  • n : the number of the current question 0-based, defaults to 0
share|improve this answer
    
You can do a[0]<'^' instead of a[0]!="_" to save bytes – Kritixi Lithos 20 hours ago
    
I think a>"" can work instead of a!="" – Kritixi Lithos 20 hours ago
    
If your initial check is just ending the recursion when a is empty, can't you just do a and? An empty string is false, otherwise it's true. – FlipTack 14 hours ago
    
@FlipTack this would throw a TypeError as the the last recursive call would return a string – ovs 14 hours ago

k, 52 bytes

Function takes 2 strings, format per the test cases

{+/(~x="_")*(+,/'(15 5 5#'0 -1 -2;15 10#'5 6))@'x=y}

Example:

k){+/(~x="_")*(+,/'(15 5 5#'0 -1 -2;15 10#'5 6))@'x=y}["DBADBDCDBAEDABCD_E__A__C_";"DBADBDCDBAEDABCDBEEDACDCA"]
99
share|improve this answer

Haskell, 84 bytes

i x a b|a>'Z'=0|a==b=6-0^x|1<2= -x
w x=x<$[1..5*3^0^x]
(sum.).zipWith3 i(w=<<[0..2])

Usage example: ((sum.).zipWith3 i(w=<<[0..2])) "DBADBDCDBAEDABCD_E__A__C_" "DBADBDCDBAEDABCDBEEDACDCA" -> 99. Try it online!.

How it works: i x a b calculates the score for a single answer a with correct result b and the penalty x for a wrong answer (a non-negative value). If you skip (a>'Z'), the score is 0, if the answer is right (a==b), the score is 6-0^x, else the score is -x.

w=<<[0..2] makes a list of penalties for all 25 questions by applying w to 0, 1 and 2, i.e. making 5*3^0^x copies of each number (-> 15 times 0, 5 times 1 and 5 times 2).

zipWith3 applies i to the list of penalties, list of answers and list of correct results. Finally all scores are added (sum).

share|improve this answer

JavaScript (ES6), 105 103 101 94 89 88 85 84 78 bytes

My first solution in ES6, maybe even first in Javascript O.o

s=>a=>eval([...s].map((c,i)=>c>'Z'?0:c==a[i]?5+(i>14):~(i>19)*(i>14)).join`+`)

Takes input with a currying syntax (s)(a), where s is the submitted solution and a is the correct solution. Both will be taken as strings.

Thanks to @ETHproductions for saving 9 bytes! s[i] to c and (-1-(i>19|0)) to ~(i>19).

Thanks to @Kritixi Lithos for saving a byte! c=='_' to c>'Z'.

Try it online!

share|improve this answer
    
Talking of this being your first solution in JS, what is your main language for code golf? I've only ever used Python and brainfuck for code golf. – J843136028 18 hours ago
    
@J843136028 My main language is Python, but I have golfed quite a bit with C# too. Haxe has been laying off for a while, but I might return to it. – TuukkaX 18 hours ago
    
Cool! I've only ever used brainfuck once, so my main language is Python too. – J843136028 18 hours ago
    
@J843136028 Yeah, I've actually seen your answers here and there. As my bio yields, I don't spend that much time figuring out solutions, so they aren't of interest most of the time. I've only done so little with BrainF*ck, as it takes a lot of time to find short solutions, even to intermediate problems. – TuukkaX 18 hours ago
    
I know what you mean about BF. I'm surprised people look at my answers. – J843136028 17 hours ago

Python 2, 86 85 83 77 bytes

f=lambda t,s,i=24:~i and(i/10*-(14<i<t[i]<'_'),5+i/15)[t[i]==s[i]]+f(t,s,i-1)

Try it online!

How it works

This defines a recursive function f that takes two non-optimal arguments: t (the answers to the test) and s (the answer sheet). When called only with these two arguments, f initializes i to 24, the last index of both t and s.

Every time f is called, it first checks if ~i (the bitwise NOT of i) is truthy/non-zero. Since ~(-1) = 0, this happens once the i reaches the value -1. If i = -1, ~i = 0 is returned, but as i takes values from 24 to 0 (all indices of t and s), the code following and is executed and f returns the result.

While i is non-negative, the following happens. First,

(i/10*-(14<i<t[i]<'_'),5+i/15)

creates a tuple of length 2:

  • The quotient i/10 is 0 if 0 ≤ i < 10, 1 if 10 ≤ i < 20, and 2 if 20 ≤ i < 25. The chained comparison 14<i<t[i]<'_' returns True if and only if all individual comparisons return True, i.e., if and only if i ≥ 15 (the range of questions with penalty), i is smaller than t[i] (always true since all numbers are smaller than all iterables in Python 2), and t[i] is not an underscore.

    If the comparison returns False, the unary - returns 0 and the entire expression evaluates to 0. However, if the comparison returns True, the unary - returns -1, so the entire expression evaluates to 0 if 0 ≤ i < 10, -1 if 10 ≤ i < 20, and -2 if 20 ≤ i < 25; these are the net results for wrong or missing answers for all indices i.

  • 5+i/15 returns 5 + 0 = 5 if 0 ≤ i < 15 and 5 + 1 = 6 if 15 ≤ i < 25. These are the net results for correct answers for all indices i.

Finally, [t[i]==s[i]] selects the first element of the constructed tuple if t[i] and s[i] differ (wrong or missing answer) and the second one if they are equal (correct answer), then adds the return value of f called with decremented i to that result. Once i reaches -1, the final score has been computed and is returned by f.

share|improve this answer

Octave, 61 54 bytes

@(a,b)[a==b,-(a<95&a~=b)]*[(x=1:25>15)+5,(1:25>20)+x]'

Try it online!

Previous answer:

@(a,b)(m=a==b)*(((f=kron(z=[0 0 0:2],z|1)')&1)+5)-(a<95&~m)*f
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.