Week 1 Assignment – Self-Avoiding Walk

For this week’s assignment, I chose to make a random self-avoiding walker. First, I started by looking at the P5JS example of it and took inspiration from it.

But it wasn’t enough. So, I have started looking for ways to make the walk not get stuck. For that, I have modified  the approach to continuously attempt to find a path by using a backtracking method. It took me a few tries, but I have eventually got there.

After everything, I have added the function to change colors everytime it changes directions. This was not as hard because we have tried it in class.

 

 

let spacing = 20;
let cols, rows;
let x, y;
let grid;
let allOptions = [
  { dx: 0, dy: 1 },
  { dx: 1, dy: 0 },
  { dx: 0, dy: -1 },
  { dx: -1, dy: 0 },
];
let stack = [];
let currentColor;

function setup() {
  createCanvas(400, 400);
  cols = width / spacing;
  rows = height / spacing;
  x = floor(cols / 2);
  y = floor(rows / 2);
  background(51);
  grid = Array.from({ length: cols }, () => Array(rows).fill(false));
  grid[x][y] = true;
  stack.push([x, y]);
  currentColor = pastelColor();
}

function draw() {
  stroke(currentColor);
  strokeWeight(spacing * 0.5);
  point(x * spacing, y * spacing);

  let options = allOptions.filter((option) =>
    isValid(x + option.dx, y + option.dy)
  );

  if (options.length > 0) {
    let step = random(options);
    strokeWeight(1);
    stroke(currentColor);
    line(
      x * spacing,
      y * spacing,
      (x + step.dx) * spacing,
      (y + step.dy) * spacing
    );

    x += step.dx;
    y += step.dy;
    grid[x][y] = true;
    stack.push([x, y]);
    currentColor = pastelColor();
  } else {
    if (stack.length > 1) {
      stack.pop();
      [x, y] = stack[stack.length - 1];
    } else {
      noLoop();
    }
  }
}

function isValid(i, j) {
  return grid[i]?.[j] === false && i >= 0 && i < cols && j >= 0 && j < rows;
}

function pastelColor() {
  return color(random(200, 255), random(200, 255), random(200, 255));
}

For the future, I think that I would like to make it more complex. Maybe I can make two of them and make it collide and when they do something happens. Until then, I am pretty pleased with the outcome

Week 1- Reading Response

Reductionism and holism offer two different ways to understand complex things, whether it’s in science or something as simple as making lasagna. With reductionism, you break down the process—like learning to cook pasta perfectly, making a sauce, and picking the right cheese. You focus on each part separately, mastering them one at a time. Once you’ve got each piece down, you bring it all together step by step to create the final dish. This approach helps you understand every part deeply before putting it all together.

Holism, on the other hand, is about seeing the dish as a whole, thinking about how the ingredients and flavors interact to create something greater than just the sum of its parts. Instead of focusing only on individual components, you consider how they work together—like adjusting the seasoning based on the cheese or layering ingredients to balance flavors and textures. Holism encourages you to think about the overall harmony of the dish, resulting in a richer, more complex lasagna.

Using food to explain my thought process is easy because of my love for it, but on a more serious note, I believe that both reductionism and holism are valuable approaches. Depending on the situation, one might be more useful than the other. Sometimes it’s better to focus on the details, while other times it’s best to look at the big picture. Understanding when to use each approach can help you navigate and understand complex systems more effectively.

Week 1 – Dynamic Random Walker

This project explores a unique blend of randomness and user interaction through a dynamic color random walk. The random walker is designed with two key features that make its movement and visual output both unpredictable and engaging.

