You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归调用蒙德里安生成器时参数归零导致无限循环问题

解决蒙德里安生成器的无限递归与参数异常问题

核心问题分析

你的代码存在几个致命逻辑错误,直接导致了无限运行和参数归零的问题:

  • 整数转换错误:(int) size会把nextDouble()返回的0~1小数直接截断为0,使得w * (int) size和h * (int) size全部变成0,递归传入的尺寸直接失效。
  • 循环与递归冲突:递归函数里使用while循环完全冗余,递归本身就是处理重复细分的逻辑,while会导致同一层级代码反复执行,陷入死循环。
  • 绘制参数逻辑混乱:fillRect(tx, ty, tx-w, ty-h)的宽高参数为负数,且完全不符合当前子矩形的绘制范围。
  • 冗余操作:每次调用subdivide都填充整个白色画布,会覆盖之前所有绘制;重复创建Random对象,浪费资源。

修正后的完整代码

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class Mondrian extends JPanel {
    private static final int CUTOFF = 40;
    private static final Color[] COLORS = {Color.RED, Color.BLUE, Color.YELLOW, Color.BLACK};
    private Random rng = new Random();
    private Image mondrian;

    public Mondrian(int w, int h) {
        mondrian = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) mondrian.getGraphics();
        // 仅初始化一次白色背景,避免覆盖已有绘制
        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, w, h);
        // 初始调用细分方法,传入正确的初始尺寸
        subdivide(0, 0, w, h, g2);
    }

    private void subdivide(int tx, int ty, int w, int h, Graphics2D g2) {
        // 尺寸小于阈值时,绘制边框后终止递归
        if (w <= CUTOFF && h <= CUTOFF) {
            g2.setColor(Color.BLACK);
            g2.drawRect(tx, ty, w, h);
            return;
        }

        // 60%概率分割矩形,40%概率填充颜色
        double splitChance = rng.nextDouble();
        if (splitChance < 0.6) {
            int splitPos;
            if (w > h) {
                // 横向分割,确保分割后两部分都不小于阈值
                splitPos = rng.nextInt(w - 2 * CUTOFF) + CUTOFF;
                subdivide(tx, ty, splitPos, h, g2);
                subdivide(tx + splitPos, ty, w - splitPos, h, g2);
                // 绘制分割线
                g2.setColor(Color.BLACK);
                g2.drawLine(tx + splitPos, ty, tx + splitPos, ty + h);
            } else {
                // 纵向分割,确保分割后两部分都不小于阈值
                splitPos = rng.nextInt(h - 2 * CUTOFF) + CUTOFF;
                subdivide(tx, ty, w, splitPos, g2);
                subdivide(tx, ty + splitPos, w, h - splitPos, g2);
                // 绘制分割线
                g2.setColor(Color.BLACK);
                g2.drawLine(tx, ty + splitPos, tx + w, ty + splitPos);
            }
        } else {
            // 随机选择颜色填充当前矩形
            Color color = COLORS[rng.nextInt(COLORS.length)];
            g2.setColor(color);
            g2.fillRect(tx, ty, w, h);
            // 绘制矩形边框
            g2.setColor(Color.BLACK);
            g2.drawRect(tx, ty, w, h);
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 将生成的图像绘制到面板上
        g.drawImage(mondrian, 0, 0, getWidth(), getHeight(), this);
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Mondrian Generator");
            Mondrian mondrian = new Mondrian(800, 1000);
            frame.add(mondrian);
            frame.setSize(800, 1000);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }
}

关键修改说明

  1. 修复尺寸计算逻辑:通过rng.nextInt(w - 2 * CUTOFF) + CUTOFF生成分割位置,确保分割后的子矩形尺寸不小于阈值,彻底避免尺寸归零。
  2. 递归逻辑优化:用if判断替代while循环,符合递归的终止条件设计,避免死循环。
  3. 修正绘制参数:所有fillRect和drawRect都使用当前子矩形的起始坐标与尺寸,确保绘制区域正确。
  4. 补充必要实现:添加paintComponent方法,确保生成的图像能显示在面板上;使用SwingUtilities.invokeLater保证Swing组件线程安全。
  5. 优化资源使用:复用类内的Random对象,仅初始化一次白色背景。

内容的提问来源于stack exchange,提问作者Snowbird2001

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 14:05:19