android对战的象棋小游戏,使用GridView做棋盘

最近写了一个对战型的中国象棋,象棋嘛,这种类型的代码,网上一定是有的,然而我发现,网上关于各类象棋的代码,几乎全部都是用Canvas去写的。的确,Canvas在布局上经常会用到,画一些曲线图形和不规则图形用Canvas是很方便的事情(用android自带的也弄不出来,很尴尬)。然而,我觉得,做象棋这种矩形棋盘直接用android自带的控件就可以了,没有必要用Canvas自己去用代码写出来,用大量的代码去写一个矩形,这很麻烦,也没必要。考虑了一下,我决定用GridView尝试着去做一下象棋,结果发现很容易就实现了(这里不包括人机对战哦,那个算法很麻烦)。
为什么用GridView呢?我是这么想的:1、GridView是矩形的,分为横纵列,正好符合棋盘的样式结构。2、GridView很用于获取到item的position,有了position这个位置的标识,就很轻松的可以换算成横纵坐标。3、GridView可以设置背景嘛,可以随便从网上找个图片将它作为棋盘,然后将GridView的横纵分割线设置为透明的,将item设置成棋子,这样象棋的棋盘和棋子就可以算基本完成有了雏形。
棋盘很简单,只需要设置几个属性就好了,所以先来弄棋盘。给GridView加一个背景,设置一下每个item之间的间隔以及GridView的列数。由于象棋是十行九列的矩形,所以将列数设置为9(在这里,棋子的x,y坐标也出来了)。

 x = position / 9;
 y = position - 9 * x;

也就是只给GridView添加下面三个属性就好了。

        android:background="@drawable/checkerboard_bg"
        android:numColumns="9"
        android:verticalSpacing="3dp"

这样棋盘就算是完成了,当然了,棋子才是最重要的。首先要将全部的棋子放到棋盘上,这里我是在activity中直接添加的数据。那红棋子做个例子,就像这样:

 //红子
        mList.add(new Piece(0, "車"));
        mList.add(new Piece(0, "馬"));
        mList.add(new Piece(0, "相"));
        mList.add(new Piece(0, "仕"));
        mList.add(new Piece(0, "帅"));
        mList.add(new Piece(0, "仕"));
        mList.add(new Piece(0, "相"));
        mList.add(new Piece(0, "馬"));
        mList.add(new Piece(0, "車"));
        for (int i = 0; i < 9; i++) {
            mList.add(new Piece(0, ""));
        }
        mList.add(new Piece(0, ""));//18
        mList.add(new Piece(0, "炮"));//19
        for (int i = 0; i < 5; i++) {
            mList.add(new Piece(0, ""));
        }
        mList.add(new Piece(0, "炮"));
        mList.add(new Piece(0, ""));
        mList.add(new Piece(0, "兵"));
        mList.add(new Piece(0, ""));
        mList.add(new Piece(0, "兵"));
        mList.add(new Piece(0, ""));
        mList.add(new Piece(0, "兵"));
        mList.add(new Piece(0, ""));
        mList.add(new Piece(0, "兵"));
        mList.add(new Piece(0, ""));
        mList.add(new Piece(0, "兵"));
        for (int i = 0; i < 9; i++) {
            mList.add(new Piece(0, ""));
        }

然后根据不同类型的棋子进行划分(不同的棋子有不同的规则嗯),先创建一个棋子的基类,里面的属性就是棋子的横纵坐标,红黑方这类棋子共通的属性。再建立7个象棋棋子的子类,因为象棋的棋子一共分为7类(车马炮相仕帅兵)嘛。这7个子类分别写各自的行棋规则比如马走日,象走田。下棋需要两个部分组成,拿棋子和落棋子,所以这里就需要新旧连那个哥position(同时也就生成了两组x,y坐标)。拿帅做个例子(帅只能在九宫里走,要限定住这个条件),代码如下(PS:我写的x,y与正常的x,y是相反的!!!!! 不耽误看啦):

/**
 * 这里的x,y与正常的x,y是相反的
 * y是横轴   y是横轴   y是横轴    y是横轴   y是横轴
 */
public class Marshal extends Piece {

    private int xStep;
    private int yStep;

