我是10年级的学生,我正在为我在学校学习Java课而开发Pacman。
但是,我正在从事的项目要求有人检查我的代码。
关于代码:我还没有启动图形。我刚刚使用二维数组存储了吃豆人的状态做了一些工作,在底部有一种随机化吃豆人运动的方法。
Beginning表示一个5 x 5的网格,其中的Pacman可以在其中移动。如果将代码复制到编译器中,您会明白我的意思。当吃豆人处于顶点时,他将做出决定,因此可以移至另一个。如果该值为负,则吃豆子可以穿过垂直距离,但是如果该值为正,则该距离是水平距离。
请给我有关您的建议我的下一步应该是如何清理代码。越具体越好。但基本上,您说的什么都可以。
public class PacmanRoughDraft {
public static void main(String[] args) {
PacmanRoughDraft pacMan = new PacmanRoughDraft();
pacMan.run();
}
//To is on the y-axis, from is on the x-axis.
int[][] graph = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
{ 0, 4, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0 */
{ 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1 */
{ 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 2 */
{ 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 3 */
{ 0, 0, 0, 4, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 4 */
{-4, 0, 0, 0, 0, 0, 4, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 5 */
{ 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 6 */
{ 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 7 */
{ 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 8 */
{ 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 9 */
{ 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 4, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 10 */
{ 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 11 */
{ 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0, 0 }, /* 12 */
{ 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0, 0, 0, 0 }, /* 13 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, 0 }, /* 14 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 4, 0, 0, 0, -4, 0, 0, 0, 0 }, /* 15 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0, 0 }, /* 16 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0, 0 }, /* 17 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0, 0,-4, 0 }, /* 18 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 0, 0, 0, 0,-4 }, /* 19 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 4, 0, 0, 0 }, /* 20 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0, 0 }, /* 21 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4, 0 }, /* 22 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0, 4 }, /* 23 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 4, 0 } /* 24 */
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
};
int[] pacManState = new int[3]; // [0] = from
// [1] = to
// [2] = steps
static final int FROM = 0;
static final int TO = 1;
static final int STEPS = 2;
public PacmanRoughDraft() {
pacManState[FROM] = 12;
pacManState[TO] = 13;
pacManState[STEPS] = 0;
}
public void displayGraph() { //this method will just print out the vertices of the graph if I don't call RenderGraph, but this method so far isn't called, because renderGraph is used instead.
for (int i=0; i<25; ++i) {
for (int j=0; j<25; ++j) {
if (graph[i][j] > 0) System.out.print("+");
else if (graph[i][j] == 0) System.out.print(" ");
System.out.print( ""+graph[i][j] );
if (j < 24) System.out.print(" ");
}
System.out.println();
}
}
public void renderGraph() {
// this is really the output image object
char[][] renderPlane = new char[17][33]; //17 tall by 33 wide
// clear image
for (int i=0; i<17; ++i) {
for (int j=0; j<33; ++j) {
renderPlane[i][j] = ' ';
}
}
// draw the bare graph
// - this should be a separate utility method
int[] rows = new int[]{ 0, 4, 8, 12, 16 };
int[] cols = new int[]{ 0, 8, 16, 24, 32 };
for (int i : rows) {
for (int j=0; j<33; ++j) renderPlane[i][j] = '-';
}
/*
0 8 16 24 32
0 ---------------------------------
4 ---------------------------------
8 ---------------------------------
12 ---------------------------------
16 ---------------------------------
*/
for (int j : cols) {
for (int i=0; i<17; ++i) renderPlane[i][j] = '|';
}
/*
0 8 16 24 32
0 |-------|-------|-------|-------|
| | | | |
| | | | |
| | | | |
4 |-------|-------|-------|-------|
| | | | |
| | | | |
| | | | |
8 |-------|-------|-------|-------|
| | | | |
| | | | |
| | | | |
12 |-------|-------|-------|-------|
| | | | |
| | | | |
| | | | |
16 |-------|-------|-------|-------|
*/
for (int i : rows) {
for (int j : cols) renderPlane[i][j] = '+';
}
/*
0 8 16 24 32
0 +-------+-------+-------+-------+
| | | | |
| | | | |
| | | | |
4 +-------+-------+-------+-------+
| | | | |
| | | | |
| | | | |
8 +-------+-------+-------+-------+
| | | | |
| | | | |
| | | | |
12 +-------+-------+-------+-------+
| | | | |
| | | | |
| | | | |
16 +-------+-------+-------+-------+
*/
// draw PacMan (and ghosts, and energy blobs)
int from = pacManState[FROM]; //12
int to = pacManState[TO]; //13
int steps = pacManState[STEPS]; //0
// translate from abstract graph position to physical render plane position
/*
0 1 2 3 4
0 8 16 24 32
0 0 0-------1-------2-------3-------4
| | | | |
| | | | |
| | | | |
1 4 5-------6-------7-------8-------9
| | | | |
| | | | |
| | | | |
2 8 10------11------12------13------14
| | | | |
| | | | |
| | | | |
3 12 15------16------17------18------19
| | | | |
| | | | |
| | | | |
4 16 20------21------22------23------24
*/
//changes the vertice's number to a position which can be recognized by the renderGraph() method.
int fromRow = (from / 5); //= 2
int fromCol = (from % 5); // = 2
int toRow = ( to / 5); // = 2
int toCol = ( to % 5); // = 3
/* Example:
from(12)-->to(13),
fromRow = 2, fromCol = 2
toRow = 2, toCol = 3
from(16)-->to(11),
fromRow = 3, fromCol = 1
toRow = 2, toCol = 1
*/
if (fromRow == toRow) {
if (fromCol < toCol) { // move right
renderPlane[4*fromRow][8*fromCol + steps] = 'Q';
}
else if (fromCol > toCol) { // move left
renderPlane[4*fromRow][8*fromCol - steps] = 'Q';
}
else { // no move
renderPlane[4*fromRow][8*fromCol] = 'Q';
}
}
else if (fromCol == toCol) {
if (fromRow < toRow) { // move down
renderPlane[4*fromRow + steps][8*fromCol] = 'Q';
}
else if (fromRow > toRow) { // move up
renderPlane[4*fromRow - steps][8*fromCol] = 'Q';
}
else { // no move
}
}
else {
System.out.println( "Illegal move." );
return;
}
// paint image on screen (this is really image.repaint() )
for (int i=0; i<17; ++i) {
for (int j=0; j<33; ++j) {
System.out.print( renderPlane[i][j] );
}
System.out.println();
}
System.out.println();
}
public void run() {
int n = 0;
while (n++ < 1000) {
int from = pacManState[FROM];
int to = pacManState[TO];
int steps = pacManState[STEPS];
System.out.println("(from,to,steps) = ("+from+","+to+","+steps+")");
System.out.println();
renderGraph();
try { Thread.sleep(100); }
catch (InterruptedException e) { }
// update PacMan state with random motion
int edgeLen = Math.abs(graph[from][to]); //gets you the length of the edge between the two vertices of where Pacman is and wants to go.
if (steps < edgeLen) {
++pacManState[STEPS]; //if Pacman hasn't gotten to the other side, his steps go up by one.
}
else if (steps == edgeLen) {
int randomizer = 0;
for (int j=0; j<25; j=j+1) {
if (!(0 == graph[to][j])) {
randomizer=randomizer+1;
}
}
int choice = (int)(randomizer * Math.random());//sets any vertex in the same row or column to the from vertex.
for (int j=0; j<25; j=j+1) {
if (!(0 == graph[to][j])) {
if (0 == (choice)) {
from = to;
to = j;
steps = 0;
}
choice=choice-1;
}
}
pacManState[FROM] = from;
pacManState[TO] = to;
pacManState[STEPS] = steps;
}
}
}
}
#1 楼
这是一个很好的代码审查机会,因为您的程序1)有效,并且2)仍有大量的改进空间。您的代码几乎每一行都可以重构,但是请不要负面考虑。每天我都会退出代码审查,并建议对我的出色代码进行更改。这就是业务的运作方式,将来我们应该总是有机会学习和编写更好的代码。这样说,在您的主要方法中,您可以使用以下方法来完成此任务:
public static void main(String[] args) {
new PacmanRoughDraft().run();
}
您可以在代码中定义图,这对于早期开发和快速调试是可以的,但是您实际上应该从文件中加载它。 Google会为您提供一些有关如何执行此操作的Stack Overflow答案,我强烈建议您这样做。这很容易,而且拥有文件IO的经验从未为时过早。
但是图中的
-4
是什么意思?如您所见,使用这些幻数是一个坏主意。int[] pacManState = new int[3]; // [0] = from
// [1] = to
// [2] = steps
static final int FROM = 0;
static final int TO = 1;
static final int STEPS = 2;
我很好奇为什么要使用数组在这里保存状态。这可以简单地是:
private int from;
private int to;
private int steps;
这样,您不必担心数组可能带来的问题。还请注意,我已将它们声明为
private
。如果没有修饰符,则它们具有default
访问权限,这意味着同一包中的任何其他类都可以修改其值。很少有个好主意。public PacmanRoughDraft() {
pacManState[FROM] = 12;
pacManState[TO] = 13;
pacManState[STEPS] = 0;
}
12
和13
是神奇的数字。您应该将其替换为在类顶部附近声明的常量,以便轻松进行修改。并根据先前的建议,可以将其重写为// near the top of the class
private static final int INITIAL_FROM = 12;
private static final int INITIAL_TO = 13;
private static final int INITIAL_STEPS = 0;
// later...
public PacmanRoughDraft() {
from = INITIAL_FROM;
to = INITIAL_TO;
steps = INITIAL_STEPS;
}
我将继续提出魔术数字,因为它们是邪恶的。或者,如果不是邪恶的,则没有必要,如以下代码所示:
public void displayGraph() {
for (int i=0; i<25; ++i) { // what is 25? the graph width?
for (int j=0; j<25; ++j) { // or is it the height?
if (graph[i][j] > 0) System.out.print("+"); // wait, now I know what -4 means... I think
else if (graph[i][j] == 0) System.out.print(" ");
System.out.print( ""+graph[i][j] );
if (j < 24) System.out.print(" ");
}
System.out.println();
}
}
可以这样重写:
public void displayGraph() {
for (int i = 0; i < graph.length; ++i) {
for (int j = 0; j < graph[i].length; ++j) {
if (graph[i][j] > 0) {
System.out.print("+");
}
else if (graph[i][j] == 0) {
System.out.print(" ");
}
System.out.print(graph[i][j]);
if (j < graph[i].length - 1) {
System.out.print(" ");
}
}
System.out.println();
}
}
这里有很多事情我要指出:
事物之间的空白。
for (int i=0; i<25; ++i) {
不需要用力地盯着眼睛。获取
length
的阵列意味着您可以更改网格的大小,而不必更改所有内容。认真地讲,代码中有25
的任何地方都应替换为grid.length
或grid[i].length
。避免(永远不要读)使用不带花括号的
if
-语句。它只会在您返回并进行更改时导致错误。例如,如果我打算只在System.out.print( ""+graph[i][j] );
时才调用graph[i][j] == 0
。说到,输出数组的传统方法是使用
Arrays.toString(graph[i][j])
而不是""+graph[i][j]
。这让我开始思考,为什么
graph
一个int
阵列吗?您不能将它做成char
数组并直接打印出来,而不进行所有这些计算吗?renderGraph()
我在这里感到困惑。什么是
renderPlane
?与graph
有何不同?话虽如此,您可以对该方法进行一些巧妙的改进。char[][] renderPlane = new char[17][33];
再次,魔术数字。用常量替换,以便可以轻松更改。从此数组的大小到
graph
数组有什么关系? int[] rows = new int[]{ 0, 4, 8, 12, 16 };
int[] cols = new int[]{ 0, 8, 16, 24, 32 };
for (int i : rows) {
for (int j=0; j<33; ++j) renderPlane[i][j] = '-';
}
我知道您在这里做什么,并且可以,但是不能扩展。如果要更改renderPlane的大小怎么办?您可以同时删除
rows
和cols
,并为ROW_SIZE
和COL_SIZE
添加常量。这样,您可以将上述代码替换为private static final int ROW_SIZE = 4;
private static final int COL_SIZE = 4;
// later...
for (int i = 0; i < renderPlane.length; i += ROW_SIZE) {
for (int j = 0; j < renderPlane[i].length; ++j) {
// Same thing about curly braces applies to for and while statements!
renderPlane[i][j] = '-';
}
}
您可以将类似的逻辑应用于该方法的其余部分。
我不会请继续使用
run
方法,因为您可以使用上面的一些注释来重构自己。总的来说,这是很好的代码。期待您发布Swing版本!评论
\ $ \ begingroup \ $
非常感谢您进行的出色而透彻的评论!我住的地方已经很晚了,但明天或我会尽快开始进行更改! :)
\ $ \ endgroup \ $
–user2279952
2014年5月2日在5:38
\ $ \ begingroup \ $
@ user2279952关于“” + graph [i] [j]-虽然这里没有必要,但总的来说,您应该首选graph [i] [j] .toString()。结果应该是相同的,但是您的意图会更清楚,甚至可能会更快,具体取决于编译器的优化方式。
\ $ \ endgroup \ $
–鲍勃
2014年5月2日在6:27
\ $ \ begingroup \ $
@Bob好点。我本来是不正确的,并且已经更新了该部分。
\ $ \ endgroup \ $
–lealand
2014年5月2日,12:26
\ $ \ begingroup \ $
欢迎使用代码审查!我们很高兴您在这里。这是一个很棒的评论。我希望你能坚持下去。如果您想打个招呼,请随意聊天。 (事实证明,通过我们的聊天室进行拖放操作会对您的声誉产生积极影响)
\ $ \ endgroup \ $
–西蒙·福斯伯格
2014年5月2日,12:41
#2 楼
这是一个有趣的项目。最后,我认为设计中有足够的问题可以重新开始。我看到的主要问题是…
绘制网格
将
renderGraph()
方法更好地命名为renderGrid()
。设计是刚性的。在
renderGraph()
中到处都有魔术数字:17、33、0、4、8、12、16、0、8、16、24、32、4、8、17、33。如果要扩展网格或扩展间距,您将不得不在许多地方进行更改。您的图形注释提供了极大的帮助。感谢您编写它们。
考虑到设计的刚性和实现效果的代码量,直接对整个结果进行硬编码会更好:
private static final String[] GRID = new String[] {
"+-------+-------+-------+-------+",
"| | | | |",
"| | | | |",
"| | | | |",
"+-------+-------+-------+-------+",
"| | | | |",
"| | | | |",
"| | | | |",
"+-------+-------+-------+-------+",
"| | | | |",
"| | | | |",
"| | | | |",
"+-------+-------+-------+-------+",
"| | | | |",
"| | | | |",
"| | | | |",
"+-------+-------+-------+-------+"
};
一次调用
System.out.print()
来打印字符是无效的。这导致每次write()
内核调用。编写要打印的字符串,然后一次全部打印。节点邻接表
我度过了一个有趣的时光,迷惑了
int[][] graph
的谜题。您已按行优先顺序从0到24编号了相交节点。 graph
矩阵指示在一对节点之间移动的步骤的数量和方向,如果两个节点不相邻,则为0。构造矩阵可能需要大量工作。如果您需要扩展网格,将再次需要大量工作。
此外,它是一个稀疏矩阵。当您使用它来选择下一个目标节点时,每次尝试最多有一个\ $ \ frac {4} {25} \ $机会选择一个有效的相邻节点(\ $ \ frac {3} {25} \ $(如果在边缘,则为\ $ \ frac {2} {25} \ $)(在拐角处)。您可以轻松地花掉十二个随机数,以摆脱困境。
其他观察结果
displayGraph()
和run()
都是长函数。您可以轻松拆分子例程,例如'Q'
的渲染和选择下一个目标。最后,您可能希望在屏幕上出现多个字符。您试图将角色的移动封装在一个
pacManState
数组中,这是一个很好的开始,但是您确实应该有一个合适的对象。制作单独的类也将有助于组织代码。建议
通过对小方块进行细化来绘制网格。
摆脱节点编号方案。
创建一个
PacmanCharacter
类来表示动画对象。通过选择四个基本方向之一来选择目的地,并检查目的地是否在边界内。
建议的实现
PacmanDraft
public class PacmanDraft {
public static final int ROWS = 4, COLS = 4;
private static final String[] SQUARE = {
"+-------",
"| ",
"| ",
"| "
};
// SQUARE is 8 chars wide vs. 4 rows high, so ASPECT_RATIO = 2
public static final int ASPECT_RATIO = 2;
public static final int SQUARE_HEIGHT = SQUARE.length,
SQUARE_WIDTH = SQUARE[0].length();
public static final int STEPS = SQUARE_HEIGHT;
private char[][] grid;
private PacmanCharacter[] characters;
public PacmanDraft() {
this.characters = new PacmanCharacter[] {
new PacmanCharacter('Q', ROWS / 2, COLS / 2)
};
}
private static char[][] makeGrid() {
// +1 so that there is a bottom edge
char[][] grid = new char[ROWS * SQUARE_HEIGHT + 1][];
for (int r = 0; r < grid.length; r++) {
// +1 so that that there is a right edge
grid[r] = new char[COLS * SQUARE_WIDTH + 1];
for (int c = 0; c < grid[0].length; c++) {
grid[r][c] = SQUARE[r % SQUARE_HEIGHT].charAt(c % SQUARE_WIDTH);
}
}
return grid;
}
private void placeCharacters() {
int[] coords = new int[2];
for (PacmanCharacter c : this.characters) {
c.getScreenCoords(coords);
this.grid[coords[0]][coords[1]] = c.getSymbol();
c.step();
}
}
public String toString() {
StringBuilder sb = new StringBuilder(this.grid.length * (this.grid[0].length + 1));
for (char[] row : this.grid) {
sb.append(row).append('\n');
}
return sb.toString();
}
public void run(int steps) throws InterruptedException {
for (int i = steps; i > 0; i--) {
this.grid = makeGrid();
this.placeCharacters();
System.out.println(this);
Thread.sleep(100);
}
}
public static void main(String[] args) throws InterruptedException {
new PacmanDraft().run(1000);
}
}
PacmanCharacter
import java.util.Random;
public class PacmanCharacter {
private final char symbol;
private int srcRow, srcCol,
dstRow, dstCol;
private int steps;
private Random random;
public PacmanCharacter(char symbol, int initRow, int initCol) {
this.symbol = symbol;
this.srcRow = this.dstRow = initRow;
this.srcCol = this.dstCol = initCol;
this.steps = PacmanDraft.STEPS;
this.random = new Random();
}
public char getSymbol() {
return this.symbol;
}
public void getScreenCoords(int[] coords) {
int row = coords[0] = PacmanDraft.SQUARE_HEIGHT * this.srcRow +
(this.dstRow - this.srcRow) * this.steps;
int col = coords[1] = PacmanDraft.SQUARE_WIDTH * this.srcCol +
PacmanDraft.ASPECT_RATIO * (this.dstCol - this.srcCol) * this.steps;
System.out.printf("(%d, %d) -> (%d, %d) step %d = [%d, %d]\n",
this.srcRow, this.srcCol, this.dstRow, this.dstCol,
this.steps,
row, col);
}
public void step() {
if (this.steps >= PacmanDraft.STEPS) {
this.nextDestination();
}
this.steps++;
}
private void nextDestination() {
this.steps = 0;
this.srcRow = this.dstRow;
this.srcCol = this.dstCol;
do {
switch (this.random.nextInt(4)) {
case 0:
this.dstRow = this.srcRow - 1;
this.dstCol = this.srcCol;
break;
case 1:
this.dstRow = this.srcRow;
this.dstCol = this.srcCol + 1;
break;
case 2:
this.dstRow = this.srcRow + 1;
this.dstCol = this.srcCol;
break;
case 3:
this.dstRow = this.srcRow;
this.dstCol = this.srcCol - 1;
break;
}
} while (this.dstRow < 0 || this.dstRow > PacmanDraft.ROWS ||
this.dstCol < 0 || this.dstCol > PacmanDraft.COLS);
}
}
评论
\ $ \ begingroup \ $
尽管有所有这些批评,但我应该指出,这是10年级的出色作品,比我那时的能力要好。
\ $ \ endgroup \ $
– 200_success
2014年5月2日21:38
评论
一件小事:当您需要记录方法/字段/类/等时。使用Javadoc注释我建议您对OO游戏设计进行一些阅读。考虑一下什么是名词,以及与这些名词相关的动词是什么。有很多例子可以学习。国际象棋是解决此类问题的一种流行选择,因此您可能需要查看一些国际象棋示例(如本示例)以获取想法。嘿,看,甚至还有街机游戏的其他示例,包括PacMan。