我一直在使用Java编写一个nonogram求解器,我的所有算法都运行正常,但我一直在努力处理可视化.
在执行算法期间,我可以访问两个“解决方案阵列”.一个是int [] []类型,并且包含值-1表示“肯定白色”,0表示“不确定”,1表示“肯定黑色”.另一个数组是float [] []类型,其中包含0到1之间的值,这里0表示肯定是白色,1表示肯定是黑色,值是.2表示单元格更可能是白色而不是白色是黑色的.
由于我最近从PHP切换到Java编程(没有正确的介绍),我不太了解正确地可视化这个数组.当然我首先尝试将第一种类型的数组打印到控制台,其中包含X,.和?,但这远非好看.然后我发现了一些关于BufferedImage的东西,我创建了以下函数(对于float [] [],int [] []类似):
public void toImage(int w, int h, float[][] solution) throws IOException {
int[] data = toImage1(w, h, solution);
BufferedImage img = toImage2(data, w, h);
toImage3(img);
}
public int[] toImage1(int w, int h, float[][] solution) throws IOException {
int[] data = new int[w * h];
int i = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int a = y / 100;
int b = x / 100;
int z = (int) (255 * Math.sqrt(1 - solution[a][b]));
if (solution[a][b] == 1 && ((((y % 100 >= 10 && y % 100 <= 15) || (y % 100 >= 85 && y % 100 <= 90)) && x % 100 >= 10 && x % 100 <= 90) || (((x % 100 >= 10 && x % 100 <= 15) || (x % 100 >= 85 && x % 100 <= 90)) && y % 100 >= 10 && y % 100 <= 90))) {
z = 100;
} else if (solution[a][b] == 0 && ((((y % 100 >= 10 && y % 100 <= 15) || (y % 100 >= 85 && y % 100 <= 90)) && x % 100 >= 10 && x % 100 <= 90) || (((x % 100 >= 10 && x % 100 <= 15) || (x % 100 >= 85 && x % 100 <= 90)) && y % 100 >= 10 && y % 100 <= 90))) {
z = 230;
}
data[i++] = z << 16 | z << 8 | z;
}
}
return data;
}
public BufferedImage toImage2(int[] data, int w, int h) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
img.setRGB(0, 0, w, h, data, 0, w);
return img;
}
public void toImage3(BufferedImage img) throws IOException {
File f = new File("Nonogram.png");
ImageIO.write(img, "PNG", f);
}
这里,w和h应该是每列中的细胞数量.行乘以100(我希望每个单元格由100×100像素的块表示).
然后我还想要一个确定的单元格中的额外灰色框,这就是if和else if的用途.
但是,我遇到两个问题:
>这个功能超级慢.在分析执行后,我看到90%的执行时间都转到了这个函数.按照评论中的建议将我的功能分解为两位后,我得到以下配置文件:
>而不是写入.png文件,我想要一个JFrame来显示我的图像,但(因为我错过了我对Java的正确介绍),JFrame似乎不是我最好的朋友,我似乎无法找出如何使用它们.
是否有可能一次填充整个100×100像素的细胞?有没有办法不必每次都创建整个BufferedImage,而只是修改另一种方法中已更改的位?我应该使用除BufferedImage之外的其他东西吗?我的代码需要哪些元素,有人可以编写示例方法或所需的代码片段吗?
解决方法:
好吧,所以看起来写入文件实际上并不是你最大的问题,看起来你最大的问题就是你要单独转储像素.以下是我可能会做的一些事情:
>制作更小的图像. 100×100很多.为什么不是20×20?您始终可以使用图像编辑器进行放大.
>完全跳过int []步骤,直接写入BufferedImage.
>像往常一样使用bufferedImage.setRGB(startX,startY,w,h,rgbArray,offset,scansize),但仅限于您正在批量绘制的图像部分.
>根据a和b的值完成所有操作(与w和h相反,包括尤其是循环,请参见第4点.
>完全填充框,然后通过分别覆盖这些线来添加内部矩形.如果检查会影响你的表现,那么这些都很复杂它是无分支的(没有语句),它运行得更快.
>将for循环中的代码放入一个单独的方法中,使其更清晰.称之为drawSingleBox.
请记住,更多具有良好名称的方法可以更容易地跟踪正在发生的事情. writeImageToFile优于toImage3. convertArrayToImage比toImage2更受欢迎.
另外,您询问了如何将图像作为JFrame的背景;一旦有了完全绘制的BufferedImage对象,就可以使用JFrame background image中的信息来完成它的这一部分.