mirror of
				https://github.com/bspeice/speice.io
				synced 2025-11-04 02:20:36 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			97 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
export const DEFAULT_SIZE: number = 400;
 | 
						|
 | 
						|
/**
 | 
						|
 * Image render manager
 | 
						|
 *
 | 
						|
 * This class tracks the chaos game state so we can periodically
 | 
						|
 * get an image.
 | 
						|
 */
 | 
						|
export abstract class Renderer {
 | 
						|
  /**
 | 
						|
   * Build a render manager. For simplicity, this class assumes
 | 
						|
   * we're working with a square image.
 | 
						|
   *
 | 
						|
   * @param size Image width and height
 | 
						|
   */
 | 
						|
  constructor(public readonly size: number) {}
 | 
						|
 | 
						|
  /**
 | 
						|
   * Run the chaos game
 | 
						|
   *
 | 
						|
   * @param quality iteration count
 | 
						|
   */
 | 
						|
  abstract run(quality: number): void;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Output the current chaos game state to image
 | 
						|
   *
 | 
						|
   * @param image output pixel buffer
 | 
						|
   */
 | 
						|
  abstract render(image: ImageData): void;
 | 
						|
}
 | 
						|
 | 
						|
export type RenderParams = {
 | 
						|
  quality: number;
 | 
						|
  renderer: (size: number) => Renderer;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @returns random number in the bi-unit square (-1, 1)
 | 
						|
 */
 | 
						|
export function randomBiUnit() {
 | 
						|
  // Math.random() produces a number in the range [0, 1),
 | 
						|
  // scale to (-1, 1)
 | 
						|
  return Math.random() * 2 - 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @returns random integer (with equal weight) in the range [min, max)
 | 
						|
 */
 | 
						|
export function randomInteger(min: number, max: number) {
 | 
						|
  return Math.floor(Math.random() * (max - min)) + min;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param choices array of [weight, value] pairs
 | 
						|
 * @returns pair of [index, value]
 | 
						|
 */
 | 
						|
export function weightedChoice<T>(choices: [number, T][]): [number, T] {
 | 
						|
  const weightSum = choices.reduce(
 | 
						|
    (current, [weight, _t]) => current + weight,
 | 
						|
    0
 | 
						|
  );
 | 
						|
  var choice = Math.random() * weightSum;
 | 
						|
 | 
						|
  for (var i = 0; i < choices.length; i++) {
 | 
						|
    const [weight, t] = choices[i];
 | 
						|
    if (choice < weight) {
 | 
						|
      return [i, t];
 | 
						|
    }
 | 
						|
 | 
						|
    choice -= weight;
 | 
						|
  }
 | 
						|
 | 
						|
  throw "unreachable";
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param x pixel coordinate
 | 
						|
 * @param y pixel coordinate
 | 
						|
 * @param width image width
 | 
						|
 * @returns index into ImageData buffer for a specific pixel
 | 
						|
 */
 | 
						|
export function imageIndex(x: number, y: number, width: number) {
 | 
						|
  // Taken from: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas
 | 
						|
  return y * (width * 4) + x * 4;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param x pixel coordinate
 | 
						|
 * @param y pixel coordinate
 | 
						|
 * @param width image width
 | 
						|
 * @returns index into a histogram for a specific pixel
 | 
						|
 */
 | 
						|
export function histIndex(x: number, y: number, width: number) {
 | 
						|
  return y * width + x;
 | 
						|
}
 |