Key Features:

  1. Biased Random Movement:
    • The random walk incorporates a 40% probability of moving towards the direction of the user’s mouse, introducing an element of interactivity. The remaining 60% of the time, the walker moves in a random direction. However, this randomness is also biased; the walker does not have an equal probability of moving left, right, up, or down, which introduces subtle variations in the walker’s path and adds complexity to its movement.
  2. Dynamic Color Evolution:
    • The visual aspect of the walker’s path is enhanced by a dynamic color mapping that evolves as the walker moves across the canvas. The color of each point is determined by its x coordinate, creating a spectrum of hues that shift horizontally across the canvas. Simultaneously, the brightness of each point is mapped to the y coordinate, resulting in a gradient that changes vertically. This color evolution adds a rich, visual narrative to the walker’s journey.
  3. Spatial Harmony:
    • To ensure the visual clarity of the path, the walker only draws a point if it has moved a minimum distance from its previous position. This spacing prevents the points from overlapping, creating a more aesthetically pleasing and well-defined pattern.

Code

let walker;
let stepSize = 8;  
let minDistance = 30; 

function setup() {
  createCanvas(600, 600);
  walker = new ColorWalker();
  background(0); 
}

function draw() {
  walker.step();
  walker.render();
}

class ColorWalker {
  constructor() {
    this.x = width / 2;
    this.y = height / 2;
    this.prevX = this.x;
    this.prevY = this.y;
  }

  step() {
    let direction = random(1) < 0.3 ? 0 : 1;
    let moveX = 0;
    let moveY = 0;

    if (direction === 0) {
      if (mouseX > this.x) {
        moveX = stepSize;
      } else if (mouseX < this.x) {
        moveX = -stepSize;
      }

      if (mouseY > this.y) {
        moveY = stepSize;
      } else if (mouseY < this.y) {
        moveY = -stepSize;
      }
    } 
    else {
      let choice = random(1);
      if (choice <= 0.4) {
        moveX = stepSize;
      } else if (choice <= 0.6) {
        moveX = -stepSize;
      } else if (choice <= 0.8) {
        moveY = stepSize;
      } else {
        moveY = -stepSize;
      }
    }

    this.x += moveX;
    this.y += moveY;

    
    this.x = constrain(this.x, 0, width - 1);
    this.y = constrain(this.y, 0, height - 1);

    
  }

  render() {
    let distance = dist(this.x, this.y, this.prevX, this.prevY);
    
    if (distance > minDistance) {
      let hue = map(this.x, 0, width, 0, 360);
      let brightness = map(this.y, 0, height, 100, 50);
      
      colorMode(HSB, 360, 100, 100);
      strokeWeight(15); 
      stroke(hue, 100, brightness); 
      strokeWeight(15); 
      point(this.x, this.y);

      this.prevX = this.x;
      this.prevY = this.y;
    }
  }
}

Potential Improvements

I want to make this walker a self-avoiding one I think that would be interesting visualization.

Week 1 Reading | Observe!

How does one explain the observable universe? One approach, reductionism, dissects each phenomenon as individual events. While this approach specifies its look over the event, in reality, many variables account for this event to happen. But if we combine those events, they create a system of events within the universe. Flake questions whether this outcome can still explain the universe or collections of phenomena that result in the universe instead.

As such, nature is full of randoms. Too many things to account for. Look not only one, but all.

The Computational Beauty of Nature proposes to look at these variables instead of observing them as system interactions. Patterns, evolutions, iterations. Singular events that when grouped create systems which then we can translate into groups of similar procedures, outcomes, or both.

However, in the quest to explain this universe, I believe that looking at both sides of the coin is a notable way to observe it. Why do sunflowers contain gridlike patterns? One could tap into its molecular structure, others can mathematically argue its most efficient way to store seeds. Regardless, approaching this observation of a sunflower with both ways allows us to understand the universe even better.

Week 1- Snake Game with Dynamic Motion and Color

Concept:

When I first saw the assignment my mind immediately went to the classic Snake game. It’s a simple yet iconic game and I thought it would be interesting to reimagine it with a twist. The idea was to combine the snake’s movement with changing colors making it more visually engaging. I decided to make the snake follow the mouse’s movement so wherever the mouse goes the snake smoothly follows. As the snake moves it doesn’t just chase the mouse it also cycles through a spectrum of colors creating a vibrant visual effect.

