Java 棋盘游戏程序中意外的应用程序崩溃
我有一个android应用程序,可以玩围棋,一种棋盘游戏。该应用程序基于 用alpha-beta修剪 该应用程序在negamax搜索深度为1时运行良好(搜索深度是传递给Java 棋盘游戏程序中意外的应用程序崩溃,java,android,minimax,crash,Java,Android,Minimax,Crash,我有一个android应用程序,可以玩围棋,一种棋盘游戏。该应用程序基于 用alpha-beta修剪 该应用程序在negamax搜索深度为1时运行良好(搜索深度是传递给generate()中rootnegamax()的第三个参数,这两个参数都在aiplayer类中)。然而,当搜索深度提高时,每当轮到电脑移动游戏时,应用程序就会说“不幸的是,Go已经停止”并崩溃。我发现在negamax()中注释出负责alpha-beta修剪的行可以解决这个问题,但我不知道为什么。我应该如何解决这个问题(当然,包括
generate()
中rootnegamax()
的第三个参数,这两个参数都在aiplayer
类中)。然而,当搜索深度提高时,每当轮到电脑移动游戏时,应用程序就会说“不幸的是,Go已经停止”并崩溃。我发现在negamax()
中注释出负责alpha-beta修剪的行可以解决这个问题,但我不知道为什么。我应该如何解决这个问题(当然,包括alpha-beta修剪)
这解决了问题:
int negamax( int alpha, int beta, int depth,int color )
{
if ( depth == 0) return evaluate(color);
int score;
for (play mv : moves(color))
{
mv.redo(_brd);
score = -negamax( -beta, -alpha, depth - 1,-color );
mv.undo(_brd);
// Commenting this out fixes the problem!?? if( score >= beta ) return beta;
if( score > alpha ) alpha = score;
}
return alpha;
}
我的应用程序的完整代码(请原谅代码的不完整性和我对某些编程约定的完全无知;这是一个非常早期的个人项目):
package com.jayjuang.testgo;
导入android.app.*;
导入android.content.*;
导入android.os.*;
导入android.R.*;
导入android.view.*;
导入android.graphics.*;
导入java.util.*;
公共类测试活动扩展了活动
{
@凌驾
创建时的公共void(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
goview goview=新goview(本);
setContentView(goview);
}
公共类goview扩展视图
{
公众意见仲裁人;
公共政府视图(上下文)
{
超级(上下文);
_vwabtr=新的viewarbiter(5,这个,新的aiplayer(1),新的viewplayer());
_vwabtr.start();
}
受保护的void onDraw(画布)
{
_vwabtr._vbrd.绘图(画布);
}
公共布尔onTouchEvent(运动事件)
{
对于(viewplayer plr:_vwabtr._plrs)plr.事件(event);
返回true;
}
}
公共类aiplayer扩展了viewplayer
{
对象_locker=新对象();
内部颜色;
玩游戏;
国际移动;
布尔就绪=假;
@凌驾
中的公共void(字符串输入)
{
新线程(new Runnable(){public void run(){process();}}});
}
@凌驾
公共程序()
{
已同步(_locker)
{
生成();
就绪=正确;
_locker.notifyAll();
返回;
}
}
@凌驾
公共字符串输出()
{
已同步(_locker)
{
虽然(!ready)尝试{{u locker.wait();}catch(InterruptedException e){}
就绪=错误;
返回新整数(_move).toString();
}
}
@凌驾
公共无效事件(MotionEvent m){}
公共aiplayer(int颜色)
{
_颜色=颜色;
}
void生成()
{
rootnegamax(整数、最小值、整数、最大值,2);
对于(整数id:_ply._chgs.keySet())
if(_ply._chgs.get(id).getValue()!=0){u move=id;return;}
_move=-1;
}
void rootnegamax(int alpha、int beta、int depth)
{
如果(深度==0)返回;
智力得分;
用于(播放mv:移动(_颜色))
{
mv.重做(_brd);
分数=-negamax(-beta,-alpha,深度-1,-u色);
mv.undo(_brd);
如果(分数>α)
{
_厚度=mv;
α=分数;
}
}
}
int negamax(int alpha、int beta、int depth、int color)
{
如果(深度==0)返回评估(颜色);
智力得分;
用于(播放mv:移动(颜色))
{
mv.重做(_brd);
分数=-negamax(-beta,-alpha,深度-1,-颜色);
mv.undo(_brd);
如果(得分>=beta)返回beta;
如果(分数>α)α=分数;
}
返回α;
}
公共整数评估(整数颜色)
{
整数和=0;
对于(点p:_brd._pnts.values())
{
如果(p._color==1)和++;
如果(p._color==-1)和--;
}
返回颜色*总和;
}
公共堆栈移动(int颜色)
{
随机r=新随机();
ArrayList ID=新的ArrayList(_brd._pnts.keySet());
ArrayList RandomId=新的ArrayList();
而(!ids.isEmpty())
{
int id=r.nextInt(id.size());
添加(id.get(id));
id.remove(id);
}
堆栈mvs=新堆栈();
for(int-id:randomids)
{
播放层=移动(id、颜色);
如果(厚度!=null)mvs.push(厚度);
}
播放层=新播放();
ply._chgs=new HashMap();
mvs推(层);
返回mvs;
}
公共播放移动(整数id,整数颜色)
{
标准板brd=(标准板)\brd;
int x=id/brd.\u尺寸;
int y=id%brd.\u大小;
if(brd.\u pnts.get(id)。\u color!=0)返回null;
HashMap chgs=新的HashMap();
brd.移动(id、颜色);
chgs.put(id,新的AbstractMap.SimpleEntry(0,颜色));
如果(y>0&&brd.\u pnts.get(id-1)。\u color==-color)for(int-badid:standard\u-board\u-clean(brd,id-1)){brd.move(badid,0);chgs.put(badid,new-AbstractMap.SimpleEntry(-color,0));}
if(y0&&brd.\u pnts.get(id brd.\u size)。\u color==-color)for(int badid:standard_board_clean(brd,id brd.\u size)){brd.move(badid,0);chgs.put(badid,new AbstractMap.SimpleEntry(-color,0))}
如果(xPost)日志请。不幸的是,我没有花时间在我的计算机上设置ADT,并且到目前为止一直在开发完全在板上的应用程序,因此,没有日志。比使用日志“了解”它崩溃的原因更好。好的。我会尽快这样做。
package com.jayjuang.testgo;
import android.app.*;
import android.content.*;
import android.os.*;
import android.R.*;
import android.view.*;
import android.graphics.*;
import java.util.*;
public class testactivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
goview goview = new goview(this);
setContentView(goview);
}
public class goview extends View
{
public viewarbiter _vwabtr;
public goview(Context context)
{
super(context);
_vwabtr=new viewarbiter(5,this,new aiplayer(1), new viewplayer());
_vwabtr.start();
}
protected void onDraw(Canvas canvas)
{
_vwabtr._vbrd.draw(canvas);
}
public boolean onTouchEvent(MotionEvent event)
{
for(viewplayer plr : _vwabtr._plrs) plr.event(event);
return true;
}
}
public class aiplayer extends viewplayer
{
Object _locker=new Object();
int _color;
play _ply;
int _move;
Boolean ready=false;
@Override
public void in(string input)
{
new Thread(new Runnable(){public void run(){process();}}).start();
}
@Override
public void process()
{
synchronized(_locker)
{
generate();
ready=true;
_locker.notifyAll();
return;
}
}
@Override
public String out()
{
synchronized(_locker)
{
while (!ready)try{_locker.wait();}catch(InterruptedException e){}
ready=false;
return new Integer(_move).toString();
}
}
@Override
public void event(MotionEvent m){}
public aiplayer(int color)
{
_color=color;
}
void generate()
{
rootnegamax(Integer.MIN_VALUE,Integer.MAX_VALUE,2);
for (Integer id:_ply._chgs.keySet())
if (_ply._chgs.get(id).getValue()!=0){_move=id;return;}
_move=-1;
}
void rootnegamax( int alpha, int beta, int depth )
{
if ( depth == 0)return;
int score;
for (play mv : moves(_color))
{
mv.redo(_brd);
score = -negamax( -beta, -alpha, depth - 1,-_color );
mv.undo(_brd);
if( score > alpha )
{
_ply=mv;
alpha = score;
}
}
}
int negamax( int alpha, int beta, int depth,int color )
{
if ( depth == 0) return evaluate(color);
int score;
for (play mv : moves(color))
{
mv.redo(_brd);
score = -negamax( -beta, -alpha, depth - 1,-color );
mv.undo(_brd);
if( score >= beta ) return beta;
if( score > alpha ) alpha = score;
}
return alpha;
}
public int evaluate(int color)
{
int sum=0;
for (point p : _brd._pnts.values())
{
if (p._color==1) sum++;
if (p._color==-1) sum--;
}
return color*sum;
}
public Stack<play> moves(int color)
{
Random r = new Random();
ArrayList<Integer> ids=new ArrayList<Integer>(_brd._pnts.keySet());
ArrayList<Integer> randomids=new ArrayList<Integer>();
while (!ids.isEmpty())
{
int id=r.nextInt(ids.size());
randomids.add(ids.get(id));
ids.remove(id);
}
Stack<play> mvs = new Stack<play>();
for (int id : randomids)
{
play ply=move(id,color);
if (ply!=null)mvs.push(ply);
}
play ply=new play();
ply._chgs=new HashMap<Integer,AbstractMap.SimpleEntry<Integer,Integer>>();
mvs.push(ply);
return mvs;
}
public play move(int id, int color)
{
standard_board brd=(standard_board)_brd;
int x=id/brd._size;
int y=id%brd._size;
if (brd._pnts.get(id)._color!=0) return null;
HashMap<Integer,AbstractMap.SimpleEntry<Integer,Integer>> chgs = new HashMap<Integer,AbstractMap.SimpleEntry<Integer,Integer>>();
brd.move(id,color);
chgs.put(id, new AbstractMap.SimpleEntry<Integer,Integer>(0,color));
if (y>0&&brd._pnts.get(id-1)._color==-color) for(int badid : standard_board_clean(brd,id-1)){brd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
if (y<brd._size-1&&brd._pnts.get(id+1)._color==-color) for(int badid : standard_board_clean(brd,id+1)){brd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
if (x>0&&brd._pnts.get(id-brd._size)._color==-color) for(int badid : standard_board_clean(brd,id-brd._size)){brd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
if (x<brd._size-1&&brd._pnts.get(id+brd._size)._color==-color) for(int badid : standard_board_clean(brd,id+brd._size)){brd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
ArrayList<Integer> suicide = standard_board_clean(brd,id);
if (suicide.size()!=0){chgs.remove(id);brd.move(id,0);}
for(int badid : suicide){if (badid!=id){brd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(color,0));}}
play ply=new play();
ply._chgs=chgs;
ply.undo(brd);
if (_game._ply._chgs!=null&&_game._ply._chgs.size()==2&&chgs.size()==2&&Arrays.deepEquals(_game._ply._chgs.keySet().toArray(),chgs.keySet().toArray()))return null;
return ply;
}
}
public class viewboard extends standard_board
{
int _intv,_inix=0;
public viewboard(int size){super(size);}
public void draw(Canvas canvas)
{
int x=canvas.getClipBounds().width();
int y=canvas.getClipBounds().height();
_intv = (y<x?y:x)/(_size+1);
_inix = (x-(y<x?y:x)*(_size-1)/(_size+1))/2;
Paint white = new Paint();
white.setARGB(255,255,255,255);
Paint black = new Paint();
black.setARGB(255,0,0,0);
Paint light = new Paint();
light.setARGB(255,200,200,200);
canvas.drawPaint(white);
for (int xin=1;xin<=_size;xin++)
{
canvas.drawLine(_inix+(xin-1)*_intv,_intv,_inix+(xin-1)*_intv,_size*_intv,black);
}
for (int yin=1;yin<=_size;yin++)
{
canvas.drawLine(_inix,yin*_intv,_inix+(_size-1)*_intv,yin*_intv,black);
}
for (int xin=0;xin<_size;xin++)
{
for (int yin=0;yin<_size;yin++)
{
if (_pnts.get(xin*_size+yin)._color==1) canvas.drawCircle((float)(_inix+xin*_intv),(float)(yin+1)*_intv,((float)_intv)/2,black);
if (_pnts.get(xin*_size+yin)._color==-1) canvas.drawCircle((float)(_inix+xin*_intv),(float)(yin+1)*_intv,((float)_intv)/2,light);
}
}
}
}
public class viewplayer extends player
{
LinkedList<Thread> _evntqueue;
LinkedList<Thread> _outqueue;
Boolean _ready=false;
Integer _id;
viewarbiter _vwabtr;
Object _locker=new Object();
@Override
public void in(string input)
{
Thread procthrd = new Thread(new Runnable(){public void run(){process();}});
_evntqueue.add(procthrd);
_outqueue.add(procthrd);
procthrd.start();
}
@Override
public void process()
{
synchronized(_locker)
{
while(!_ready)
{
try{_locker.wait();}
catch(InterruptedException e){}
}
_ready=false;
Thread.currentThread().setName(_id.toString());
}
_evntqueue.remove(Thread.currentThread());
}
@Override
public String out()
{
try
{
Thread procthrd=_outqueue.poll();
if (procthrd==null)return null;
procthrd.join();
return procthrd.getName();
}
catch(InterruptedException e)
{
return null;
}
}
public void event(MotionEvent event)
{
if (_evntqueue.isEmpty()) return;
if ((event.getAction()|MotionEvent.ACTION_UP)!=event.getAction()) return;
viewboard brd=_vwabtr._vbrd;
float x=event.getX();
float y=event.getY();
if (x<brd._inix-0.5*brd._intv||x>=brd._inix+(brd._size-0.5)*brd._intv) return;
if (y<brd._intv*0.5||y>=(brd._size+0.5)*brd._intv) return;
_id=(brd._size*java.lang.Math.round((x-brd._inix)/brd._intv)+java.lang.Math.round(y/brd._intv)-1);
synchronized(_locker)
{
_ready=true;
_locker.notifyAll();
}
}
public viewplayer()
{
_evntqueue=new LinkedList<Thread>();
_outqueue=new LinkedList<Thread>();
}
}
public class viewarbiter extends arbiter
{
viewboard _vbrd;
ArrayList<viewplayer> _plrs;
Thread _thrd;
goview _goview;
@Override
public void start()
{
_thrd=new Thread(new Runnable()
{
public void run()
{
for (int turn=0;;turn++)
{
do{_plrs.get(turn%2).in(null);}
while (!move(Integer.parseInt(_plrs.get(turn%2).out()),1-2*(turn%2)));
}
}
});
_thrd.start();
}
@Override
public void stop()
{
_thrd.stop();
}
@Override
public void attach(player player)
{
try
{
if (_plrs.size()<2) _plrs.add((viewplayer)player);
((viewplayer)player)._vwabtr=this;
player._brd=_brd;
player._game=_game;
}
catch(Exception e){}
}
public viewarbiter(int size, goview goview,viewplayer viewplayer1, viewplayer viewplayer2)
{
_game=new game(new play());
_plrs=new ArrayList<viewplayer>();
_goview=goview;
_brd=_vbrd=new viewboard(size);
attach(viewplayer1);
attach(viewplayer2);
}
public Boolean move(int id, int color)
{
if (id==-1)
{
play ply=new play();
ply._chgs=null;
game gm=new game(ply);
game_attach(gm,_game);
_game=gm;
return true;
}
int x=id/_vbrd._size;
int y=id%_vbrd._size;
if (_vbrd._pnts.get(id)._color!=0) return false;
HashMap<Integer,AbstractMap.SimpleEntry<Integer,Integer>> chgs = new HashMap<Integer,AbstractMap.SimpleEntry<Integer,Integer>>();
_vbrd.move(id,color);
chgs.put(id, new AbstractMap.SimpleEntry<Integer,Integer>(0,color));
if (y>0&&_vbrd._pnts.get(id-1)._color==-color) for(int badid : standard_board_clean(_vbrd,x*_vbrd._size+y-1)){_vbrd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
if (y<_vbrd._size-1&&_vbrd._pnts.get(id+1)._color==-color) for(int badid : standard_board_clean(_vbrd,x*_vbrd._size+y+1)){_vbrd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
if (x>0&&_vbrd._pnts.get(id-_vbrd._size)._color==-color) for(int badid : standard_board_clean(_vbrd,(x-1)*_vbrd._size+y)){_vbrd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
if (x<_vbrd._size-1&&_vbrd._pnts.get(id+_vbrd._size)._color==-color) for(int badid : standard_board_clean(_vbrd,(x+1)*_vbrd._size+y)){_vbrd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(-color,0));}
ArrayList<Integer> suicide=standard_board_clean(_vbrd,id);
if (suicide.size()>0){chgs.remove(id);_vbrd.move(id,0);}
for(int badid : suicide){if (badid!=id){_vbrd.move(badid,0);chgs.put(badid, new AbstractMap.SimpleEntry<Integer,Integer>(color,0));}}
_goview.postInvalidate();
play ply=new play();
ply._chgs=chgs;
game gm=new game(ply);
game_attach(gm,_game);
_game=gm;
return true;
}
}
public class standard_board extends board
{
int _size;
public standard_board(int size)
{
_size=size;
_pnts=new HashMap<Integer,point>();
int id=0;
for (int xin=0;xin<size;xin++)
{
for (int yin=0;yin<size;yin++)
{
_pnts.put(id,new point(0));
if (xin>0) point_connect(_pnts.get(id),_pnts.get(id-size));
if (yin>0) point_connect(_pnts.get(id),_pnts.get(id-1));
id++;
}
}
}
}
public ArrayList<Integer> standard_board_clean(standard_board stdbrd,int id)
{
int color=stdbrd._pnts.get(id)._color;
int x,y;
ArrayList<Integer> fnd=new ArrayList<Integer>();
Stack<Integer> news=new Stack<Integer>();
Stack<Boolean> a=new Stack<Boolean>();
Stack<Boolean> b=new Stack<Boolean>();
Stack<Boolean> c=new Stack<Boolean>();
Stack<Boolean> d=new Stack<Boolean>();
int fx,fy;
news.push(id);
while (!news.empty())
{
id=news.pop();
x=id/stdbrd._size;
y=id%stdbrd._size;
a.push(y!=0);
b.push(y!=stdbrd._size-1);
c.push(x!=0);
d.push(x!=stdbrd._size-1);
for (int fid : fnd)
{
fx=fid/stdbrd._size;
fy=fid%stdbrd._size;
if (fx==x&&fy==y-1) {a.pop();a.push(false);}
if (fx==x&&fy==y+1) {b.pop();b.push(false);}
if (fx==x-1&&fy==y) {c.pop();c.push(false);}
if (fx==x+1&&fy==y) {d.pop();d.push(false);}
}
if (a.peek()&&stdbrd._pnts.get(id-1)._color==0) return new ArrayList<Integer>();
if (b.peek()&&stdbrd._pnts.get(id+1)._color==0) return new ArrayList<Integer>();
if (c.peek()&&stdbrd._pnts.get(id-stdbrd._size)._color==0) return new ArrayList<Integer>();
if (d.peek()&&stdbrd._pnts.get(id+stdbrd._size)._color==0) return new ArrayList<Integer>();
fnd.add(id);
if (a.pop()&&stdbrd._pnts.get(id-1)._color==color) news.push(id-1);
if (b.pop()&&stdbrd._pnts.get(id+1)._color==color) news.push(id+1);
if (c.pop()&&stdbrd._pnts.get(id-stdbrd._size)._color==color) news.push(id-stdbrd._size);
if (d.pop()&&stdbrd._pnts.get(id+stdbrd._size)._color==color) news.push(id+stdbrd._size);
news.removeAll(fnd);
}
return fnd;
}
public class point
{
int _color;
point[] _adjs;
public point(int color)
{
_color=color;
_adjs=new point[0];
}
}
static public void point_connect(point point1, point point2)
{
point1._adjs=Arrays.copyOf(point1._adjs,point1._adjs.length+1);
point2._adjs=Arrays.copyOf(point2._adjs,point2._adjs.length+1);
point1._adjs[point1._adjs.length-1]=point2;
point2._adjs[point2._adjs.length-1]=point1;
}
public class board
{
HashMap<Integer,point> _pnts;
public void move(int id, int color)
{
_pnts.get(id)._color=color;
}
}
public class play
{
HashMap<Integer,AbstractMap.SimpleEntry<Integer,Integer>> _chgs;
public void redo(board board)
{
for(int id : _chgs.keySet())
{
board.move(id, _chgs.get(id).getValue());
}
}
public void undo(board board)
{
for(int id : _chgs.keySet())
{
board.move(id, _chgs.get(id).getKey());
}
}
}
public class game
{
play _ply;
game _prnt;
game[] _cdrn;
public game(play play)
{
_ply=play;
_prnt=null;
_cdrn=new game[0];
}
}
static public void game_attach(game child, game parent)
{
if (child._prnt!=null) return;
child._prnt=parent;
parent._cdrn=Arrays.copyOf(parent._cdrn,parent._cdrn.length+1);
parent._cdrn[parent._cdrn.length-1]=child;
}
public class arbiter
{
board _brd;
game _game;
public void start(){}
public void stop(){}
public void attach(player player){}
}
public class player
{
board _brd;
game _game;
public void in(string input){}
public void process(){}
public String out(){return null;}
}
}