83 76 67 bytes
Just realized that I can save several bytes by not bothering to check if the candidate urinals are empty. Non-empty urinals will always return an
Inf discomfort value, so they're excluded in the course of the calculation. Also, just using direct indexing rather than
replace, so it's shorter but less elegant.
We read the current state from stdin and call it
x. We assume that the input is a sequence of
0s separated by spaces or newlines. For the purposes of the explanation, let's say we input
1 0 0 0 0 0 1.
We replace a value of
x at a particular index with 1. Everything between the
[ ] is figuring out what the best index is.
Since the existing urinals are immutable, we don't need to consider the distances between them. We only need to consider the distances between the occupied urinals and the possible new one. So we determine the indices of the occupied urinals. We use
which, a function to return the indices of a logical vector which are
TRUE. All numbers in R, when coerced to type
TRUE if nonzero and
FALSE if zero. Simply doing
which(x) will result in a type error,
argument to 'which' is not logical, as
x is a numeric vector. We therefore have to coerce it to logical.
! is R's logical negation function, which automatically coerces to logical. Applying it twice,
!!x, yields a vector of
FALSE indicating which urinals are occupied. (Alternative byte-equivalent coercions to logical involve the logical operators
| and the builtins
T&x and so on.
!!x looks more exclamatory so we'll use that.)
This is paired with
seq(x), which returns the integer sequence from
1 to the length of
x, i.e. all urinal locations (and thus all possible locations to consider).
Now we have the indices of our occupied urinals:
1 7 and our empty urinals
1 2 3 4 5 6 7. We pass
`-`, the subtraction function, to the
outer function to get the "outer subtraction", which is the following matrix of distances between all urinals and the occupied urinals:
[1,] 0 -6
[2,] 1 -5
[3,] 2 -4
[4,] 3 -3
[5,] 4 -2
[6,] 5 -1
[7,] 6 0
We raise this to the
-2th power. (For those who are a little lost, in the OP, "discomfort" is defined as
1 / (distance(x, y) * distance(x, y)), which simplifies to
Take the sum of each row in the matrix.
Get the index of the smallest value, i.e. the optimal urinal. In the case of multiple smallest values, the first (i.e. leftmost) one is returned.
And voilà, we have the index of the optimal urinal. We replace the value at this index in
1. In the case of
1111 as input, it doesn't matter which one we replace, we'll still have a valid output.
Return the modified input.