从零開始开发Android版2048 (三)逻辑推断
近期工作比較忙,所以更新的慢了一点,今天的主要内容是关于Android版2048的逻辑推断,经过本篇的解说,基本上完毕了这个游戏的主体部分。
首先还是看一下,我在实现2048时用到的一些存储的数据结构。
我在实现时,为了省事存储游戏过程中的变量主要用到的是List。
比方说:List<Integer> spaceList = new ArrayList<Integer>();这个spaceList主要用于保存。全部空白格的位置,也就是空白格在GridLayout中的位置(从0到15)
对于数字格,以及格子相应的数据。我写了一个类例如以下:
package com.example.t2048; import java.util.ArrayList;
import java.util.List; import android.util.Log; /**
* 用于保存数字格,已经数字格相应的数字
* @author Mr.Wang
*
*/
public class NumberList { //这个list用于保存全部不为空的格子的坐标(在GridLayout中的位置从0到15)
private List<Integer> stuffList = new ArrayList<Integer>();
//这个list用于保存全部不为空的格子相应的数字(以2为底数的指数)
private List<Integer> numberList = new ArrayList<Integer>(); /**
* 新增加的数字格
* @param index 数字格相应的位置
* @param number 相应数字的指数(以2为底数)
*/
public void add(int index, int number){
stuffList.add(index);
numberList.add(number);
} /**
* 用于推断当前位置是否为数字格
* @param index 当前位置
* @return true表示是
*/
public boolean contains(int index){
return stuffList.contains(index);
} /**
* 将当前的格子从数字列表中去掉
* @param index
*/
public void remove(int index){
int order = stuffList.indexOf(index);
numberList.remove(order);
stuffList.remove(order);
} /**
* 将当前格子相应的数字升级,指数加1
* @param index
*/
public void levelup(int index){
int order = stuffList.indexOf(index);
numberList.set(order, numberList.get(order)+1);
} /**
* 将当前格子相应的位置置换为新的位置
* @param index 当前位置
* @param newIndex 新的位置
*/
public void changeIndex(int index, int newIndex){
stuffList.set(stuffList.indexOf(index), newIndex);
} /**
* 通过格子相应的位置获取其相应的数字
* @param index 当前位置
* @return 格子相应数字的指数
*/
public int getNumberByIndex(int index){
int order = stuffList.indexOf(index);
return numberList.get(order) ;
} public String toString(){
return stuffList.toString()+numberList.toString();
} public void printLog(){
Log.i("stuffList", stuffList.toString());
Log.i("numberList", numberList.toString());
}
}
这个类主要是我对数字格、数字格相应数字的保存,和增删改等操作。
事实上就是两个list,我为了操作起来方便,所以把他们写在一个类里。
然后,我们来讲一下这个游戏的逻辑。
比方,我们在游戏过程中运行了一次向右滑动的操作,在这个操作中,我们要对全部能够移动和合并的格子进行推断和对应的操作:
1、数字格的右边假设是空白格。则数字格与空白格交换
2、数字格右边假设有多个空白格,则数字格与连续的最后一个空白格做交换
3、数字格的右边假设存在与之同样的数字格,则本格置空。右边的数字格升级(指数加一)
4、假设滑动方向连续存在多个同样的数字格,右的格子优先升级
5、在一次滑动中,每一个格子最多升级一次
当一个格子存在上述前四种中的随意一种时,则完毕了对它的操作
我们试着把上面的推断规则翻译成代码,首先,明白在GridLayout中的坐标位置。我在GridLayout中採用的是水平布局,所以每一个格子相应的位置例如以下
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhcGlubm9uZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
在这个基础上,我建立例如以下的坐标轴,以左上角为原点,x轴为横轴,y轴为竖轴:
当向右滑动的时候,从上面逻辑来看,为了方便,我们应当从右向左遍历格子
for(int y=0;y<4;y++){
for(int x=2;x>=0;x--){
int thisIdx = 4*y +x;
Change(thisIdx,direction);
}
}
每遍历到一个新的格子,运行一次change()方法。事实上应该是每遍历到一个非空的格子。运行一次change()可是我为了省事,把非空推断加到了change的代码里。我们看一下change()这种方法的实现。这种方法主要是用来推断,一个格子是须要移动、合并,还是什么都不操作。:
/**
* 该方法,为每一个符合条件的格子运行变动的操作。如置换,升级等
* @param thisIdx 当前格子的坐标
* @param direction 滑动方向
*/
public void Change(int thisIdx,int direction){
if(numberList.contains(thisIdx)){ int nextIdx = getLast(thisIdx, direction);
if(nextIdx == thisIdx){
//不能移动
return;
}else if(spaceList.contains(nextIdx)){
//存在能够置换的空白格
replace(thisIdx,nextIdx);
}else{
if(numberList.getNumberByIndex(thisIdx) == numberList.getNumberByIndex(nextIdx)){
//能够合并
levelup(thisIdx, nextIdx);
}else{
int before = getBefore(nextIdx, direction);
if(before != thisIdx){
//存在能够置换的空白格
replace(thisIdx,before);
}
}
}
}
}
当中getLast()方法,用于获取当前格子在移动方向的能够移动或者合并的最后一个格子,假设返回值还是当前的格子,则表示不能移动。当中调用的getNext()方法是为了获取当前格子在移动方向的下个格子的位置。
/**
* 用于获取移动方向上最后一个空白格之后的位置
* @param index 当前格子的坐标
* @param direction 移动方向
* @return
*/
public int getLast(int thisIdx, int direction){
int nextIdx = getNext(thisIdx, direction);
if(nextIdx < 0)
return thisIdx;
else{
if(spaceList.contains(nextIdx))
return getLast(nextIdx, direction);
else
return nextIdx;
}
}
然后是replace(int thisIdx, int nextIdx),这种方法是运行两个格子互换位置。内容主要是对两个格子中的view更换背景图片,然后操作空白格的list和数字格的list:
/**
* 该方法用来交换当前格与目标空白格的位置
* @param thisIdx 当前格子的坐标
* @param nextIdx 目标空白格的坐标
*/
public void replace(int thisIdx, int nextIdx){
moved = true;
//获取当前格子的view,并将其置成空白格
View thisView = gridLayout.getChildAt(thisIdx);
ImageView image = (ImageView) thisView.findViewById(R.id.image);
image.setBackgroundResource(icons[0]); //获取空白格的view,并将其背景置成当前格的背景
View nextView = gridLayout.getChildAt(nextIdx);
ImageView nextImage = (ImageView) nextView.findViewById(R.id.image);
nextImage.setBackgroundResource(icons[numberList.getNumberByIndex(thisIdx)]); //在空白格列表中。去掉目标格。加上当前格
spaceList.remove(spaceList.indexOf(nextIdx));
spaceList.add(thisIdx); //在数字格列表中,当前格的坐标置换成目标格的坐标
numberList.changeIndex(thisIdx, nextIdx);
}
levelup(int thisIdx, int nextIdx)这种方法是为了实现同样数字格的合并操作。事实上就是将当前的格子置成空白格。将移动方向上下一个格子相应的背景置成下一个背景:
/**
* 刚方法用于合并在移动方向上两个同样的格子
* @param thisIdx 当前格子的坐标
* @param nextIdx 目标格子的坐标
*/
public void levelup(int thisIdx, int nextIdx){ //一次移动中,每一个格子最多仅仅能升级一次
if(!changeList.contains(nextIdx)){
moved = true;
//获取当前格子的view,并将其置成空白格
View thisView = gridLayout.getChildAt(thisIdx);
ImageView image = (ImageView) thisView.findViewById(R.id.image);
image.setBackgroundResource(icons[0]); //获取目标格的view,并将其背景置成当前格升级后的背景
View nextView = gridLayout.getChildAt(nextIdx);
ImageView nextImage = (ImageView) nextView.findViewById(R.id.image);
nextImage.setBackgroundResource(icons[numberList.getNumberByIndex(nextIdx)+1]); //在空白格列表中增加当前格
spaceList.add(thisIdx);
//在数字列中删掉第一个格子
numberList.remove(thisIdx);
//将数字列表相应的内容升级
numberList.levelup(nextIdx); changeList.add(nextIdx);
} }
写完这些,基本完毕了基本的推断,可是还有两个问题:1是假设每次滑动没有格子移动(合并),那么就不应该新随机生成格子;2每一个格子仅仅能合并一次。
为解决这两个问题,我又加了两个变量
//用于保存每次操作时。已经升级过的格子
List<Integer> changeList = new ArrayList<Integer>(); //用于表示本次滑动是否有格子移动过
boolean moved = false;
当中changeList在每次滑动前清空,然后增加本次移动中发生过合并的格子,在每次合并的推断时首先看看要合并的格子是不是在这个list中。假设在的话,说明已经合并过。那么就不运行合并的操作了。
还有个波尔型的moved变量,这个也是在每次滑动前置为false,假设在本次滑动中,有格子移动或者合并,就置为ture,在滑动的最后。通过这个变量推断是否要随机生产新的格子。
以下是完整的Activity中的代码:
package com.example.t2048; import java.util.ArrayList;
import java.util.List;
import java.util.Random; import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.GridLayout;
import android.widget.ImageView; public class MainActivity extends Activity { final static int LEFT = -1;
final static int RIGHT = 1;
final static int UP = -4;
final static int DOWN = 4; GridLayout gridLayout = null; //用于保存空格的位置
List<Integer> spaceList = new ArrayList<Integer>(); //全部非空的格子
NumberList numberList = new NumberList(); //用于保存每次操作时,已经升级过的格子
List<Integer> changeList = new ArrayList<Integer>(); //用于表示本次滑动是否有格子移动过
boolean moved = false; GestureDetector gd = null; /**
* 图标数组
*/
private final int[] icons = { R.drawable.but_empty, R.drawable.but2,
R.drawable.but4, R.drawable.but8, R.drawable.but16,
R.drawable.but32, R.drawable.but64, R.drawable.but128,
R.drawable.but256, R.drawable.but512, R.drawable.but1024,
R.drawable.but2048, R.drawable.but4096 }; protected void onCreate(Bundle savedInstanceState) {
System.out.println("程序启动");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); gridLayout = (GridLayout) findViewById(R.id.GridLayout1); init(); MygestureDetector mg = new MygestureDetector(); gd = new GestureDetector(mg);
gridLayout.setOnTouchListener(mg);
gridLayout.setLongClickable(true);
} //初始化界面
public void init(){
System.out.println("初始化"); //首先在16个各种都填上空白的图片
for(int i=0;i<16;i++){
View view = View.inflate(this, R.layout.item, null);
ImageView image = (ImageView) view.findViewById(R.id.image); image.setBackgroundResource(icons[0]);
spaceList.add(i);
gridLayout.addView(view);
} //在界面中随机增加两个2或者4
addRandomItem();
addRandomItem();
} //从空格列表中随机获取位置
public int getRandomIndex(){
Random random = new Random();
if(spaceList.size()>0)
return random.nextInt(spaceList.size());
else
return -1;
} //在空白格中随机增加数字2或4
public void addRandomItem(){
int index = getRandomIndex();
if(index!=-1){
System.out.println("随机生成数字 位置"+spaceList.get(index));
//获取相应坐标所相应的View
View view = gridLayout.getChildAt(spaceList.get(index));
ImageView image = (ImageView) view.findViewById(R.id.image);
//随机生成数字1或2
int i = (int) Math.round(Math.random()+1);
//将当前格子的图片置换为2或者4
image.setBackgroundResource(icons[i]); //在numList中增加该格子的信息
numberList.add(spaceList.get(index), i); //在空白列表中去掉这个格子
spaceList.remove(index); }
} public class MygestureDetector implements OnGestureListener,OnTouchListener{ @Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return gd.onTouchEvent(event);
} @Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
} @Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) { // 參数解释:
// e1:第1个ACTION_DOWN MotionEvent
// e2:最后一个ACTION_MOVE MotionEvent
// velocityX:X轴上的移动速度,像素/秒
// velocityY:Y轴上的移动速度。像素/秒 // 触发条件 :
// X轴的坐标位移大于FLING_MIN_DISTANCE,且移动速度大于FLING_MIN_VELOCITY个像素/秒 if(e1.getX()-e2.getX()>100){
System.out.println("向左");
move(LEFT);
return true;
}else if(e1.getX()-e2.getX()<-100){
System.out.println("向右");
move(RIGHT);
return true;
}else if(e1.getY()-e2.getY()>100){
System.out.println("向上");
move(UP);
return true;
}else if(e1.getY()-e2.getY()<-00){
System.out.println("向下");
move(DOWN);
return true;
}
return false;
} @Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub } @Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
} @Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub } @Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
} } /**
* 用于获取移动方向上下一个格子的位置
* @param index 当前格子的位置
* @param direction 滑动方向
* @return 假设在边界在返回-1
*/
public int getNext(int index,int direction){ int y = index/4;
int x = index%4; if(x==3 && direction==RIGHT)
return -1;
if(x==0 && direction==LEFT)
return -1;
if(y==0 && direction==UP)
return -1;
if(y==3 && direction==DOWN)
return -1;
return index+direction;
} /**
* 用于获取移动方向上前一个格子的位置
* @param index 当前格子的位置
* @param direction 滑动方向
* @return 假设在边界在返回-1
*/
public int getBefore(int index,int direction){ int y = index/4;
int x = index%4; if(x==0 && direction==RIGHT)
return -1;
if(x==3 && direction==LEFT)
return -1;
if(y==3 && direction==UP)
return -1;
if(y==0 && direction==DOWN)
return -1;
return index-direction;
} /**
* 该方法用来交换当前格与目标空白格的位置
* @param thisIdx 当前格子的坐标
* @param nextIdx 目标空白格的坐标
*/
public void replace(int thisIdx, int nextIdx){
moved = true;
//获取当前格子的view,并将其置成空白格
View thisView = gridLayout.getChildAt(thisIdx);
ImageView image = (ImageView) thisView.findViewById(R.id.image);
image.setBackgroundResource(icons[0]); //获取空白格的view,并将其背景置成当前格的背景
View nextView = gridLayout.getChildAt(nextIdx);
ImageView nextImage = (ImageView) nextView.findViewById(R.id.image);
nextImage.setBackgroundResource(icons[numberList.getNumberByIndex(thisIdx)]); //在空白格列表中,去掉目标格。加上当前格
spaceList.remove(spaceList.indexOf(nextIdx));
spaceList.add(thisIdx); //在数字格列表中,当前格的坐标置换成目标格的坐标
numberList.changeIndex(thisIdx, nextIdx);
} /**
* 刚方法用于合并在移动方向上两个同样的格子
* @param thisIdx 当前格子的坐标
* @param nextIdx 目标格子的坐标
*/
public void levelup(int thisIdx, int nextIdx){ //一次移动中。每一个格子最多仅仅能升级一次
if(!changeList.contains(nextIdx)){
moved = true;
//获取当前格子的view,并将其置成空白格
View thisView = gridLayout.getChildAt(thisIdx);
ImageView image = (ImageView) thisView.findViewById(R.id.image);
image.setBackgroundResource(icons[0]); //获取目标格的view,并将其背景置成当前格升级后的背景
View nextView = gridLayout.getChildAt(nextIdx);
ImageView nextImage = (ImageView) nextView.findViewById(R.id.image);
nextImage.setBackgroundResource(icons[numberList.getNumberByIndex(nextIdx)+1]); //在空白格列表中增加当前格
spaceList.add(thisIdx);
//在数字列中删掉第一个格子
numberList.remove(thisIdx);
//将数字列表相应的内容升级
numberList.levelup(nextIdx); changeList.add(nextIdx);
} } /**
* 该方法为不同的滑动方向。运行不同的遍历顺序
* @param direction 滑动方向
*/
public void move(int direction){ moved = false; changeList.clear(); numberList.printLog(); switch(direction){
case RIGHT:
for(int y=0;y<4;y++){
for(int x=2;x>=0;x--){
int thisIdx = 4*y +x;
Change(thisIdx,direction);
}
}
break;
case LEFT:
for(int y=0;y<4;y++){
for(int x=1;x<=3;x++){
int thisIdx = 4*y +x;
Change(thisIdx,direction);
}
}
break;
case UP:
for(int x=0;x<4;x++){
for(int y=1;y<=3;y++){
int thisIdx = 4*y +x;
Change(thisIdx,direction);
}
}
break;
case DOWN:
for(int x=0;x<4;x++){
for(int y=2;y>=0;y--){
int thisIdx = 4*y +x;
Change(thisIdx,direction);
}
}
break;
} //假设本次滑动有格子移动过,则随机填充新的格子
if(moved)
addRandomItem(); } /**
* 该方法。为每一个符合条件的格子运行变动的操作,如置换,升级等
* @param thisIdx 当前格子的坐标
* @param direction 滑动方向
*/
public void Change(int thisIdx,int direction){
if(numberList.contains(thisIdx)){ int nextIdx = getLast(thisIdx, direction);
if(nextIdx == thisIdx){
//不能移动
return;
}else if(spaceList.contains(nextIdx)){
//存在能够置换的空白格
replace(thisIdx,nextIdx);
}else{
if(numberList.getNumberByIndex(thisIdx) == numberList.getNumberByIndex(nextIdx)){
//能够合并
levelup(thisIdx, nextIdx);
}else{
int before = getBefore(nextIdx, direction);
if(before != thisIdx){
//存在能够置换的空白格
replace(thisIdx,before);
}
}
}
}
} /**
* 用于获取移动方向上最后一个空白格之后的位置
* @param index 当前格子的坐标
* @param direction 移动方向
* @return
*/
public int getLast(int thisIdx, int direction){
int nextIdx = getNext(thisIdx, direction);
if(nextIdx < 0)
return thisIdx;
else{
if(spaceList.contains(nextIdx))
return getLast(nextIdx, direction);
else
return nextIdx;
}
} public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} }
写到这里,做为我学习Android以来。第一个自己写的程序已经完毕一半了。
逻辑推断这部分写的时候,还是费了一点时间,由于总有一些情况没有考虑进来,到如今基本上已经实现了。可是也反应出来一个非常重要的问题。那就是自己在数据结构和算法方面还是非常薄弱。整个读一下自己写的代码,为了完毕对各种情况的推断。整个代码看起来十分冗余。并且效率之低就更不用说了。再看看别人写的代码。感觉自己在开发方面还是有非常长的路要走的。
接下来的时间,我会利用工作之余的时间不断去完好这个程序,并尽可能的去优化。
大家共勉吧!
代码写成这样,我也不藏拙了,我把代码打包上传了,须要的朋友能够下载,也希望大家多多指正
从零開始开发Android版2048 (三)逻辑推断的更多相关文章
- 从零開始开发Android版2048 (一)初始化界面
自学Android一个月多了,一直在工作之余零零散散地看一些东西.感觉经常使用的东西都有些了解了,可是一開始写代码总会出各种奇葩的问题.感觉还是代码写得太少.这样继续杂乱地学习下去进度也太慢了,并且学 ...
- 从零開始开发Android版2048 (二)获取手势信息
今天是尝试開始Android版2048小游戏的第二天.在今天,我主要学习了怎样获取用户在屏幕滑动的手势,以及对布局进行了一些小小的完好. 获取用户操作的手势(比方向左滑.向右滑等)主要用到了Gestu ...
- 从零開始开发Android版2048 (四) 分数、重置、结束
这一篇的内容主要是在上一篇的基础上,增加分数计算(包含当前分数和最高分数).游戏结束的推断以及游戏界面的重置这三个部分的功能. 一.分数的计算和保存 首先,2048这个游戏的分数包含 ...
- 从零開始开发Android版2048 (五) 撤销的实现
本篇的内容是,在前一篇的基础上添�了撤销的功能.撤销事实上就是将当前的用户界面恢复到这次滑动值前的样子.我实现撤销的主要原理是,将每次滑动后界面上的格子和相应的数字记录下来,当然还有分数,把这些数据写 ...
- Bmob移动后端云服务平台--Android从零開始--(二)android高速入门
Bmob移动后端云服务平台--Android从零開始--(二)android高速入门 上一篇博文我们简介何为Bmob移动后端服务平台,以及其相关功能和优势. 本文将利用Bmob高速实现简单样例,进一步 ...
- 从零開始学android<TabHost标签组件.二十九.>
TabHost主要特点是能够在一个窗体中显示多组标签栏的内容,在Android系统之中每一个标签栏就称为一个Tab.而包括这多个标签栏的容器就将其称为TabHost.TabHost类的继承结构例如以下 ...
- 第13章、布局Layouts之RelativeLayout相对布局(从零開始学Android)
RelativeLayout相对布局 RelativeLayout是一种相对布局,控件的位置是依照相对位置来计算的,后一个控件在什么位置依赖于前一个控件的基本位置,是布局最经常使用,也是最灵活的一种布 ...
- 从零開始学android<SeekBar滑动组件.二十二.>
拖动条能够由用户自己进行手工的调节,比如:当用户须要调整播放器音量或者是电影的播放进度时都会使用到拖动条,SeekBar类的定义结构例如以下所看到的: java.lang.Object ↳ an ...
- 从零開始学android<数据存储(1)SharedPreferences属性文件.三十五.>
在android中有五种保存数据的方法.各自是: Shared Preferences Store private primitive data in key-value pairs. 相应属性的键值 ...
随机推荐
- Linux运维 -- 文件备份同步系列
[1.]文件备份与恢复 #()整盘数据备份-->另一个盘/一个image文件 dd if=/dev/sdb of=/dev/sde #备份到指定的image文件中 dd if=/dev/sdb ...
- [Codeforces #211] Tutorial
Link: Codeforces #211 传送门 一套非常简单的题目,但很多细节都是错了一次才能发现啊…… 还是不能养成OJ依赖症,交之前先多想想corner case!!! A: 模拟,要特判0啊 ...
- [Arc074E] RGB Sequence
[Arc074E] RGB Sequence Description 今天也在愉快地玩Minecraft!现在MM有一块1?N的空地,每个格子按照顺序标记为1到N.MM想要在这块空地上铺上红石块.绿宝 ...
- HDU 6053 TrickGCD(分块)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6053 [题目大意] 给出一个数列每个位置可以取到的最大值, 问这个可以构造多少个数列,使得他们的最 ...
- 【主席树】【最近公共祖先】hdu6162 Ch’s gift
题意:一棵树,每个点有个权值,m次询问,每次给你一条链和两个值a,b,问你这条链上权值在[a,b]之间的权值的和是多少. std竟然是2个log的……完全没必要链剖,每个结点的主席树从其父节点转移过 ...
- 【欧拉回路】【欧拉路径】【Fleury算法】CDOJ1634 记得小苹初见,两重心字罗衣
Fleury算法看这里 http://hihocoder.com/problemset/problem/1181 把每个点看成边,每个横纵坐标看成一个点,得到一个无向图. 如果新图中每个点的度都是偶数 ...
- 【动态规划/递推】BZOJ1806[IOI2007]- Miners
IOI历史上的著名水题,我这种蒟蒻都能写的东西. [思路] 用1.2.3分别代替三种食物,0表示当前矿井没有食物.f[i][a][b][c][d]当前第i个食物,矿1的食物顺序由上至下为a,b:矿2的 ...
- php的json_encode()之后float类型丢失精度
在后台php中,金额保留两位小数.但是前端显示精度丢失,出现了14位小数的奇怪现象.本来以为是前端js解析之后出现的问题.检查之后发现json_encode()之后就出现了. 原始的值: array( ...
- Java并发(五):synchronized实现原理
一.synchronized用法 Java中的同步块用synchronized标记. 同步块在Java中是同步在某个对象上(监视器对象). 所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操 ...
- Problem A: 逆序输出数列
#include<stdio.h> int main(void) { int n,i,a[100]; while(scanf("%d ",&n)!=EOF) { ...