Task

Given a string of characters A, C, G, and T representing a DNA sequence write a routine to mutate the sequence, (string) by:

 Choosing a random base position in the sequence.
 Mutate the sequence by doing one of either:
 Swap the base at that position by changing it to one of A, C, G, or T. (which has a chance of swapping the base for the same base)
 Delete the chosen base at the position.
 Insert another base randomly chosen from A,C, G, or T into the sequence at that position.
 Randomly generate a test DNA sequence of at least 200 bases
 "Pretty print" the sequence and a count of its size, and the count of each base in the sequence
 Mutate the sequence ten times.
 "Pretty print" the sequence after all mutations, and a count of its size, and the count of each base in the sequence.
Extra credit

 Give more information on the individual mutations applied.
 Allow mutations to be weighted and/or chosen.
var [const] bases="ACGT", lbases=bases.toLower();
dna:=(190).pump(Data().howza(3),(0).random.fp(0,4),bases.get); // bucket of bytes
 
foreach s,m in (T("Original","Mutated").zip(T(True,False))){
   println("\n",s," DNA strand:"); dnaPP(dna);
   println("Base Counts: ", dna.len()," : ",
      dna.text.toUpper().counts()	// ("A",5, "C",10, ...)
      .pump(String,Void.Read,"%s(%d) ".fmt));
   if(m) mutate(dna,10,True);
}
 
fcn mutate(dna,count=1,verbose=False){
   if(verbose) println("Mutating:");
   do(count){ 
      n,rb := (0).random(dna.len()), lbases[(0).random(4)];
      switch( (0).random(3) ){
	 case(0){ if(verbose) println("Change[%d] '%s' to '%s'".fmt(n,dna.charAt(n),rb));
	    dna[n]=rb;
	 }
	 case(1){ if(verbose) println("Delete[%d] '%s'".fmt(n,dna.charAt(n)));
	    dna.del(n);
	 }
	 else{	  if(verbose) println("Insert[%d] '%s'".fmt(n,rb));
	    dna.insert(n,rb);
	 }
      }
   }
}
 
fcn dnaPP(dna,N=50){
   [0..*,50].zipWith(fcn(n,bases){ println("%6d: %s".fmt(n,bases.concat())) },
      dna.walker().walk.fp(50)).pump(Void);  // .pump forces the iterator
}