    public Marshal() {
    }
    /**
     * 帅只能在九宫里走
     * 红:(0,3)(0,4)(0,5)(1,3)(1,4)(1,5)(2,3)(2,4)(2,5)
     * 黑:(7,3)(7,4)(7,5)(8,3)(8,4)(8,5)(9,3)(9,4)(9,5)
     *
     * @return
     */
    public boolean judgeMarshal(int x, int y, int xOriginal, int yOriginal,int classType) {
        boolean isTrue = false;

        if (classType == 0) {//红
            if ((x < 3 && y > 2) && (x < 3 && y < 6)) {
                if (x == (xOriginal + 1) && y == yOriginal) {
                    isTrue = true;
                } else if (x == (xOriginal - 1) && y == yOriginal) {
                    isTrue = true;
                } else if (x == xOriginal && y == (yOriginal + 1)) {
                    isTrue = true;
                } else if (x == xOriginal && y == (yOriginal - 1)) {
                    isTrue = true;
                } else if (x == xOriginal && y == yOriginal) {
                    isTrue = true;
                } else {
                    isTrue = false;
                }
            } else {
                isTrue = false;
            }
        } else {//黑
            if ((x > 6 && y > 2) && (x > 6 && y < 6)) {
                if (x == (xOriginal + 1) && y == yOriginal) {
                    isTrue = true;
                } else if (x == (xOriginal - 1) && y == yOriginal) {
                    isTrue = true;
                } else if (x == xOriginal && y == (yOriginal + 1)) {
                    isTrue = true;
                } else if (x == xOriginal && y == (yOriginal - 1)) {
                    isTrue = true;
                } else if (x == xOriginal && y == yOriginal) {
                    isTrue = true;
                } else {
                    isTrue = false;
                }
            } else {
                isTrue = false;
            }
        }

        return isTrue;
    }
 }

在activity中先判断一下是拿棋子还是落棋子,这里我是用GridView的item点击事件来判断的,给她设一个变量,用来记录是否是第一次点击(如果是第一次点击,之前肯定是没有选中的棋子的)。第一次点击棋子就是拿棋子,当然,第二次点击便是落棋子,如果是第二次点击,将此变量清零。

