The reason that the queue is full when the size is N-1 is that in this simple implementation, 'r' represents the index of the next free element and 'f' represents the next element to retrieve. If 'f' and 'r' are equal, the queue is empty, so the queue is full if incrementing 'r' would result in it being equal to 'f'.
In this implementation, at least one element is always empty. This usually is more efficient than adding more logic to differentiate the case where the 'f' and 'r' is equal and the queue is full vs the case where it is empty.
BTW, in most processors the mod function is a lot more expensive than using logic like this:
Algorithm enqueue(e):
rNext<---r + 1
if rNext = N
rNext<---0
if rNext = r then
throw a FullQueueException
r<---rNext
Q[r]<---e