I added a basic gameplay mechanic where the snake grows longer each time it eats a food block. The food blocks are placed randomly on the canvas and each one has a unique color. When the snake eats a block it adopts the block’s color and continues to grow. I also wanted to add a challenge: if the snake touches the edge of the canvas it shrinks back to its original size. This keeps the game interesting and adds a layer of difficulty.

Code Highlight:

One part of the code that I’m particularly proud of is the implementation of the color transition. Instead of just having the snake follow the mouse I wanted to make its movement visually interesting by having it change colors smoothly as it moves. Here’s how I did it:

// Update the snake's color through the HSB space
  hueValue = (hueValue + 1) % 360; // Increment the hue value to cycle through colors, reset to 0 after reaching 360
  snakeColor = color(hueValue, 100, 100); // Update the snake's color with the new hue value

  // Draw the snake on the canvas
  for (let i = 0; i < snake.length; i++) { // Loop through each segment of the snake
    fill(snakeColor); // Set the fill color for the current segment
    ellipse(snake[i].x, snake[i].y, 16, 16); // Draw the segment as a circle at the current position
  }

This code snippet ensures that as the snake moves its color gradually shifts through the HSB color space. It cycles through all the hues creating a smooth and continuous color transition. This makes the snake look more dynamic and adds a lot of visual appeal to the game.

Embedded Sketch:

Reflection and Future Improvements:

The project works well overall but there are definitely some areas that could be improved. The boundary detection for instance doesn’t always function perfectly. The idea was to have the snake reset to its original size when it touches the edges of the canvas but this doesn’t always happen as smoothly as I’d like. Sometimes the reset doesn’t trigger right away or the snake’s movement becomes a bit erratic. This is something I’d like to refine in future versions.

I’m also thinking about adding more complexity to the snake’s movement. For example incorporating Perlin noise could make the snake’s movement smoother and more natural giving it an organic feel. Another idea is to experiment with sound. Imagine if the snake’s movement and growth were accompanied by dynamic audio feedback like a change in pitch or tone as the snake grows or when it changes direction. This could add another layer of immersion to the game.

This project was a great starting point for exploring the combination of motion and visual effects in a simple game. There’s a lot of potential for further development and I’m excited to keep experimenting with these ideas and see where they lead.

Week 1 – Reading Response

In this reading, Gary William Flake invites readers on a journey through the world’s complex systems, where simplicity gives rise to complexity. Flake begins by examining the concept of reductionism which is a traditional scientific approach to understanding systems by dissecting them into their smallest components. While reductionism has been a powerful tool in science, enabling breakthroughs in fields from biology to physics, Flake argues that it falls short when grasping the behavior of complex systems. According to Flake, considering the smallest unit of complex system is not enough to understand the behavior of the entire system; for instance, one can not deduce the behavior of the ant colony by considering individual ants or the nervous system by just considering individual neurons. This is the result of what Flake calls holism where the whole system is greater than the sum of the individual parts mainly due to the complex interaction of the individual parts in the system.  The complex interaction among the individual systems can be explained by three attributes namely: Parallelism, Iteration, and Adaptation. These complex interactions of individual units in complex systems among themselves and with their environment make it difficult to use a direct reductionist approach. 

Later in this chapter, Flake turns to discussing the convergence of sciences due to computation. According to Flake, computers have blurred the line between experimentation and theory. This is mainly a result of the simulation of experiments on computers. Through modeling various phenomena, such as weather patterns and brain networks, researchers have discovered general laws that dictate the actions of intricate systems. Thus, Flake establishes the framework for the remainder of the book, which aims to investigate the computational foundations of some of nature’s most complex phenomena, such as adaptive systems and fractals. 

 

Stargazing with a Musical Twist – Week 1

Concept

