本文所有程序的運(yùn)行環(huán)境為控制臺(tái)轮听,通過字符在控制臺(tái)中輸出一些有趣的圖案笋鄙。
控制臺(tái)輸出五角星
注:本程序首先發(fā)布在 CSDN 我的博客 上吸重,這里作為引用互拾。
剛開始學(xué)習(xí)語(yǔ)言的時(shí)候,老師都很喜歡讓我們?cè)诳刂婆_(tái)上使用“*”來輸出某些圖形晤锹,比如:三角形摩幔、菱形、方塊什么的鞭铆,這主要能讓我們能更好地理解循環(huán)的語(yǔ)法和邏輯思維能力或衡。
這些圖形基本上都是直線的,所以在控制臺(tái)上可以很方便地進(jìn)行輸出车遂,不知道有沒有人想過在控制臺(tái)上輸出一條有斜率的斜線呢封断?
在 AWT 上使用 Graphics 對(duì)象來做這些事的話是相當(dāng)簡(jiǎn)單的,其中有內(nèi)置的 drawLine 方法舶担,告訴它 4 個(gè)點(diǎn)的坐標(biāo)就可以很方便地在界面上畫出一條斜線坡疼,但是在控制臺(tái)我們?nèi)绾巫龅竭@些呢?
閑著沒事的時(shí)候衣陶,寫了一個(gè)在控制臺(tái)上輸出五角星的小程序柄瑰,不過這里面有點(diǎn)小小的 bug,bug 是什么剪况、究竟在什么地方呢教沾?先賣個(gè)關(guān)子吧,我弄了好久頭都大了不想去想了译断,如果發(fā)現(xiàn)的話或者是解決了的話授翻,別忘記告訴我。
public class Test {
public static void main(String[] args) {
// 畫一個(gè)半徑為10,旋轉(zhuǎn)為0堪唐,空白為全身空格巡语,填充為的五角星
Pentagram pen = new Pentagram(10, 0, ' ', '');
// 在控制臺(tái)上輸出這個(gè)五角星
Draw.printCanvas(pen.getPentagram());
}
private static class Pentagram {
private final char FILL_CHAR; // 填充字符
private final char SPACE_CHAR; // 空檔字符
private final int R; // 五角星的外接圓半徑
private final float ROTATION; // 五角星逆時(shí)針旋轉(zhuǎn)角度
private final int X; // 用于生成畫圖數(shù)組
private final int Y; // 用于生成畫圖數(shù)組
/**
* 構(gòu)造一個(gè)Pentagram對(duì)象
* @param radius 五角星的半徑
* @param rotation 五角星的逆時(shí)針旋轉(zhuǎn)度數(shù)
* @param spaceChar 畫布上空白處填充字符
* @param fillChar 畫布上線條部分填充字符
*/
public Pentagram(int radius, float rotation, char spaceChar, char fillChar) {
this.R = radius;
this.ROTATION = rotation;
this.FILL_CHAR = fillChar;
this.SPACE_CHAR = spaceChar;
this.X = 2 * R + 1;
this.Y = 2 * R + 1;
}
public char[][] getPentagram() {
char[][] canvas = initCanvas();
Draw draw = new Draw(FILL_CHAR);
// 設(shè)五角星的最右邊的一個(gè)點(diǎn)為 A,逆時(shí)針選取點(diǎn) B~E
// 通過圓的極坐標(biāo)公式可以得出:
// 得出以下各點(diǎn)的坐標(biāo)
// A 點(diǎn)坐標(biāo)(0.951R, 0.309R)
// B 點(diǎn)坐標(biāo)(0, R)
// C 點(diǎn)坐標(biāo)(-0.951R, 0.309R)
// D 點(diǎn)坐標(biāo)(-0.588R, -0.809R)
// E 點(diǎn)坐標(biāo)(0.588R, -0.809R)
// 畫線段CA
draw.drawLine(mcos(162) * R, msin(162) * R, mcos(18) * R, msin(18) * R, canvas);
// 畫線段DA
draw.drawLine(mcos(234) * R, msin(234) * R, mcos(18) * R, msin(18) * R, canvas);
// 畫線段CE
draw.drawLine(mcos(162) * R, msin(162) * R, mcos(306) * R, msin(306) * R, canvas);
// 畫線段DB
draw.drawLine(mcos(234) * R, msin(234) * R, mcos(90) * R, msin(90) * R, canvas);
// 畫線段BE
draw.drawLine(mcos(90) * R, msin(90) * R, mcos(306) * R, msin(306) * R, canvas);
return canvas;
}
// 在方形的字符數(shù)組中指定兩點(diǎn)畫線條
// 對(duì)圖形數(shù)組進(jìn)行初始化淮菠,填充空格
private char[][] initCanvas() {
char[][] canvas = new char[Y][X];
for (int i = 0; i < Y; i++) {
for (int j = 0; j < X; j++) {
canvas[i][j] = SPACE_CHAR;
}
}
return canvas;
}
// 根據(jù)角度求正弦值男公,保留兩位小數(shù)
private double msin(float a) {
return ((int) (Math.sin(Math.toRadians(a + ROTATION)) * 100)) / 100.0;
}
// 根據(jù)角度求余弦值,保留兩位小數(shù)
private double mcos(float a) {
return ((int) (Math.cos(Math.toRadians(a + ROTATION)) * 100)) / 100.0;
}
}
private static class Draw {
private char fillChar;
public Draw(char fillChar) {
this.fillChar = fillChar;
}
/**
* 根據(jù)兩個(gè)點(diǎn)畫線在二維字符數(shù)組上畫線
* @param x1
* @param y1
* @param x2
* @param y2
* @param canvas
*/
public void drawLine(double x1, double y1, double x2, double y2, char[][] canvas) {
int radius = (canvas.length - 1) / 2;
// 從 x 方向進(jìn)行填充
if (x1 > x2) {
double t = x1;
x1 = x2;
x2 = t;
t = y1;
y1 = y2;
y2 = t;
}
// 獲得直線方程的兩個(gè)系數(shù)
double a = (y1 - y2) / (x1 - x2);
double b = y1 - a * x1;
// 根據(jù) x 方向的值求出 y 值兜材,并填充圖形
for (int i = (int) Math.round(x1); i <= (int) Math.round(x2); i++) {
// 根據(jù)直線方程 y = ax + b理澎,求 y
int y = (int) Math.round(a * i + b);
// 因?yàn)?y 和 i 算出來的結(jié)果有可能是負(fù)數(shù),
// 為了采用數(shù)組來表示坐標(biāo)曙寡,做了以下變換
// c[R][R] 即為坐標(biāo)原點(diǎn)
// c[R][0..R] 為 x 方向的負(fù)半軸
// c[R][R+1..2*R] 為 x 方向的正半軸
// c[0..R][R] 為 y 方向的正半軸
// c[R+1..2*R][R] 為 y 方向的負(fù)半軸
int yy = radius - y;
int xx = radius + I;
yy = yy < 0 ? 0 : yy;
yy = yy > 2 * radius ? 2 * radius : yy;
xx = xx < 0 ? 0 : xx;
xx = xx > 2 * radius ? 2 * radius : xx;
canvas[yy][xx] = fillChar;
}
// 從 y 方向進(jìn)行填充糠爬,便于減少間距問題產(chǎn)生的字符空檔
if (y1 > y2) {
double t = x1;
x1 = x2;
x2 = t;
t = y1;
y1 = y2;
y2 = t;
}
// 根據(jù) y 方向的值求出 x 值,并填充圖形
for (int i = (int) Math.round(y1); i <= (int) Math.round(y2); i++) {
// 根據(jù) x = (y - b) / a举庶,求 x
int y = (int) Math.round((i - b) / a);
int yy = radius - I;
int xx = radius + y;
yy = yy < 0 ? 0 : yy;
yy = yy > 2 * radius ? 2 * radius : yy;
xx = xx < 0 ? 0 : xx;
xx = xx > 2 * radius ? 2 * radius : xx;
canvas[yy][xx] = fillChar;
}
}
/**
* 將畫完圖之后的畫布輸出到控制臺(tái)上
* @param canvas
*/
public static void printCanvas(char[][] canvas) {
for (int i = 0; i < canvas.length; i++) {
for (int j = 0; j < canvas[i].length; j++) {
System.out.print(canvas[i][j]);
}
System.out.println();
}
}
}
}
下圖是一個(gè)半徑為 20执隧,旋轉(zhuǎn)度為 0 度的五角星控制臺(tái)輸出。
下圖是一個(gè)半徑為 20户侥,旋轉(zhuǎn)度為 15 度的五角星控制臺(tái)輸出镀琉。
菱形繪制及思路
先上代碼:
public class Test {
public static void main(String[] args) {
printDiamond(7, true);
System.out.println();
printDiamond(7, false);
}
/**
* 輸出菱形
* @param line 菱形的行數(shù)
* @param isSolid 是否為實(shí)心
*/
private static void printDiamond(int line, boolean isSolid) {
// 行數(shù)應(yīng)為奇數(shù),若為偶數(shù)時(shí)則向上取奇數(shù)
line |= 1;
for(int k = line / 2, i = -k; i <= k; i++) {
for(int j = -k, m = k - Math.abs(i); j <= m; j++) {
boolean b;
if(isSolid) {
b = Math.abs(j) + Math.abs(i) > k;
} else {
b = Math.abs(j) + Math.abs(i) != k;
}
System.out.print(b ? " " : "*");
}
System.out.println();
}
}
}
分析:菱形是一個(gè)上下蕊唐、左右對(duì)稱的圖形屋摔,行列可以按照下面的方式來進(jìn)行循環(huán):
j=
-3 -2 -1 0 1 2 3
i= +---+---+---+---+
-3 | | | | * |
+---+---+---+---+---+
-2 | | | * | * | * |
+---+---+---+---+---+---+
-1 | | * | * | * | * | * |
+---+---+---+---+---+---+---+
0 | * | * | * | * | * | * | * |
+---+---+---+---+---+---+---+
1 | | * | * | * | * | * |
+---+---+---+---+---+---+
2 | | | * | * | * |
+---+---+---+---+---+
3 | | | | * |
+---+---+---+---+
行數(shù)為 ,則 替梨,這個(gè)數(shù)值很有用處钓试,暫且稱為 。
和 的循環(huán)起始均為 副瀑,而 的終止循環(huán)為 弓熏, 的終止循環(huán)條件理應(yīng)為 ,注意右邊糠睡,我特意把它挖空了挽鞠,因?yàn)橛疫叺亩际强崭瘢瑸榱藘?yōu)化程序就沒有必要輸出了狈孔,這樣 的循環(huán)終止條件與 是有密切關(guān)系的信认,為 ,即:當(dāng) 時(shí)均抽,嫁赏,因此 只要從 循環(huán)到 就可以了。
再看看 *
位置上的規(guī)律到忽,注意最左邊的 *
橄教,在 時(shí)輸出的是空格,小于等于 時(shí)喘漏,輸出的是 *
护蝶。
- 當(dāng) , 坐標(biāo)上,翩迈, 是大于 的魏割,因此輸出空格
- 當(dāng) , 坐標(biāo)上帖族,, 是不大于 的,因此輸出
*
如果需要的是空心菱心吗跋,只要把判斷條件設(shè)為 時(shí)才輸出 *
,否則輸出空格彭谁。
因此肛捍,這樣我們就利用于圖形的對(duì)稱性完成了菱形的輸出。
楊輝三角形
public class Yanghui {
public static void main(String[] args) {
Yanghui yang = new Yanghui();
yang.printYanghuiTriangle(13);
}
/**
* 生成指定行數(shù)的楊輝三角形
*
* @param lines 楊輝三角形的行數(shù)
*/
public void printYanghuiTriangle(int lines) {
if(lines < 1) {
throw new IllegalArgumentException("lines must be great than 0.");
}
if(lines > 30) {
throw new IllegalArgumentException("lines is too big.");
}
int[] line = new int[lines];
int maxLen = getMaxLen(lines);
for(int i = 0; i < lines; i++) {
line[0] = line[i] = 1;
for(int j = 1, k = i / 2, pre = line[0]; j <= k; j++) {
int cur = line[j];
line[i - j] = line[j] += pre;
pre = cur;
}
printLine(line, i + 1, maxLen);
}
}
/**
* 根據(jù)指定行數(shù)的楊輝三角形洞坑,計(jì)算其中最大數(shù)字的長(zhǎng)度
* @param lines 楊輝三角形的行數(shù)
* @return 最大數(shù)字的長(zhǎng)度
*/
private int getMaxLen(int lines) {
int k = lines / 2;
long maxNum = factorial(k + 1, lines - 1) / factorial(1, lines - 1 - k);
return getLength(maxNum);
}
/**
* 階乘計(jì)算
* @param start 階乘計(jì)算的起始數(shù)字
* @param num 階乘計(jì)算的終止數(shù)字
* @return 階乘計(jì)算結(jié)果
*/
private long factorial(int start, int num) {
long result = start > 0 ? start : 1L;
while(num > start) {
result *= num--;
}
return result;
}
/**
* 根據(jù)指定數(shù)字計(jì)算數(shù)字的長(zhǎng)度
* @param num 數(shù)字
* @return 數(shù)字的長(zhǎng)度
*/
private int getLength(long num) {
int len = 0;
while(num > 0L) {
num /= 10L;
len++;
}
return len;
}
private void printLine(int[] yanghui, int line, int width) {
printSpaces((yanghui.length - line) * width);
for(int i = 0; i < line; i++) {
if(i > 0) {
printSpaces(width);
}
printSpaces(width - getLength(yanghui[i]));
System.out.print(yanghui[I]);
}
System.out.println();
if(width > 1) {
System.out.println();
}
}
private void printSpaces(int spaceCount) {
for(int i = 0; i < spaceCount; i++) {
System.out.print(" ");
}
}
}
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
正弦函數(shù)
public class Test {
public static void main(String[] args) {
TriFunc tri = new TriFunc();
// 生成一塊25×100的畫布
Canvas canvas = new Canvas(25, 120);
// 畫sin曲線盲链,周期為2
tri.drawSin(canvas, 2.0);
canvas.printCanvas();
System.out.println();
canvas.reset();
// 畫cos曲線,周期為2
tri.drawCos(canvas, 2.0);
canvas.printCanvas();
}
}
class TriFunc {
/**
* 畫sin曲線
* @param canvas 畫布
* @param period 曲線周期
*/
public void drawSin(Canvas canvas, double period) {
char[][] chars = canvas.getCanvas();
// x 軸的比率
double xRatio = (2 * period * Math.PI) / (canvas.getWidth() - 1);
// y 軸的放大倍率
int yMulti = (canvas.getHeight() - 1) / 2;
for(int i = 0; i < canvas.getWidth(); i++) {
// 將數(shù)組索引映射為橫坐標(biāo)值
double k = (i - canvas.getWidth() / 2) * xRatio;
// 將sin值映射為數(shù)組索引
int h = yMulti - (int)Math.round(Math.sin(k) * yMulti);
chars[h][i] = Canvas.FILL_CHAR;
}
}
/**
* 畫cos曲線
* @param canvas 畫布
* @param period 曲線周期
*/
public void drawCos(Canvas canvas, double period) {
char[][] chars = canvas.getCanvas();
double xRatio = (2 * period * Math.PI) / (canvas.getWidth() - 1);
int yMulti = (canvas.getHeight() - 1) / 2;
for(int i = 0; i < canvas.getWidth(); i++) {
double k = (i - canvas.getWidth() / 2) * xRatio;
int h = yMulti - (int)Math.round(Math.cos(k) * yMulti);
chars[h][i] = Canvas.FILL_CHAR;
}
}
}
class Canvas {
private int height;
private int width;
private char[][] canvas;
// 填充字符
public static char FILL_CHAR = '+';
// 空白字符
public static char BLANK_CHAR = ' ';
/**
* 構(gòu)建一塊畫布
* @param height
* @param width
*/
public Canvas(int height, int width) {
// 由于需要畫坐標(biāo)軸迟杂,所以得采用奇數(shù)
this.height = height % 2 == 0 ? height + 1 : height;
this.width = width % 2 == 0 ? width + 1 : width;
init();
}
/**
* 初始化畫布
*/
private void init() {
this.canvas = new char[height][width];
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
canvas[i][j] = BLANK_CHAR;
}
}
addAxis();
}
/**
* 添加坐標(biāo)軸
*/
private void addAxis() {
// 添加橫坐標(biāo)
int y = height / 2;
for(int x = 0; x < width; x++) {
canvas[y][x] = '-';
}
// 添加縱坐標(biāo)
int xx = width / 2;
for(int yy = 0; yy < height; yy++) {
canvas[yy][xx] = '|';
}
// 添加原點(diǎn)
canvas[y][xx] = '+';
}
/**
* 輸出畫布
*/
public void printCanvas() {
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
System.out.print(canvas[i][j]);
}
System.out.println();
}
}
/**
* 清空畫布
*/
public void reset() {
init();
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public char[][] getCanvas() {
return canvas;
}
}
#### | ####
## ## | ## ##
# # | # #
# # | # #
# # | # #
# # | # #
# # | # #
|
# # | # #
# # | # #
# # |# #
|
#------------------------#------------------------#------------------------#------------------------#
|
# #| # #
# # | # #
# # | # #
|
# # | # #
# # | # #
# # | # #
# # | # #
# # | # #
## ## | ## ##
#### | ####
### ##### ###
## ## | ## ##
# # | # #
# # | # #
# # | # #
|
# # | # #
# # | # #
# # | # #
|
# # | # #
# # | # #
--------------------------------------------------+--------------------------------------------------
# # | # #
# # | # #
|
# # | # #
# # | # #
# # | # #
|
# # | # #
# # | # #
# # | # #
## ## | ## ##
##### | #####
LED
public class Test {
public static void main(String[] args) {
LED led = new LED();
char[][] chss = led.getLED("0123456789");
LED.print(chss);
}
}
class LED {
/**
* 每個(gè) LED 的大小刽沾,可以進(jìn)行調(diào)整
*/
public final static int ROW = 7;
public final static int COL = 7;
/**
* 每個(gè) LED 的間隔
*/
private final static int SEPARATOR = 1;
private final static char FILL_CHAR = '#';
private final static char SPACE_CHAR = ' ';
/**
* 工具方法,用于輸出 LED
* @param chs
*/
public static void print(char[][] chs) {
for (int i = 0; i < chs.length; i++) {
for (int j = 0; j < chs[i].length; j++) {
System.out.print(chs[i][j]);
}
System.out.println();
}
}
/**
* 根據(jù)數(shù)字得到 LED 顯示數(shù)組
* @param num *
* @return
*/
public char[][] getLED(String num) {
char[] chs = num.toCharArray();
char[][][] chsss = new char[chs.length][][];
for (int i = 0; i < chs.length; i++) {
chsss[i] = showLed(chs[i] - '0');
}
return putManyLed(chsss);
}
/**
* 將多個(gè) LED 組成一排
* @param chsss
* @return
*/
private char[][] putManyLed(char[][][] chsss) {
if (chsss.length < 1) {
throw new IllegalArgumentException("LED is NULL!");
}
if (chsss.length == 1) {
return chsss[0];
}
char[][] chss = new char[ROW][chsss.length * (COL + SEPARATOR)
- SEPARATOR];
for (int i = 0; i < chsss.length; i++) {
int m = i * (COL + SEPARATOR);
for (int j = 0; j < chsss[i].length; j++) {
for (int k = 0; k < chsss[i][j].length; k++) {
chss[j][m + k] = chsss[i][j][k];
}
}
}
for (int i = 0; i < chss.length; i++) {
for (int j = 0; j < chss[i].length; j++) {
if (chss[i][j] != FILL_CHAR) {
chss[i][j] = SPACE_CHAR;
}
}
}
return chss;
}
/**
*
* @param num
* @return
*/
private char[][] showLed(int num) {
boolean[] b = getLed(num);
char[][] chs = new char[ROW][COL];
if (b[0])
for (int i = 0; i < COL; I++)
chs[0][i] = FILL_CHAR;
if (b[1])
for (int i = 0; i <= ROW / 2; I++)
chs[i][COL - 1] = FILL_CHAR;
if (b[2])
for (int i = ROW / 2; i < ROW; I++)
chs[i][COL - 1] = FILL_CHAR;
if (b[3])
for (int i = 0; i < COL; I++)
chs[ROW - 1][i] = FILL_CHAR;
if (b[4])
for (int i = ROW / 2; i < ROW; I++)
chs[i][0] = FILL_CHAR;
if (b[5])
for (int i = 0; i <= ROW / 2; I++)
chs[i][0] = FILL_CHAR;
if (b[6])
for (int i = 0; i < COL; I++)
chs[ROW / 2][i] = FILL_CHAR;
return chs;
}
/**
*
* 譯碼器
*
* 0
* #######
* # # 1
* 5 # 6 #
* #######
* # #
* 4 # # 2
* #######
* 3
*
* 0 表示 leds[0]排拷,若為 true 表示該 LED 顯示侧漓,否則不顯示
*
* @param num
* @return
*/
private boolean[] getLed(int num) {
boolean a = (num & 8) >>> 3 == 1;
boolean b = (num & 4) >>> 2 == 1;
boolean c = (num & 2) >>> 1 == 1;
boolean d = (num & 1) == 1;
boolean[] leds = new boolean[7];
leds[0] = a | (!a & c) |(!a & !b & !c & !d) | (!a & b & !c & d);
leds[1] = a | (!a & !b) | (!a & b & c & d) | (!a & b & !c & !d);
leds[2] = a | b | !c | d;
leds[3] = a | (!a & !b & c) | (!a & !b & !c & !d) | (!a & b & c & !d) |
(!a & b & !c & d);
leds[4] = (!a & c & !d) | (!b & !c & !d);
leds[5] = a | (!a & !b & !c & !d) | (!a & b & !d) | (!a & b & !c & d);
leds[6] = a | (!a & !b & c) | (!a & b & !c) | (!a & b & c & !d);
return leds;
}
}
####### # ####### ####### # # ####### ####### ####### ####### #######
# # # # # # # # # # # # # #
# # # # # # # # # # # # # #
# # # ####### ####### ####### ####### ####### # ####### #######
# # # # # # # # # # # # #
# # # # # # # # # # # # #
####### # ####### ####### # ####### ####### # ####### #######
下面的部分涉及數(shù)字電路中譯碼電路、卡諾圖等方面的知識(shí)监氢,有興趣的話可以去查找相關(guān)資料布蔗。
七段 LED 各段位的真值表如下:
A, B, C, D 表示數(shù)字的各二進(jìn)制位
a, b, c, d, e, f, g 表示 LED 的各段,為 1 時(shí)該段顯示忙菠,為 0 時(shí)該段不顯示
a
#######
# # b
f # g #
#######
# # c
e # #
#######
d
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| | A | B | C | D | | a | b | c | d | e | f | g |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 1 | 0 | 0 | 0 | 1 | | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 2 | 0 | 0 | 1 | 0 | | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 2 | 0 | 0 | 1 | 1 | | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 4 | 0 | 1 | 0 | 0 | | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 5 | 0 | 1 | 0 | 1 | | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 6 | 0 | 1 | 1 | 0 | | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 7 | 0 | 1 | 1 | 1 | | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 8 | 1 | 0 | 0 | 0 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
| 9 | 1 | 0 | 0 | 1 | | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
+---+---+---+---+---+ +---+---+---+---+---+---+---+
根據(jù)這個(gè)真值表可以得出這個(gè)反映了數(shù)字二進(jìn)制位與 LED 各段之間的邏輯關(guān)系:
采用卡諾圖化簡(jiǎn)后可以得到:
上面代碼中的 getLed
方法中的算法就是這樣來的何鸡。
螺旋矩陣
public class SpiralMatrix {
public final static int DOWN_FIRST = 0;
public final static int RIGHT_FIRST = 1;
public static void main(String[] args) {
final int N = 9;
final int DIRECT = RIGHT_FIRST;
int[][] spiralMatrix = new int[N][N];
int[] rc = { 0, 0 };
for(int c = 0, n = 1, t = (N << 1) - 1; c < t; ) {
int p = (c + 1) >> 1;
while(p++ < N) {
spiralMatrix[rc[0]][rc[1]] = n++;
if(p == N) {
c++;
}
rc[(c & 1) ^ DIRECT] += 1 - (c & 2);
}
}
output(spiralMatrix);
}
private static void output(int[][] matrix) {
for(int i = 0; i < matrix.length; i++) {
for(int j = 0; j < matrix[i].length; j++) {
if(j > 0) {
System.out.print(' ');
}
System.out.printf("%2d", matrix[i][j]);
}
System.out.println();
}
}
}
1 2 3 4 5 6 7 8 9
32 33 34 35 36 37 38 39 10
31 56 57 58 59 60 61 40 11
30 55 72 73 74 75 62 41 12
29 54 71 80 81 76 63 42 13
28 53 70 79 78 77 64 43 14
27 52 69 68 67 66 65 44 15
26 51 50 49 48 47 46 45 16
25 24 23 22 21 20 19 18 17
阿基米德螺線
根據(jù)阿基米德螺線參數(shù)方程畫圖:
import java.io.PrintStream;
public class ArchimedeanSpiral {
public static void main(String[] args) {
CoordinateCanvas canvas = new CoordinateCanvas(22);
for (double t = 0; t < 13; t += 0.00005) {
double r = 1.8 * t;
double radians = Math.toRadians(t * 180);
double x = r * Math.cos(radians);
double y = r * Math.sin(radians);
canvas.putPoint(x, y);
}
canvas.output(System.out, false);
}
}
class CoordinateCanvas {
private final int positiveX;
private final int negativeX;
private final int positiveY;
private final int negativeY;
private final char plotChar;
private final char[][] canvas;
public CoordinateCanvas(int quadrant) {
this(quadrant, '#');
}
public CoordinateCanvas(int quadrant, char plotChar) {
this(quadrant, quadrant, plotChar);
}
public CoordinateCanvas(int x, int y) {
this(x, y, '#');
}
public CoordinateCanvas(int x, int y, char plotChar) {
this(x, x, y, y, plotChar);
}
public CoordinateCanvas(int positiveX, int negativeX,
int positiveY, int negativeY, char plotChar) {
this.positiveX = Math.abs(positiveX);
this.negativeX = Math.abs(negativeX);
this.positiveY = Math.abs(positiveY);
this.negativeY = Math.abs(negativeY);
this.plotChar = plotChar;
this.canvas = new char[getHeigh()][getWidth()];
init();
}
public void putPoint(double x, double y) {
int ix = (int)Math.round(x);
int iy = (int)Math.round(y);
if (ix > positiveX || ix < -negativeX) {
return;
}
if (iy > positiveY || iy < -negativeY) {
return;
}
canvas[positiveY - iy][negativeX + ix] = plotChar;
}
public void output(PrintStream output, boolean line) {
for (int i = 0; i < canvas.length; i++) {
for (int j = 0; j < canvas[i].length; j++) {
output.print(canvas[i][j]);
if (line && i == negativeY) {
output.print('─');
}
if (line && j == negativeX) {
output.print('│');
}
if (line && i == negativeY && j == negativeX) {
output.print('┼');
}
}
output.println();
}
}
private int getHeigh() {
return positiveY + negativeY + 1;
}
private int getWidth() {
return positiveX + negativeX + 1;
}
private void init() {
for (int i = 0; i < canvas.length; i++) {
for (int j = 0; j < canvas[i].length; j++) {
canvas[i][j] = ' ';
}
}
}
}
#############E;叮
÷饽小#### “谩###8羰ⅲ
##J拔龋 ∷笨弧###
》玫谩#A祝 ∩掳肌######## ■#6虐遥
##7鞫ⅲ ∮优##### √父汀####M徘 ##?胀梗
『炕ā## ⊙街蕖##7坊茫 ##A阶欤 〈猿##
°颈琛#Hば #7∧ 』灯健## 〗跻唷#2疤妫
#8茉埃 」说伞### ∨滓稀#########3滦眩 ##G扑Γ 《巍##
《且荨#R蓿 ”蚧怠## ∠チ馈###2韵剩 ###g栌蹋 #H骶危 〈跬恰#
∮秃N】福 #7Φ拢 〕芳椤## 『袄ā#k使希 #VJ玻 「##
∧⒄#6勐 #I昃剑 ⊥溲痢### √攴ā#####K檗啵 #4蓿 ∏K隆# 《髦#C泵ィ
#A┛椋 ±栊荨E欤 #J迫 ×贰#### ∩诱###@峄希 ##J鹫眨 』隼帷## 〗ㄜ健C话
= ∮移选## 「鲜臁#9逋 #S匙 『渤拧## “⊙搿?粽 #9霞ⅲ ∈徘恕##
#E彝粒 ∠艹薄## ∪に铡=葡啵 ##J晨模 【∽亍## ”蚵住#L舷ぃ ∫了小# 』毓佟2苎纾
# ∏柑帷5烟梗 #L蓿 “胬## ×悼健######## √薄#J吖耍 #O嫔樱 【骰怼## 】尽O鲜ぃ
# 』铘妗E牍牵 #2男梗 【诨馈# ±凇#B褪鳎 #5┦拢 】## 〗愀 9人欤 B衾穑 ÷窨#5懵ィ
# “锥浴#B永 Kδ眨 ◇扒啤## √趺##T梦郏 #6て眩 ∏卸恕## ∏晏洹#Lぴ妫 8泼桑 ∫鹌佟#
」帷B碜颍 ?甘 『枧酢## 「碓5亚 #2ⅲ 〖⒛浴## ∨潮T詈洌 K⒏郑 ∷癫## 0槌危
「吵# 》橇琛#>倥 3ㄎ耍 “湓恪## 『磴病######@饷玻 #;啵 』橥选# ∩紫瘛U厦常 S缴荆 ∪窍搿N蚀剩
《胶## 〖づ病3浇疲 B⒎郑 ⊥鹌# ”∈=斜叮 #2蛄觯 ∵壕搿# ∽蟆#2显螅 G培停 ⌒肫蕖W序颍 ##
』睦簟A簿 K疽校 《够臁# 《#C笏牛 〖宾#J醒剩 #L逊铮 〉ぶ濉6恃ǎ L福 ∷嫌汀# ∧佤ぁ0ǎ #
「薄J莺眨 8蛴 ∪肥## √骜伞P1纾 A就 ∫酥洹### ⌒赜觥S牛 # ”恫8沤 7逄拢 〔砑健# 「懦堋#
∈固住# 【媳U旄撸 Q岫牛 》钋骸# 『痪 G谱常 3孜眨∨夭邸# ∪Ψ摹#G胤蓿 T拢 ⌒≡ā7ㄈ欤 ∶0取# “氲取W岢睿 #
∩倍CФ冢 G芯啵 ⌒喽小# ;靶ぃ ”被唷# ∽钔病:孛ィ 4仓 ≌夼唷# ⌒暇狻Q锶铮 5で妫 〕唷# ∨葛摹#
÷# 』偕<酰 #>囊欤 「省# 》握痢i艽海 #C床 ∨迸## √锶帷@停 #S脖 ⌒蓝妗# ∽嚎摹T等Γ ×庸狻##
T惆眩 ∈晗摺# 『ァ4沽龋 A矸妫 ≈拖睢# ∝财骸###N呐校 #J颐罚 ∠凡帧# ⊥鍪蟆I脱辏 <浜 ∪嗜取#
」戳ā#?勾溃 K祭停 ⊙该# ∏迸选#;喟 #D频迹 ≌鸺怠#I瘢 ∧凳簟# 《蟛恰#4ぃ °彩啤## 〈敕ァL叵耍
=募樱 ∨醮妗## 〉0堋N粞ǎ L崆埃 ÷鸹酢## ”吠#V姘幔 #M夭福 ∮露狻# ∈颗浮?悖 4∮伲
≌阜拧# 「胄住1疑埃 #2=模 【龃荨## 〈绽肌#######U谱 #9檬常 〔ǖ骸# ∫舭搿T蚩剑 」北汀##
』筒纭3馄蹋 L成疲 ×乐# ∶呤骸#s舷耍 #W榱Γ ∈∪荨## ×亲帧#P冉罚 :蜓埽
×搿## ◎嚷埂#1蹩常 #Q欤 ⊥锵贰## ∷拧#O旆辏 #W厮铮 √蛲ぁ# ◇翱 G掌蹋
Vぃ ∶础# ∥笊酢#8克Γ ∑拙弧###Rぐ睿 ∩猛#### 「郧铡#=即裕 #G粕福 ±魇臁##
〗匣稀#W嵘 #U 【钇## 〉呵怼#####5籽 #;比穑 ∥醯印## ±ч荨l舸欤
5垦兀 ∪灼纭## ∠陨颉##H硐梗 #@叮 〉咏健## ∧Э丁#V欢В
#T憾 ◎哒埂#:硖埽 #W莨耍 ∥榍选### ∈┯狻#7蠼茫 #:憾睿
〔苷獭## ∪渌选#T趺# ###########<斯啵 」旄颉## ⊙#>闫迹
#8娑 ∏鼓ⅰ### ♂狻#T榔模 #B妫 』安唷##
〈巢巍#U芭簦 #B拐 ⌒虏### 〗挪荨#:涨模
## 」』础###0π浚 ∥酢###E勺 ∽拭痢#V指蹋
∈省##5锞 〔滦濉#########V确。 ∨场##
《痉选#1螅 ##C俨#
∠爰省#### ∠濉##:荆
####; 〔喔Α#####
√;隆#######
約瑟夫問題
算法過程參考 Ronald L.Graham, Donald E.Knuth, Oren Patashnik 編寫的 Concrete Mathematics(《具體數(shù)學(xué)》)第 1.3 節(jié)披粟。
public class JosephusTest {
public static void main(String[] args) {
System.out.println(josephus2(5));
}
/**
* 計(jì)算約瑟夫問題,間隔 1 個(gè)的值冷冗,這個(gè)有數(shù)學(xué)解法守屉,即:
* 將最高位的 1 取出,將數(shù)值左移一位蒿辙,再將最高位的那
* 個(gè) 1 添至最低位即可拇泛。
* 例如 1010 的約瑟夫間隔為 1 的值為 0101(5)
* Concrete Mathematics 書中并未加 1,那是由于其第一個(gè)
* 從 0 開始的思灌,如果從 1 開始時(shí)需要加 1
*/
public static int josephus2(int count) {
int n = (count ^ leftOneBit(count)) << 1;
return (n | 1) + 1;
}
/**
* 獲得一個(gè)數(shù)最高位為 1 的值俺叭,比如 1111(15)
* 的最高位值為 1000
* 算法參考:Hacker's Delight 一書第三章
*/
public static int leftOneBit(int num) {
for (int i = 0; i < 5; i++) {
num |= (num >> (1 << i));
}
return num - (num >>> 1);
}
}