Play around with the Chaos game!

Write your own code to calculate where the next point should be. The default code simply picks one of the vertices at random and moves the current point halfway there. But you can change that using functions, operators, and whatever else you can find in MathJS. You can use the coordinates of the current point, currentPoint, and the coordinates of each target vertex, targetPoints. Both are matrices. All you must do is set the nextPoint variable to either an array of two numbers like [100, 200] or a matrix like [[100, 200]].

The following functions are usually used in the optional initialization code:
Advanced example - The Levy C curve fractal:
zoom(325)
A = matrix([[.5,  .5], [-.5, .5]])
B = matrix([[.5, -.5], [ .5, .5]])
point1 = transpose(multiply(A, transpose(currentPoint)))
point2 = transpose(multiply(B, transpose(currentPoint)) - transpose(matrix([[.5, .5]])))
nextPoint = randomInt() ? point1 : point2
Advanced example - Avoid previous target vertex:
# IMPORTANT! Put these two lines in the "Optional initialization code" pane.
previous_vertex = -1  # start with a non-existing vertex
slider = userControl("how far to go toward the target", -2, 1.4, .5)

# The rest of this code goes in the main pane

# Get all possible indices except the vertex we used in the last iteration
_possibleTargetIndices = math.range(1, targetPointsLength+1)
_possibleTargetIndices = _possibleTargetIndices[_possibleTargetIndices != previous_vertex]

# Pick a random target vertex
_nextTargetIndex = math.pickRandom(_possibleTargetIndices)
# ... and get its coordinates
_nextTarget = targetPoints[_nextTargetIndex, :]

# Make next point midway to the target
nextPoint = (currentPoint + _nextTarget) * slider

# Store current vertex for next iteration
previous_vertex = _nextTargetIndex
Advanced example - The Corcoran Attractor:
# try sine_scale of 1/3 and 12 vertices with a 3 million points and 0.1 opacity!
nextTargetIndex = math.randomInt(1, targetPointsLength+1)
_nextTarget = targetPoints[nextTargetIndex, :]

# Create user controls for the parameters
sine_shift = userControl("Sine shift", 0, 2*math.pi, math.pi*29/25)
sine_scale = userControl("Sine scale", -3/2, 4, 1/2)
sine_offset = userControl("Sine offset", -1, 7/4, 1/2)

displacement_factors = math.matrix([
  [math.sin(_nextTarget[1,2] + sine_shift) * sine_scale + sine_offset,
   math.sin(_nextTarget[1,1] + sine_shift) * sine_scale + sine_offset]
])
# Apply the factors to the displacement
displacement_to_target = _nextTarget - currentPoint
nextPoint = currentPoint + math.dotMultiply(displacement_to_target, displacement_factors)


Examples:

Add 1 to both x and y:
nextPoint = currentPoint + 1
With rotation:
nextTargetIndex = math.randomInt(1, targetPointsLength+1)
_nextTarget = targetPoints[nextTargetIndex, :]
midpoint = (currentPoint + _nextTarget) / 2
rotation = [[math.cos(math.pi/4), -math.sin(math.pi/4)], [math.sin(math.pi/4), math.cos(math.pi/4)]]
nextPoint = math.multiply(midpoint, rotation)

source   3D version