if (pieceState == 0) {//判断棋子是否是正常状态,如果是正常状态,则可以进行选中走棋落子的操作
            choiceNone(text, position, itemText);
        } else {//如果棋子已经有选中的状态的,则不能再次选中其他棋子,只能走棋,落子
            if (mList.get(mBeforePosition).getClassType() == 0) {
                if (position == mBeforePosition) {//如果选中棋子之后想换一个棋子执行(红)
                //判断黑方执行次数  
                    blackExecutionTimes = 2;
                    //判断红方执行次数  
                    redExecutionTimes = 0;
                    mIsChangePiece = true;
                } else {
                    redExecutionTimes++;
                }
            } else {
                if (position == mBeforePosition) {//如果选中棋子之后想换一个棋子执行(黑)
                    redExecutionTimes = 2;
                    blackExecutionTimes = 0;
                    mIsChangePiece = true;
                } else {
                    blackExecutionTimes++;
                }
            }

 /**第一次点击item
     * 没有选择棋子的时候
     */
    private void choiceNone(String text, int position, TextView itemText) {
        if ("".equals(text) || TextUtils.isEmpty(text)) {
            Toast.makeText(getApplicationContext(), "请选择棋子", Toast.LENGTH_SHORT).show();
        } else { //选中的不是空棋子,则获取棋子上的字
//               setPieceState(itemText,text,position);
            if (mList.get(position).getClassType() == 0) {
                //先判断是红黑方 在对执行次数进行判断,选中时,执行次数为1,落下时为2,如果大于2,则执行另一方的棋子
                redExecutionTimes++;//1
                if (redExecutionTimes > 1) {//2
                    Toast.makeText(getApplicationContext(), "红方已经落子,请黑方落子!", Toast.LENGTH_SHORT).show();
                    blackExecutionTimes = 0;//3
                } else {
                    setPieceState(itemText, text, position);
                    blackExecutionTimes = 0;//4
                }
            } else {
                blackExecutionTimes++;//1
                if (blackExecutionTimes > 1) {//2
                    Toast.makeText(getApplicationContext(), "黑方已经落子,请红方落子!", Toast.LENGTH_SHORT).show();
                    redExecutionTimes = 0;//3
                } else {
                    setPieceState(itemText, text, position);
                    redExecutionTimes = 0;//4
                }
            }
        }
    }

上面代码中红黑方棋子的执行次数是指,如果红方执行次数大于两次(就代表拿棋子和落棋子都已经完成),就要换成黑方执行走棋落子,红黑交替,反之亦然。
然后判断是哪一类的棋子,调用相对于的方法进行判断。比如,调用judgeMarshal()方法,判断帅棋子是否符合规定。是很简单的吧。
然后来看看activity对棋子子类方法的调用

//先判断是那种棋子
if ("兵".equals(mShowPiece) || "卒".equals(mShowPiece)) {//卒
    setSoldierPiece(text, itemText, position);
} else if ("車".equals(mShowPiece) || "车".equals(mShowPiece)) {//車
   setCarPiece(text, itemText, position);
} else if ("帅".equals(mShowPiece) || "将".equals(mShowPiece)) {//帅
  setMarshalPiece(text, itemText, position);
} else if ("仕".equals(mShowPiece) || "士".equals(mShowPiece)) {//士
   setCounselorPiece(text, itemText, position);
} else if ("馬".equals(mShowPiece) || "马".equals(mShowPiece)) {//马
  setHorsePiece(text, itemText, position);
} else if ("相".equals(mShowPiece) || "象".equals(mShowPiece)) {
  setPrimeMinisterPiece(text, itemText, position);
} else if ("炮".equals(mShowPiece) || "砲".equals(mShowPiece)) {
  setGunPiece(text, itemText, position);
}
/**
     * 帅
     */
private void setMarshalPiece(String text, TextView itemText, int position) {
        if (marshal.judgeMarshal(x, y, xOriginal, yOriginal, classTypeOriginal)) {//帅的走棋规则
            showPieceResult(text, itemText, position);
            if (mList.get(position).getClassType() == 0) {//改变帅的位置后,将帅移动后的位置赋给帅的初始位
                mMarshalRedX = x;
                mMarshalRedY = y;
            } else {
                mMarshalBlackX = x;
                mMarshalBlackY = y;
            }
            judgeMarshalToFace(position);
            mIsCorrect = true;
        } else {
            Toast.makeText(getApplicationContext(), "请遵守规则", Toast.LENGTH_SHORT).show();
            mIsCorrect = false;
        }
    }
然后是判断落下棋子后的状态,是走棋,吃棋子,还是赢得了游戏。
/**
     * 落子后状态
     */
    private void showPieceResult(String text, TextView itemText, int position) {
        if ("".equals(text) || TextUtils.isEmpty(text)) {//如果落下的位置原来没有棋子
            setPieceTextState(itemText, position);
            showToastTv.setText("中国象棋");
            showToastTv.setTextColor(Color.BLACK);
        } else if (position == mBeforePosition) {
            setPieceTextState(itemText, position);
            showToastTv.setText("现在可以重新选择棋子!");
            showToastTv.setTextColor(Color.RED);
        } else {//如果有,判断是否为同一方棋子
            if (classTypeOriginal == mList.get(position).getClassType()) {
                Toast.makeText(getApplicationContext(), "不能吃掉已方棋子", Toast.LENGTH_SHORT).show();
                mIsCorrect = false;
            } else {
                setPieceTextState(itemText, position);
                mIsCorrect = true;

                if ("帅".equals(text)) {
                    showDialog("游戏结束,黑方胜");
                    return;
                } else if ("将".equals(text)) {
                    showDialog("游戏结束,红方胜");
                    return;
                } else {
                    if (mList.get(position).getClassType() == 0) {
                        redExecutionTimes++;//7
                    } else {
                        blackExecutionTimes++;//7
                    }
                    judgeMarshalToFace(position);
                }
                showToastTv.setText("中国象棋");
                showToastTv.setTextColor(Color.BLACK);
            }
        }
    }

 /**
     * 走棋 正确
     *
     * @param itemText
     * @param position
     */
    private void setPieceTextState(TextView itemText, int position) {
        itemText.setText(mShowPiece);//将第一次选中棋子上面的字赋给本次选中的位置
        itemText.setBackgroundResource(R.drawable.piece_normal);
        itemText.setVisibility(View.VISIBLE);///
        if (classTypeOriginal == 0) {
            itemText.setTextColor(Color.parseColor("#DC143C"));//执方颜色改变
            itemText.setRotation(180);
        } else {
            itemText.setTextColor(Color.parseColor("#3B3B3B"));//执方颜色改变
            itemText.setRotation(360);
        }
        mList.set(mBeforePosition, new Piece(classTypeOriginal, ""));
        mList.set(position, new Piece(classTypeOriginal, mShowPiece));
        mShowPiece = "";//将用来记录选中棋子上的字的变量清空
        mGridViewAdapter.notifyDataSetChanged();
        pieceState = 0;
    }

最后在item的点击事件中刷新adapter就可以了。
最后上一下adapter的代码,虽然没有什么东西。

  @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_gridview, parent, false);
            holder.mItemTV = (TextView) convertView.findViewById(R.id.piece_id_tv);
            holder.mItemTV.setText(mData.get(position).getPieceText());
            String pieceContext = holder.mItemTV.getText().toString();

            if (mData.get(position).getClassType() == 0) {
                holder.mItemTV.setTextColor(Color.parseColor("#DC143C"));
                holder.mItemTV.setRotation(180);
            } else {
                holder.mItemTV.setTextColor(Color.parseColor("#3B3B3B"));
                holder.mItemTV.setRotation(360);
            }
            if ("".equals(pieceContext) || TextUtils.isEmpty(pieceContext)) {
                holder.mItemTV.setVisibility(View.INVISIBLE);
            } else {
                holder.mItemTV.setVisibility(View.VISIBLE);
                holder.mItemTV.setBackgroundResource(R.drawable.piece_normal);
            }
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        return convertView;
    }

    public final class ViewHolder {
        public TextView mItemTV;
    }

    public void setData(List<Piece> data) {
        if (data != null) {
            this.mData.clear();
            this.mData.addAll(data);
            notifyDataSetChanged();
        }
    }

然后。。。就没有然后了,完成了 很简单,比Canvas简单多了,是吧。
之后准备搞一个蓝牙联机对战,待续。

呃。。。有想要源码的到这里(真的很简单的,真的)
源码下载

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值