I’ve always been fascinated by stargazing, but I wanted to create a unique way to experience it. In this interactive sketch, you’re not just a passive observer—you control where the stars appear as you move your mouse across the canvas. To enhance the experience, I created the night sky with faded clouds manually using Perlin noise, inspired by Professor Nimrah’s work from Week 2, rather than using an image from Google. I adjusted this technique to fit my needs, resulting in a serene and dynamic background. For the interactive elements, I incorporated a random walker that moves in the direction of the mouse from List 1, symbolizing your role in guiding the stars. From List 2, I used the concept of walking through RGB space to generate evolving colors as stars are plotted, and I tied the presence and intensity of the stars to the volume and playback of a soft piano sound, one of my favorite instrumental tones. The music fades away along with the stars, creating a soothing, immersive experience where the visual and auditory elements blend together seamlessly.

Highlight of the Code
One part of the code that I’m particularly proud of is how the volume of the music changes based on the number of stars on the screen. This small detail adds an extra layer of immersion:

  // Adjust the volume of the song based on the number of stars on the canvas
  let targetVol = constrain(map(stars.length, 0, 100, 0, 1), 0, 1);  // Map the number of stars to a volume level
  song.setVolume(targetVol, 0.1);  // Gradually change the volume over 0.1 seconds

  if (stars.length === 0 && song.isPlaying()) {
    song.pause();  // Pause the song if no stars are left on the canvas
  } else if (stars.length > 0 && !song.isPlaying()) {
    song.play();  // Play the song if there are stars on the canvas
  }
}

This section of the code ensures that as more stars are plotted, the volume of the piano music increases, and as they fade away, the music gradually softens until it stops. It’s a simple yet effective way to tie the visual and auditory experiences together.

Embedded Sketch

Video Representation 

Reflection and Ideas for Future Work
Creating this sketch was a rewarding experience as it allowed me to combine my love for stargazing with music in a creative way. The fading effect, both for the stars and the sound, adds a dreamy quality that I find very calming.

In the future, I’d love to experiment with adding more interactive elements, such as varying the types of sounds or letting users choose different star colors and patterns. Another idea could be to introduce a more complex musical composition that evolves as the stars increase in number or move in specific patterns. This project has opened up so many possibilities, and I’m excited to see where it can go next!

P5.js Full Code and Sketch

https://editor.p5js.org/maryamalmatrooshi/sketches/IZVrVbVB1

References

https://editor.p5js.org/masakudamatsu/sketches/uPF7TUpcf

https://editor.p5js.org/nimrah.syed/sketches/w_5GyQsyh

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#reversing_an_array_in_place

https://p5js.org/reference/#/p5.SoundFile/setVolume

 

Reading Reflection – Week 1 (Maryam AlMatrooshi)

For this week’s reflection on The Computational Beauty of Nature by Gary William Flake, I found the discussion about reductionism really interesting. The author explains that reductionism, which is breaking things down into smaller parts to understand them better, is a powerful tool. However, it has its limits, especially when we try to predict how a whole system will behave just by looking at its parts. This idea made me think about how, in software development, knowing how individual pieces of code work doesn’t always help in understanding how the entire program will run in real life. This reading made me question how effective reductionism really is, especially in complex systems where things interact in unexpected ways.

The author also talks about the importance of looking at the bigger picture, which is called holism (the opposite of reductionism). He suggests that to truly understand complex systems, we need to consider how different parts interact with each other and their surroundings. This idea made me think differently about how I approach problems, as it challenges the usual way of focusing only on individual parts. However, I wonder if the author might be a bit biased in favoring holism too much, without recognizing that reductionism can be very useful in some cases. This reading has encouraged me to think more about balancing both approaches when trying to solve complex problems.

 

 

 

 

Week 1 | Star Aviators

Star Aviators | p5.js (youtube.com)
Check the sketch here!

How to navigate the stars:

Move around the mouse in, between, and out of the canvas. Observe the stroke behavior!

Concept

I scoured the internet to find some inspiration. One particular video that interested me was this random walker by @Jakim_. Mesmerized by this walker, I messed around with this concept for quite some time.

Applying Shiffman’s tutorials, I wanted to shift beyond just a few pixels and lines forming around. What if there are circular points at the end of each stroke? What if the colors change? By refreshing the background, changing colors, and varying frame intervals, I achieved the desired result: trails of star explorers in the pitch-black space.

