|
| 1 | +package gomouse |
| 2 | + |
| 3 | +import ( |
| 4 | + cryptorand "crypto/rand" |
| 5 | + "encoding/binary" |
| 6 | + "math" |
| 7 | + "math/rand" |
| 8 | +) |
| 9 | + |
| 10 | +// MouseSettings initiate the mouse settings |
| 11 | +type MouseSettings struct { |
| 12 | + StartX float64 |
| 13 | + StartY float64 |
| 14 | + EndX float64 |
| 15 | + EndY float64 |
| 16 | + Gravity float64 |
| 17 | + Wind float64 |
| 18 | + MinWait float64 |
| 19 | + MaxWait float64 |
| 20 | + MaxStep float64 |
| 21 | + TargetArea float64 |
| 22 | +} |
| 23 | + |
| 24 | +func RandomNumberFloat() float64 { |
| 25 | + // avoid pitfalls of clock based seed value |
| 26 | + var b [8]byte |
| 27 | + _, err := cryptorand.Read(b[:]) |
| 28 | + if err != nil { |
| 29 | + panic("cannot seed math/rand package with cryptographically secure random number generator") |
| 30 | + } |
| 31 | + |
| 32 | + r := rand.New(rand.NewSource(int64(binary.LittleEndian.Uint64(b[:])))) |
| 33 | + return r.Float64() |
| 34 | +} |
| 35 | + |
| 36 | +func hypot(dx, dy float64) float64 { |
| 37 | + return math.Sqrt(dx*dx + dy*dy) |
| 38 | +} |
| 39 | + |
| 40 | +func GeneratePoints(settings MouseSettings) [][]float64 { |
| 41 | + if settings.Gravity < 1 { |
| 42 | + settings.Gravity = 1 |
| 43 | + } |
| 44 | + |
| 45 | + if settings.MaxStep == 0 { |
| 46 | + settings.MaxStep = 0.01 |
| 47 | + } |
| 48 | + |
| 49 | + windX := math.Floor(RandomNumberFloat() * 10) |
| 50 | + windY := math.Floor(RandomNumberFloat() * 10) |
| 51 | + |
| 52 | + var oldX float64 |
| 53 | + var oldY float64 |
| 54 | + newX := math.Floor(settings.StartX) |
| 55 | + newY := math.Floor(settings.StartY) |
| 56 | + |
| 57 | + waitDiff := settings.MaxWait - settings.MinWait |
| 58 | + |
| 59 | + // Hardcore instead of doing math.sqrt, maybe saving us some computiong time |
| 60 | + sqrt2 := 1.4142135623730951 |
| 61 | + sqrt3 := 1.7320508075688772 |
| 62 | + sqrt5 := 2.23606797749979 |
| 63 | + |
| 64 | + var randomDist float64 |
| 65 | + var velocityX float64 = 0 |
| 66 | + var velocityY float64 = 0 |
| 67 | + var dist float64 |
| 68 | + var veloMag float64 |
| 69 | + var step float64 |
| 70 | + |
| 71 | + var points [][]float64 |
| 72 | + var currentWait float64 = 0 |
| 73 | + |
| 74 | + dist = hypot(settings.EndX-settings.StartX, settings.EndY-settings.StartY) |
| 75 | + |
| 76 | + for dist > 1.0 { |
| 77 | + settings.Wind = math.Min(settings.Wind, dist) |
| 78 | + |
| 79 | + if dist >= settings.TargetArea { |
| 80 | + w := math.Floor(RandomNumberFloat()*math.Round(settings.Wind)*2 + 1) |
| 81 | + |
| 82 | + windX = windX/sqrt3 + (w-settings.Wind)/sqrt5 |
| 83 | + windY = windY/sqrt3 + (w-settings.Wind)/sqrt5 |
| 84 | + } else { |
| 85 | + windX = windX / sqrt2 |
| 86 | + windY = windY / sqrt2 |
| 87 | + |
| 88 | + if settings.MaxStep < 3 { |
| 89 | + settings.MaxStep = math.Floor(RandomNumberFloat()*3) + 3.0 |
| 90 | + } else { |
| 91 | + settings.MaxStep = settings.MaxStep / sqrt5 |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + velocityX += windX |
| 96 | + velocityY += windY |
| 97 | + velocityX = velocityX + (settings.Gravity*(settings.EndX-settings.StartX))/dist |
| 98 | + velocityY = velocityY + (settings.Gravity*(settings.EndY-settings.StartY))/dist |
| 99 | + |
| 100 | + if hypot(velocityX, velocityY) > settings.MaxStep { |
| 101 | + randomDist = settings.MaxStep/2.0 + math.Floor((RandomNumberFloat()*math.Round(settings.MaxStep))/2) |
| 102 | + veloMag = hypot(velocityX, velocityY) |
| 103 | + velocityX = (velocityX / veloMag) * randomDist |
| 104 | + velocityY = (velocityY / veloMag) * randomDist |
| 105 | + } |
| 106 | + |
| 107 | + oldX = math.Round(settings.StartX) |
| 108 | + oldY = math.Round(settings.StartY) |
| 109 | + |
| 110 | + settings.StartX += velocityX |
| 111 | + settings.StartY += velocityY |
| 112 | + |
| 113 | + dist = hypot(settings.EndX-settings.StartX, settings.EndY-settings.StartY) |
| 114 | + |
| 115 | + newX = math.Round(settings.StartX) |
| 116 | + newY = math.Round(settings.StartY) |
| 117 | + |
| 118 | + step = hypot(settings.StartX-oldX, settings.StartY-oldY) |
| 119 | + wait := math.Round(waitDiff*(step/settings.MaxStep) + settings.MinWait) |
| 120 | + |
| 121 | + currentWait += wait |
| 122 | + |
| 123 | + if oldX != newY || oldY != newY { |
| 124 | + points = append(points, []float64{ |
| 125 | + newX, |
| 126 | + newY, |
| 127 | + currentWait, |
| 128 | + }) |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + return points |
| 133 | +} |
0 commit comments