Computer Cipher
Perl 6, 125 bytes
->\n{*.&{S:g{.}=(65..90)>>.chr.roll(n).join.subst(/./,$/,:th($!=roll 1..n:)).subst(/./,$!,:th($!-1??(^n+1∖$!).roll!!n+1))}}
Try it online!
Takes input and output in uppercase. Takes input curried, like f(n)(string)
. Uses 1 indexing.
Explanation:
->\n{*.&{ ... }} # Anonymous code block that takes a number n and returns a function
S:g{.}= # That turns each character of the given string into
.roll(n) # Randomly pick n times with replacement
(65..90)>>.chr # From the uppercase alphabet
.join # And join
.subst( ) # Then replace
/./, ,:th($!=roll 1..n:) # A random index (saving the number in $!)
$/ # With the original character
.subst( ) # Replace again
/./,$!,:th( ... ) # The xth character with $!, where x is:
$!-1?? # If $! is not 1
(^n+1∖$!).roll # A random index that isn't $!
!!n+1 # Else an index out of range
Python 2, 187 177 176 156 154 148 bytes
lambda l,s:''.join([chr(choice(R(65,91))),c,`n`][(j==n)-(j==i)*(n>0)]for c in s for n,i in[sample(R(l),2)]for j in R(l))
from random import*
R=range
Try it online!
Uses uppercase letters, and 0-indexed numbers.
-3 bytes, thanks to Kevin Cruijssen
JavaScript (Node.js), 135 bytes
n=>f=([c,...s])=>c?(g=n=>n?g(--n)+(n-p?n-q|!p?(r(26)+10).toString(36):p:c):'')(n,r=n=>Math.random()*n|0,p=r(n),q=r(n-1),q+=q>=p)+f(s):s
Try it online!
Thank Arnauld for 1B