//Create ellipse at the end point
ellipse(pos.x + s / 2, pos.y + s / 2, diameter);

let x = frameCount % 100;

// If the mouseX > width/2,
// decrease the frame rate & change background
if (mouseX > width || mouseY > height) {
  frameRate(24);
  background(10, 10, 10, 100);
} else {
  frameRate(20);
  background(100, 100, 100, 6);
}
Reflection

There are infinite ways this small project can be expanded. What if I utilize classes to generate multiple walkers? What about synchronizing the steps to a music beat? Perhaps, I could limit such that the strokes avoid previous ones while maintaining only x or y directions. The possibilities are limitless.

Resources Used

Random Walker with Levy Flights, Daniel Shiffman.

Background fade effect, Ashibe Yoichi.

Week 1 – Fireflies by Dachi

Sketch

Code:

let fireflies = [];
const numFireflies = 50;
const avoidanceRadius = 150;  // Radius around cursor where fireflies start avoiding
let backgroundImage;
let canteenImage;
let mainTheme;

function preload() {
  // Load assets before setup
  backgroundImage = loadImage('background.png');
  canteenImage = loadImage('canteen2.png');
  soundFormats('mp3', 'ogg');
  mainTheme = loadSound('grave_of_fireflies_theme.mp3');
}

function setup() {
  createCanvas(800, 600);

  // Initialize fireflies
  for (let i = 0; i < numFireflies; i++) {
    fireflies.push(new Firefly());
  }

  noCursor();  // Hide default cursor

  // Start background music
  mainTheme.setVolume(0.5);
  mainTheme.loop();
}

function draw() {
  image(backgroundImage, 0, 0, width, height);

  drawShadow();

  // Update and display fireflies
  for (let firefly of fireflies) {
    firefly.move();
    firefly.display();
  }

  drawCanteen();
}

function drawShadow() {
  let canteenSize = 100;
  let shadowSize = canteenSize * 1.5;

  // Calculate shadow offset based on simulated light source
  let lightX = width / 2;
  let lightY = height / 2;
  let shadowOffsetX = map(mouseX - lightX, -width/2, width/2, -20, 20);
  let shadowOffsetY = map(mouseY - lightY, -height/2, height/2, -20, 20);

  push();
  translate(mouseX + shadowOffsetX, mouseY + shadowOffsetY);

  // Create and draw radial gradient for shadow
  let gradient = drawingContext.createRadialGradient(0, 0, 0, 0, 0, shadowSize/2);
  gradient.addColorStop(0, 'rgba(0, 0, 0, 0.3)');
  gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
  drawingContext.fillStyle = gradient;
  ellipse(0, 0, shadowSize, shadowSize * 0.6);

  pop();
}

function drawCanteen() {
  let canteenSize = 100;
  let tiltAmount = 10;

  // Tilt canteen based on mouse position
  let tiltX = map(mouseX, 0, width, -tiltAmount, tiltAmount);
  let tiltY = map(mouseY, 0, height, -tiltAmount, tiltAmount);

  push();
  translate(mouseX, mouseY);
  rotate(radians(tiltX));
  rotate(radians(tiltY));
  image(canteenImage, -canteenSize/2, -canteenSize/2, canteenSize, canteenSize);
  pop();
}

class Firefly {
  constructor() {
    this.reset();
  }

  reset() {
    // Initialize firefly properties
    this.x = random(width);
    this.y = random(height);
    this.brightness = random(150, 255);
    this.blinkRate = random(0.01, 0.03);
    this.speed = random(0.2, 0.5);
    this.size = random(10, 15);
    this.angle = random(TWO_PI);
    this.turnSpeed = random(0.05, 0.1);
  }

