棋盘游戏计划中意外的应用程序崩溃

时间:2013-08-04 11:13:01

标签: java android minimax crash

我有这个Android应用程序玩Go,一个棋盘游戏。该应用基于negamax  使用alpha beta修剪。

该应用适用于negamax搜索深度为1(搜索深度是rootnegamax()中传递给generate()的第三个参数,两者都在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;

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;}
}
}

0 个答案:

没有答案