棱形打印
问题
*
***
*****
*******
*********
*******
*****
***
*
* * *
*** *** ***
***** ***** *****
******* ******* *******
***************************
******* ******* *******
***** ***** *****
*** *** ***
* * *
* * * * *
*** *** *** *** ***
***** ***** ***** ***** *****
******* ******* ******* ******* *******
*********************************************
******* ******* ******* ******* *******
***** ***** ***** ***** *****
*** *** *** *** ***
* * * * *
* * *
*** *** ***
***** ***** *****
******* ******* *******
***************************
******* ******* *******
***** ***** *****
*** *** ***
* * *
*
***
*****
*******
*********
*******
*****
***
*
分析
上图的棱形打印我们可以看成是一个大棱形的每个点有变成了一个个的小棱形,我们称整体的棱形为外套棱形,外套棱形的点变成的小棱形称为内嵌棱形。
之前我们打印过单个的棱形,类似于下面的:
*
***
*****
******* -棱1
*****
***
*
像-棱1
这种的棱形打印的方法有很多,
普通棱形打法1
像初学者可能会这样做:
先打印这一行的空格
再打印这一行的
*
,然后一行行的打,这是最没有技术含量的的打法。
数理思维好一点的可能会采用下面的两种打印方法
普通棱形打法2
如上图 ,我们要打印一个半径为2的棱形,绿色的圆就是我们要在程序中用
*
代替的,我们发现所有的圆点都在四条直线上或者在四条直线的内部所以我们得到四个判断条件,只要满足这四个条件,那么这个点在我们的程序中就是
*
而不是空格
n <= x + y
x + y <= 3n
x - y >= -n
x - y <= n
所以我们写出一部分代码,用来判断这个点是否是*
public static boolean isTrue(int i ,int j ,int n){
int temp = Math.abs(i-j) ;
// if (( (temp) <= n ) && ( (i+j)<=(3*n) && ( n <= (i+j) )) ){ //实心棱形
if (( (temp) == n ) || ( (i+j)==(3*n) || ( n == (i+j) )) ){ //空性棱形
return true;
}else {
return false;
}
}
普通棱形打法3(围点打棱)
* * *
* ==> *** *** ***
* ==> ***** *****
*** ==> *******
* *****
***
*
棱心 1层 2层 3层
在 打法2 的基础上可以完成想上面的棱形打印顺序,不过打印起来需要3层for循环(不推荐),但是需要打印
*
* *
* *
* * *
* * * *
* * * *
* * * * *
* * * * * *
* * * * *
* * * *
* * * *
* * *
* *
* *
*
这种间隔层的棱形,就需要一层层的打。
如上图(0,0)为棱心,3为半径的一个棱形,我们会发现所有棱形内的点都满足 |x| + |y| <= 3
上面是理想状态下,下面是我们实际的控制台输出坐标模式,有时候我们的棱心坐标任意呢,依然满足上面的条件
所以我们可以写出如下代码:
//判断这个点是否是我们棱形上的点
public static boolean isOne(int i ,int j ,int x ,int y , int len){
if ((Math.abs(x-i) + Math.abs(y-j) <= len)){
return true;
}
return false;
}
本题分析
看我们本题需要打印的图形,从整体上来看,是一个大棱形;再细看大棱形都是由一个个的小棱形组成的,而且看起来小棱形就是大棱形的点,在这里,我们称大棱形叫外套棱形,小棱形叫内嵌棱形。
我们获取到外套棱形的每个点,然后对每个点实行围点打棱
这样就能打印出本题的图形了。
但是我们要知道小棱形的半径和大棱形的半径,当然一个小棱形对大棱形在我们这里只能当做一个单位看
我们假设小棱形半径为:min
大棱形半径为:max
步骤
###### 1. 确认打印这个棱形需要多大的纸(数组)
需要用到多大的纸取决于我们的最大值,就是棱形的对角线长度:
小棱形最多需要 minLen
=(2*min+1)
大棱形最多需要 (2*max+1)
所以我们的纸最小为 (2*min+1)(2*max+1)
= maxLen
int[][] array = new int[maxLen][maxLen];
2. 在数组中标记棱形的点
我们需要先找到所有小棱形的棱形,小棱形的棱形棱心与大棱形有关,如下:
如上图:红色的棱形为外套棱形的初始状态,经过变换后,外套棱形的所有点都变为小棱形(蓝色棱形),所有的蓝色棱形组合一起就变成了我们需要的大棱形
所以我们需要先建一个简单的外套棱形,然后找到简单的外套棱形与复杂棱形之间的关系
我们发现,所有外套棱形的小棱形的棱心与简单外套棱形上的点存在以下关系
小棱形半径
minR
= min小棱形直径
minD
= 2*minR
+1
变换关系
( x , y ) ===>>> (x*minD
+ minR
, y*minD
+minR
)
得到变换关系之后 ,我们可以通过外套棱形的半径max
先构建一个简单棱形,在通过变换关系将我们的纸上的所有内嵌棱形棱心标记,最后通过围点打棱
打印出问题所需要的棱形
代码
/**
* @Author chen_jiapin
* @Date 2023/2/13 8:45
* @Version 1.0
* 打印棱形 column line
*/
public class PrintPrismatic {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入内嵌棱形的半径(int):");
int min = sc.nextInt();
System.out.println("请输入外套棱形的半径(int):");
int max = sc.nextInt();
int[][] array = initArr(min,max);
int[][] maxArray = fun_02(max);
int minD = 2*min+1;
int minR = min;
for (int i = 0; i < maxArray.length; i++) {
for (int j = 0; j < maxArray[i].length; j++) {
if (maxArray[i][j]==1){
int maxX = i*minD+minR;
int maxY = j*minD+minR;
array[maxX][maxY]=1;
fun_03(array,maxX,maxY,min);
}
}
}
print(array);
}
//初始化纸
public static int[][] initArr(int min,int max){
int minLen = min*2+1;
int maxLen = (max*2+1)*minLen;
int[][] array = new int[maxLen][maxLen];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
array[i][j] = 0 ;
}
}
return array;
}
//打印简单棱形方法
public static int[][] fun_02(int n){
int m = 2*n+1;
int[][] array = new int[m][m];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
array[i][j]=0;
}
}
toWork(array,n);
return array;
}
//标记纸上的点
public static void fun_03(int[][] array,int x,int y,int len){
array[x][y] = 1 ;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (isOne(i,j,x,y,len)){
array[i][j]=1;
}
}
}
}
//标记简单棱形上的点
public static void toWork(int[][] array ,int n){
array[n][n]=1;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (isOne(i,j,n,n,n)){
array[i][j]=1;
}
}
}
}
//判断点是否在棱形内
public static boolean isOne(int i ,int j ,int x ,int y , int len){
if ((Math.abs(x-i) + Math.abs(y-j) <= len)){
return true;
}
return false;
}
//更具数组打印棱形
public static void print(int[][] array){
int line = 0;
for (int i = 0; i < array.length; i++) {
line++;
int column = 0;
for (int j = 0; j < array[i].length; j++) {
column++;
if (array[i][j]==1){
System.out.print("*");
}
else System.out.print(" ");
}
System.out.println("\t" + column + " - " + line);
}
}
}
控制台结果
请输入内嵌棱形的半径(int):
3
请输入外套棱形的半径(int):
4
* 63 - 1
*** 63 - 2
***** 63 - 3
******* 63 - 4
***** 63 - 5
*** 63 - 6
* 63 - 7
* * * 63 - 8
*** *** *** 63 - 9
***** ***** ***** 63 - 10
********************* 63 - 11
***** ***** ***** 63 - 12
*** *** *** 63 - 13
* * * 63 - 14
* * * * * 63 - 15
*** *** *** *** *** 63 - 16
***** ***** ***** ***** ***** 63 - 17
*********************************** 63 - 18
***** ***** ***** ***** ***** 63 - 19
*** *** *** *** *** 63 - 20
* * * * * 63 - 21
* * * * * * * 63 - 22
*** *** *** *** *** *** *** 63 - 23
***** ***** ***** ***** ***** ***** ***** 63 - 24
************************************************* 63 - 25
***** ***** ***** ***** ***** ***** ***** 63 - 26
*** *** *** *** *** *** *** 63 - 27
* * * * * * * 63 - 28
* * * * * * * * * 63 - 29
*** *** *** *** *** *** *** *** *** 63 - 30
***** ***** ***** ***** ***** ***** ***** ***** ***** 63 - 31
*************************************************************** 63 - 32
***** ***** ***** ***** ***** ***** ***** ***** ***** 63 - 33
*** *** *** *** *** *** *** *** *** 63 - 34
* * * * * * * * * 63 - 35
* * * * * * * 63 - 36
*** *** *** *** *** *** *** 63 - 37
***** ***** ***** ***** ***** ***** ***** 63 - 38
************************************************* 63 - 39
***** ***** ***** ***** ***** ***** ***** 63 - 40
*** *** *** *** *** *** *** 63 - 41
* * * * * * * 63 - 42
* * * * * 63 - 43
*** *** *** *** *** 63 - 44
***** ***** ***** ***** ***** 63 - 45
*********************************** 63 - 46
***** ***** ***** ***** ***** 63 - 47
*** *** *** *** *** 63 - 48
* * * * * 63 - 49
* * * 63 - 50
*** *** *** 63 - 51
***** ***** ***** 63 - 52
********************* 63 - 53
***** ***** ***** 63 - 54
*** *** *** 63 - 55
* * * 63 - 56
* 63 - 57
*** 63 - 58
***** 63 - 59
******* 63 - 60
***** 63 - 61
*** 63 - 62
* 63 - 63
Process finished with exit code 0