Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/main/java/com/thealgorithms/others/Mandelbrot.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ public static BufferedImage getImage(int imageWidth, int imageHeight, double fig
// loop through the image-coordinates
for (int imageX = 0; imageX < imageWidth; imageX++) {
for (int imageY = 0; imageY < imageHeight; imageY++) {
// determine the figure-coordinates based on the image-coordinates
double figureX = figureCenterX + ((double) imageX / imageWidth - 0.5) * figureWidth;
double figureY = figureCenterY + ((double) imageY / imageHeight - 0.5) * figureHeight;
double figureX = pixelToFigureCoordinate(imageX, imageWidth, figureCenterX, figureWidth);
double figureY = pixelToFigureCoordinate(imageY, imageHeight, figureCenterY, figureHeight);

double distance = getDistance(figureX, figureY, maxStep);

Expand All @@ -105,6 +104,19 @@ public static BufferedImage getImage(int imageWidth, int imageHeight, double fig
return image;
}

/**
* Maps a pixel index along one image axis to its corresponding coordinate in figure space.
*
* @param pixelIndex Zero-based pixel index along the axis.
* @param imageSpan Total number of pixels along the axis.
* @param figureCenter Figure-space coordinate at the center of the axis.
* @param figureSpan Total width (or height) of the figure along the axis.
* @return The figure-space coordinate corresponding to {@code pixelIndex}.
*/
private static double pixelToFigureCoordinate(int pixelIndex, int imageSpan, double figureCenter, double figureSpan) {
return figureCenter + ((double) pixelIndex / imageSpan - 0.5) * figureSpan;
}

/**
* Black and white color-coding that ignores the relative distance. The
* Mandelbrot set is black, everything else is white.
Expand Down
132 changes: 132 additions & 0 deletions src/test/java/com/thealgorithms/others/MandelbrotTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.thealgorithms.others;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.awt.Color;
import java.awt.image.BufferedImage;
import org.junit.jupiter.api.Test;

/**
* Regression tests for {@link Mandelbrot#getImage(int, int, double, double, double, int, boolean)}.
*
* <p>Source anchors ({@code Mandelbrot.java}, {@code main} lines 32-47):
* <ul>
* <li>{@code blackAndWhiteImage = getImage(800, 600, -0.6, 0, 3.2, 50, false)}</li>
* <li>{@code blackAndWhiteImage.getRGB(0, 0) == new Color(255, 255, 255).getRGB()} (line 35)</li>
* <li>{@code blackAndWhiteImage.getRGB(400, 300) == new Color(0, 0, 0).getRGB()} (line 38)</li>
* <li>{@code coloredImage = getImage(800, 600, -0.6, 0, 3.2, 50, true)}</li>
* <li>{@code coloredImage.getRGB(0, 0) == new Color(255, 0, 0).getRGB()} (line 44)</li>
* <li>{@code coloredImage.getRGB(400, 300) == new Color(0, 0, 0).getRGB()} (line 47)</li>
* </ul>
*/
public class MandelbrotTest {

private static void logCase(String id, String input, Object expected, Object actual) {
System.out.println("[R45-T016] " + id + " | input=" + input
+ " | expected=" + expected + " | actual=" + actual);
}

/**
* Executable source anchors from {@code Mandelbrot.main} (lines 32-47) plus neighboring pixel
* {@code (1, 0)} (figure coordinates {@code (-2.196, -1.2)}, diverging at step 0).
*/
@Test
public void sourceAnchorsAndNeighboringPixelMatchExpectedRgb() {
BufferedImage bw = Mandelbrot.getImage(800, 600, -0.6, 0, 3.2, 50, false);
assertEquals(800, bw.getWidth());
assertEquals(600, bw.getHeight());
assertEquals(BufferedImage.TYPE_INT_RGB, bw.getType());

int white = new Color(255, 255, 255).getRGB();
int black = new Color(0, 0, 0).getRGB();
int red = new Color(255, 0, 0).getRGB();

int bw00 = bw.getRGB(0, 0);
logCase("anchor-bw-0-0", "800x600 bw (0,0)", white, bw00);
assertEquals(white, bw00);

int bw400300 = bw.getRGB(400, 300);
logCase("anchor-bw-400-300", "800x600 bw (400,300)", black, bw400300);
assertEquals(black, bw400300);

int bw10 = bw.getRGB(1, 0);
logCase("neighbor-bw-1-0", "800x600 bw (1,0)", white, bw10);
assertEquals(white, bw10);

BufferedImage colored = Mandelbrot.getImage(800, 600, -0.6, 0, 3.2, 50, true);
int col00 = colored.getRGB(0, 0);
logCase("anchor-colored-0-0", "800x600 colored (0,0)", red, col00);
assertEquals(red, col00);

int col400300 = colored.getRGB(400, 300);
logCase("anchor-colored-400-300", "800x600 colored (400,300)", black, col400300);
assertEquals(black, col400300);

int col10 = colored.getRGB(1, 0);
logCase("neighbor-colored-1-0", "800x600 colored (1,0)", red, col10);
assertEquals(red, col10);
}

/**
* Independently hand-calculated {@code 2x2} image centered at {@code (0, 0)} with
* {@code figureWidth = 2.0, maxStep = 5}:
* <ul>
* <li>{@code (0, 0)} -> {@code (-1.0, -1.0)} breaks at step 1 -> {@code distance = 0.25} ->
* color {@code (127, 255, 0)}</li>
* <li>{@code (0, 1)} -> {@code (-1.0, 0.0)} period-2 cycle -> {@code distance = 1.0} ->
* black {@code (0, 0, 0)}</li>
* <li>{@code (1, 1)} -> {@code (0.0, 0.0)} fixed point -> {@code distance = 1.0} ->
* black {@code (0, 0, 0)}</li>
* </ul>
*/
@Test
public void independentlyCalculatedSmallGridMatchesExactPixelValues() {
BufferedImage bw = Mandelbrot.getImage(2, 2, 0.0, 0.0, 2.0, 5, false);
BufferedImage colored = Mandelbrot.getImage(2, 2, 0.0, 0.0, 2.0, 5, true);

int white = new Color(255, 255, 255).getRGB();
int black = new Color(0, 0, 0).getRGB();
int expectedColor00 = new Color(127, 255, 0).getRGB();

logCase("grid-2x2-bw-0-0", "2x2 bw (0,0)", white, bw.getRGB(0, 0));
assertEquals(white, bw.getRGB(0, 0));

logCase("grid-2x2-colored-0-0", "2x2 colored (0,0)", expectedColor00, colored.getRGB(0, 0));
assertEquals(expectedColor00, colored.getRGB(0, 0));

logCase("grid-2x2-colored-0-1", "2x2 colored (0,1)", black, colored.getRGB(0, 1));
assertEquals(black, colored.getRGB(0, 1));

logCase("grid-2x2-colored-1-1", "2x2 colored (1,1)", black, colored.getRGB(1, 1));
assertEquals(black, colored.getRGB(1, 1));
}

/**
* Parameter validation contract (lines 76-86): non-positive dimensions or {@code maxStep}
* throw {@link IllegalArgumentException} with specific messages.
*/
@Test
public void invalidArgumentsThrowIllegalArgumentException() {
IllegalArgumentException badWidth = assertThrows(
IllegalArgumentException.class,
() -> Mandelbrot.getImage(0, 10, 0, 0, 2.0, 10, false));
logCase("invalid-width", "imageWidth=0",
"imageWidth should be greater than zero", badWidth.getMessage());
assertEquals("imageWidth should be greater than zero", badWidth.getMessage());

IllegalArgumentException badHeight = assertThrows(
IllegalArgumentException.class,
() -> Mandelbrot.getImage(10, 0, 0, 0, 2.0, 10, false));
logCase("invalid-height", "imageHeight=0",
"imageHeight should be greater than zero", badHeight.getMessage());
assertEquals("imageHeight should be greater than zero", badHeight.getMessage());

IllegalArgumentException badStep = assertThrows(
IllegalArgumentException.class,
() -> Mandelbrot.getImage(10, 10, 0, 0, 2.0, 0, false));
logCase("invalid-maxStep", "maxStep=0",
"maxStep should be greater than zero", badStep.getMessage());
assertEquals("maxStep should be greater than zero", badStep.getMessage());
}
}
70 changes: 70 additions & 0 deletions work/R45-T016/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Runner for task R45-T016: focused refactoring checks for Mandelbrot.

Runs the focused JUnit test through Maven, requires a nonzero test count,
saves inputs, expected versus actual results, and tool versions into work/R45-T016/,
and exits non-zero on any failure.
"""
import glob
import subprocess
import sys
import xml.etree.ElementTree as ET
from pathlib import Path

HERE = Path(__file__).resolve().parent
REPO = HERE.parent.parent
TEST_CLASS = "MandelbrotTest"
CMD = ["mvn", "-B", "test", f"-Dtest={TEST_CLASS}", "-Dsurefire.failIfNoSpecifiedTests=false"]


def tool_version(cmd):
try:
out = subprocess.run(cmd, capture_output=True, text=True, cwd=REPO)
return "\n".join(l for l in (out.stdout + out.stderr).splitlines()
if not l.startswith("Picked up")).strip()
except FileNotFoundError:
return f"{cmd[0]}: not found"


def main():
(HERE / "tool_versions.txt").write_text(
"java:\n" + tool_version(["java", "-version"]) + "\n\nmvn:\n"
+ tool_version(["mvn", "-v"]) + "\n\npython:\n" + sys.version + "\n")

print("Running:", " ".join(CMD))
proc = subprocess.run(CMD, capture_output=True, text=True, cwd=REPO)
combined_output = proc.stdout + proc.stderr
(HERE / "mvn_output.txt").write_text(combined_output)

records = [line.strip() for line in combined_output.splitlines()
if line.strip().startswith("[R45-T016]")]
(HERE / "comparisons.txt").write_text(
("\n".join(records) + "\n") if records else "No check records captured.\n")

reports = glob.glob(str(REPO / "target/surefire-reports" / f"TEST-*{TEST_CLASS}.xml"))
if not reports:
(HERE / "result.txt").write_text(
f"command: {' '.join(CMD)}\nFAIL: no surefire report found\n")
print("FAIL: no surefire report found")
return 1

suite = ET.parse(reports[0]).getroot()
tests = int(suite.get("tests", 0))
failures = int(suite.get("failures", 0)) + int(suite.get("errors", 0))
skipped = int(suite.get("skipped", 0))
passed = proc.returncode == 0 and failures == 0 and tests > 0 and len(records) > 0
status = "PASS" if passed else "FAIL"
summary = (
f"command: {' '.join(CMD)}\n"
f"tests={tests} failures/errors={failures} skipped={skipped} "
f"records={len(records)} mvn_exit={proc.returncode}\n"
f"status={status}\n"
)
(HERE / "result.txt").write_text(summary)
print(summary)

return 0 if passed else 1


if __name__ == "__main__":
sys.exit(main())
13 changes: 13 additions & 0 deletions work/R45-T016/comparisons.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[R45-T016] grid-2x2-bw-0-0 | input=2x2 bw (0,0) | expected=-1 | actual=-1
[R45-T016] grid-2x2-colored-0-0 | input=2x2 colored (0,0) | expected=-8388864 | actual=-8388864
[R45-T016] grid-2x2-colored-0-1 | input=2x2 colored (0,1) | expected=-16777216 | actual=-16777216
[R45-T016] grid-2x2-colored-1-1 | input=2x2 colored (1,1) | expected=-16777216 | actual=-16777216
[R45-T016] invalid-width | input=imageWidth=0 | expected=imageWidth should be greater than zero | actual=imageWidth should be greater than zero
[R45-T016] invalid-height | input=imageHeight=0 | expected=imageHeight should be greater than zero | actual=imageHeight should be greater than zero
[R45-T016] invalid-maxStep | input=maxStep=0 | expected=maxStep should be greater than zero | actual=maxStep should be greater than zero
[R45-T016] anchor-bw-0-0 | input=800x600 bw (0,0) | expected=-1 | actual=-1
[R45-T016] anchor-bw-400-300 | input=800x600 bw (400,300) | expected=-16777216 | actual=-16777216
[R45-T016] neighbor-bw-1-0 | input=800x600 bw (1,0) | expected=-1 | actual=-1
[R45-T016] anchor-colored-0-0 | input=800x600 colored (0,0) | expected=-65536 | actual=-65536
[R45-T016] anchor-colored-400-300 | input=800x600 colored (400,300) | expected=-16777216 | actual=-16777216
[R45-T016] neighbor-colored-1-0 | input=800x600 colored (1,0) | expected=-65536 | actual=-65536
62 changes: 62 additions & 0 deletions work/R45-T016/mvn_output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[INFO] Scanning for projects...
[INFO] Loaded 24447 auto-discovered prefixes for remote repository central (prefixes-central.txt)
[INFO]
[INFO] -----------------------< com.thealgorithms:Java >-----------------------
[INFO] Building Java 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- jacoco:0.8.16:prepare-agent (default) @ Java ---
[INFO] Loaded 64 auto-discovered prefixes for remote repository apache.snapshots (prefixes-apache.snapshots.txt)
[INFO] argLine set to -javaagent:/Users/shyamlibakale/.m2/repository/org/jacoco/org.jacoco.agent/0.8.16/org.jacoco.agent-0.8.16-runtime.jar=destfile=/Users/shyamlibakale/TheAlgorithms-Java/TheAlgorithms-Java/target/jacoco.exec
[INFO]
[INFO] --- resources:3.5.0:resources (default-resources) @ Java ---
[INFO] skip non existing resourceDirectory /Users/shyamlibakale/TheAlgorithms-Java/TheAlgorithms-Java/src/main/resources
[INFO]
[INFO] --- compiler:3.16.0:compile (default-compile) @ Java ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 848 source files with javac [debug release 21] to target/classes
[INFO]
[INFO] --- resources:3.5.0:testResources (default-testResources) @ Java ---
[INFO] skip non existing resourceDirectory /Users/shyamlibakale/TheAlgorithms-Java/TheAlgorithms-Java/src/test/resources
[INFO]
[INFO] --- compiler:3.16.0:testCompile (default-testCompile) @ Java ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 797 source files with javac [debug release 21] to target/test-classes
[INFO]
[INFO] --- surefire:3.6.0:test (default-test) @ Java ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.thealgorithms.others.MandelbrotTest
[R45-T016] grid-2x2-bw-0-0 | input=2x2 bw (0,0) | expected=-1 | actual=-1
[R45-T016] grid-2x2-colored-0-0 | input=2x2 colored (0,0) | expected=-8388864 | actual=-8388864
[R45-T016] grid-2x2-colored-0-1 | input=2x2 colored (0,1) | expected=-16777216 | actual=-16777216
[R45-T016] grid-2x2-colored-1-1 | input=2x2 colored (1,1) | expected=-16777216 | actual=-16777216
[R45-T016] invalid-width | input=imageWidth=0 | expected=imageWidth should be greater than zero | actual=imageWidth should be greater than zero
[R45-T016] invalid-height | input=imageHeight=0 | expected=imageHeight should be greater than zero | actual=imageHeight should be greater than zero
[R45-T016] invalid-maxStep | input=maxStep=0 | expected=maxStep should be greater than zero | actual=maxStep should be greater than zero
[R45-T016] anchor-bw-0-0 | input=800x600 bw (0,0) | expected=-1 | actual=-1
[R45-T016] anchor-bw-400-300 | input=800x600 bw (400,300) | expected=-16777216 | actual=-16777216
[R45-T016] neighbor-bw-1-0 | input=800x600 bw (1,0) | expected=-1 | actual=-1
[R45-T016] anchor-colored-0-0 | input=800x600 colored (0,0) | expected=-65536 | actual=-65536
[R45-T016] anchor-colored-400-300 | input=800x600 colored (400,300) | expected=-16777216 | actual=-16777216
[R45-T016] neighbor-colored-1-0 | input=800x600 colored (1,0) | expected=-65536 | actual=-65536
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.094 s -- in com.thealgorithms.others.MandelbrotTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jacoco:0.8.16:report (generate-code-coverage-report) @ Java ---
[INFO] Loading execution data file /Users/shyamlibakale/TheAlgorithms-Java/TheAlgorithms-Java/target/jacoco.exec
[INFO] Analyzed bundle 'Java' with 1073 classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.703 s
[INFO] Finished at: 2026-11-11T17:41:01+05:30
[INFO] ------------------------------------------------------------------------
3 changes: 3 additions & 0 deletions work/R45-T016/result.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
command: mvn -B test -Dtest=MandelbrotTest -Dsurefire.failIfNoSpecifiedTests=false
tests=3 failures/errors=0 skipped=0 records=13 mvn_exit=0
status=PASS
14 changes: 14 additions & 0 deletions work/R45-T016/tool_versions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
java:
openjdk version "21.0.13" 2026-10-20 LTS
OpenJDK Runtime Environment Temurin-21.0.13+9 (build 21.0.13+9-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.13+9 (build 21.0.13+9-LTS, mixed mode, sharing)

mvn:
Apache Maven 3.10.0 (c43a36b8d67be7e0805a411bc0898af1a51f5472)
Maven home: /opt/homebrew/Cellar/maven/3.10.0/libexec
Java version: 27.0.1.0.3, vendor: Homebrew, runtime: /opt/homebrew/Cellar/openjdk/27.0.1.0.3/libexec/openjdk.jdk/Contents/Home
Default locale: en_IN, platform encoding: UTF-8, time zone: Asia/Kolkata
OS name: "mac os x", version: "27.0", arch: "aarch64", family: "mac"

python:
3.14.7 (v3.14.7:823f0323ee6, Aug 5 2026, 07:07:01) [Clang 21.0.0 (clang-2100.1.1.101)]