  move() {
    let d = dist(this.x, this.y, mouseX, mouseY);

    if (d < avoidanceRadius) {
      // Avoid cursor
      let avoidanceSpeed = map(d, 0, avoidanceRadius, this.speed * 5, this.speed);
      let angle = atan2(this.y - mouseY, this.x - mouseX);
      this.x += cos(angle) * avoidanceSpeed;
      this.y += sin(angle) * avoidanceSpeed;
    } else {
      // Normal movement using Perlin noise
      let noiseScale = 0.01;
      let noiseVal = noise(this.x * noiseScale, this.y * noiseScale, frameCount * noiseScale);
      this.angle += map(noiseVal, 0, 1, -this.turnSpeed, this.turnSpeed);
      this.x += cos(this.angle) * this.speed;
      this.y += sin(this.angle) * this.speed;
    }

    // Wrap around edges of canvas
    if (this.x < -this.size) this.x = width + this.size;
    if (this.x > width + this.size) this.x = -this.size;
    if (this.y < -this.size) this.y = height + this.size;
    if (this.y > height + this.size) this.y = -this.size;

    // Update brightness for blinking effect
    this.brightness += sin(frameCount * this.blinkRate) * 5;
    this.brightness = constrain(this.brightness, 150, 255);
  }

  display() {
    noStroke();
    let glowSize = this.size * 2;
    let alpha = map(this.brightness, 150, 255, 50, 150);

    // Draw firefly with layered glow effect
    fill(255, 255, 150, alpha * 0.3);
    ellipse(this.x, this.y, glowSize, glowSize);
    fill(255, 255, 150, alpha * 0.7);
    ellipse(this.x, this.y, this.size * 1.5, this.size * 1.5);
    fill(255, 255, 150, alpha);
    ellipse(this.x, this.y, this.size, this.size);
  }
}

Concept

This project is an interactive simulation inspired by the Studio Ghibli film “Grave of the Fireflies”. It aims to capture mesmerizing fireflies which is connected to the main movie theme. The simple movement creates an atmospheric environment where glowing fireflies interact with the user’s cursor, represented by the famous candy tin from the film. This concept seeks to evoke the bittersweet feelings of the movie, allowing users to subtly engage with its symbolism.

How It Works

Each firefly is represented by a glowing orb that moves automatically across the screen. The movement of these digital insects is controlled by Perlin noise. This technique results in firefly movements that appear organic and natural, where the erratic flight patterns of real fireflies are mimicked.

The visual representation of the fireflies is achieved through different layers. Each firefly consists of multiple semi-transparent circles of varying sizes which create a soft bloomy look. The brightness of each firefly pulsates over time, simulating the flashing characteristic of these insects.

As the user moves this cursor across the screen, nearby fireflies react by moving away, creating a dynamic and responsive environment. This small interaction element is quite smooth and I fine-tuned it to not appear too rapid.

Background music is the theme of the movie which enhances the experience and is quite emotional.
I used Adobe Photoshop to modify the background image to create a suitable environment for the fireflies. Additionally, the candy tin image used for the cursor was edited to include a subtle red glow, helping it integrate seamlessly with the illumination of the fireflies.

Potential Improvements

While the current implementation achieves its basic goals, there are many ways to improve. The most significant one would be, adding more interactive elements that could enhance user engagement. This might include implementing sound effects that respond to firefly movements or user interactions or introducing environmental factors like wind or obstacles that influence firefly behavior.
Lastly, providing user controls to adjust parameters such as firefly count, speed, or glow intensity could allow for a more personalized experience, enabling users to experiment with different atmospheres.

Difficulties and Challenges

One of the main challenges in this project was creating a natural-looking movement pattern for the fireflies that didn’t appear too random or too uniform. Initially, the fireflies tended to drift in one direction over time, which required careful tuning of the Perlin noise parameters to correct. Another significant challenge was implementing the avoidance behavior in a way that felt organic; early iterations had the fireflies reacting too abruptly to the cursor, which broke the illusion of natural movement.

References

1. Studio Ghibli. (1988). Grave of the Fireflies [Motion Picture]. Japan.
2. Coding Train from Youtube

(This project satisfies the assignment requirements by experimenting with motion through the implementation of Perlin noise-based movement and avoidance behavior of the fireflies. Additionally, it applies rules of motion to another medium of expression by translating the movement algorithms into visual representations of color and brightness in the fireflies’ glow effect.)