最终效果:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.caobotao.crazycat" > <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>

MainActivity.java

package com.example.caobotao.crazycat;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new PlayGround(this));
}
}

Dot.java

package com.example.caobotao.crazycat;

/**
* Created by caobotao on 15/11/9.
*/
public class Dot {
private int x;
private int y;
private int status;
static final int STATUS_ON = 1;//障碍的圆圈状态
static final int STATUS_OFF = 0;//可点击的圆圈状态
static final int STATUS_IN = 9;//猫所在的圆圈状态
public Dot(){}
//实例化时每个圆圈都是可点击的状态
public Dot(int x,int y){
this.x = x;
this.y = y;
status = STATUS_OFF;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
} public int getStatus() {
return status;
} public void setStatus(int status) {
this.status = status;
} public void setXY(int x,int y){
this.x = x;
this.y = y;
}
}

PlayGround.java

package com.example.caobotao.crazycat;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast; import java.util.HashMap;
import java.util.Vector; /**
* Created by caobotao on 15/11/9.
*/
public class PlayGround extends SurfaceView implements OnTouchListener{
private static int WIDTH = 45;//圆圈宽度
private static final int ROW = 10;//每行显示的圆圈数
private static final int COL = 10;//每列显示的圆圈数
private static final int Blocks = 13;//初始化障碍的个数
private Dot matrix[][];
private Dot cat;
public PlayGround(Context context) {
super(context);
getHolder().addCallback(callback);
//声明ROW x COL的圆圈矩阵并初始化
matrix = new Dot[ROW][COL];
for (int i = 0;i < ROW;i ++){
for (int j = 0;j < ROW;j ++){
matrix[i][j] = new Dot(j,i);
}
}
initGame();
setOnTouchListener(this);
}
private void redraw(){
//初始化画板
Canvas canvas = getHolder().lockCanvas();
// Log.i("info", "222222");
//设置画板背景色
canvas.drawColor(Color.LTGRAY);
Paint p = new Paint();
p.setFlags(Paint.ANTI_ALIAS_FLAG);
//设置不同状态的圆圈的颜色,并绘制
for (int i = 0;i < ROW;i ++){
int offset = 0;
//如果为偶数行,设置半个圆圈宽度的偏移量
if (i % 2 != 0){
offset = WIDTH / 2;
}
for (int j = 0;j < COL; j ++){
Dot one = getDot(j, i);
switch (one.getStatus()){
case Dot.STATUS_OFF:
p.setColor(0xFFEEEEEE);
break;
case Dot.STATUS_ON:
p.setColor(0xFFFFAA00);
break;
case Dot.STATUS_IN:
p.setColor(0xFFFF0000);
break;
}
RectF rectF = new RectF(one.getX() * WIDTH + offset, one.getY() * WIDTH,
(one.getX() + 1) * WIDTH + offset, (one.getY() + 1) * WIDTH);;
// if(i % 2 ==0) {
// rectF = new RectF((one.getX() + 1) * WIDTH, (one.getY() + 2) * WIDTH, (one.getX() + 2) * WIDTH, (one.getY() + 2) * WIDTH);
// }
canvas.drawOval(rectF,p);
}
}
getHolder().unlockCanvasAndPost(canvas);
}
private void initGame(){
//将每个圆圈初始化为可点击状态
for (int i = 0;i < ROW;i ++){
for (int j = 0;j < ROW;j ++){
matrix[i][j].setStatus(Dot.STATUS_OFF);
}
}
//将(4,5)设置初始化为猫所在的圆圈,并将状态设置为猫所在
cat = getDot(4,5);
cat.setStatus(Dot.STATUS_IN);
//随机设置Blocks个障碍
for (int i = 0 ;i < Blocks;){
int x = (int) ((Math.random() * 1000)%COL);
int y = (int) ((Math.random() * 1000)%ROW);
if(getDot(x,y).getStatus() == Dot.STATUS_OFF){
getDot(x,y).setStatus(Dot.STATUS_ON);
i ++;
}
} }
private boolean isAtEdge(Dot dot){
//判断某个圆圈是否在边缘
if(dot.getX() * dot.getY() == 0 || dot.getX()+1 == ROW || dot.getY() + 1 == COL){
return true;
}
return false;
}
//获取某个圆圈的左起1,2,3,4,5,6方向的相邻的圆圈
private Dot neighbour(Dot dot,int dir){
int x = -1;
int y = -1;
switch (dir){
case 1:
//return getDot(dot.getX()-1,dot.getY());
x = dot.getX()-1;
y = dot.getY();
break;
case 2:
if(dot.getY() % 2 == 0){
x = dot.getX() - 1;
y = dot.getY() - 1;
}
else {
x = dot.getX();
y = dot.getY() - 1;
}
break;
case 3:
if(dot.getY() % 2 == 0){
x = dot.getX() ;
y = dot.getY() - 1;
}
else {
x = dot.getX() + 1;
y = dot.getY() - 1;
}
break;
case 4:
x = dot.getX() + 1;
y = dot.getY();
break;
case 5:
if(dot.getY() % 2 == 0){
x = dot.getX() ;
y = dot.getY() + 1;
}
else {
x = dot.getX() + 1;
y = dot.getY() + 1;
}
break;
case 6:
if(dot.getY() % 2 == 0){
x = dot.getX() - 1;
y = dot.getY() + 1;
}
else {
x = dot.getX();
y = dot.getY() + 1;
}
break;
}
if (x != -1 || y != -1){
return getDot(x,y);
}
return null;
}
//获取某个圆圈在某个方向到矩阵边缘或到障碍的距离,如果是到边缘,返回正值,如果是到障碍,返回负值
private int getDistance(Dot dot,int dir){
int distance = 0;
if (isAtEdge(dot)){
return 1;
}
Dot ori = dot;
Dot next;
while (true){
next = neighbour(ori,dir);
if (next.getStatus() == Dot.STATUS_ON){
return distance * -1;
}
if (isAtEdge(next)){
distance ++;
return distance;
}
distance ++;
ori = next;
}
}
//将猫移动到某个圆圈
private void moveTo(Dot dot){
Dot temp = new Dot();
temp = dot;
dot = cat;
cat = temp;
cat.setStatus(Dot.STATUS_IN);
dot.setStatus(Dot.STATUS_OFF);
//如果移动后猫已在矩阵边缘,则游戏失败
if (isAtEdge(cat)){
lose();
}
// getDot(cat.getX(),cat.getY()).setStatus(Dot.STATUS_OFF);
// dot.setStatus(Dot.STATUS_IN);
// cat.setXY(dot.getX(), dot.getY());
}
private Dot getDot(int x,int y){
return matrix[y][x];
}
Callback callback = new Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
redraw();
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//根据屏幕自适应每个圆圈的宽度
WIDTH = width / (COL + 1);
redraw();
} @Override
public void surfaceDestroyed(SurfaceHolder holder) { }
}; @Override
public boolean onTouch(View v, MotionEvent event) {
// Log.i("info","33333"); if (event.getAction() == MotionEvent.ACTION_UP){
// Log.i("info", "44444");
// Toast.makeText(getContext(),event.getX() + ":" + event.getY(),Toast.LENGTH_SHORT).show();
int x,y;
//获取点击点所在的列数
y = (int) (event.getY() / WIDTH);
//获取点击点所在的行数
if (y % 2 == 0){
x = (int) (event.getX() / WIDTH);
}
else {
x = (int) ((event.getX() - WIDTH/2) / WIDTH);
}
//如果点击点不在矩阵范围内,重新初始化游戏
if (x + 1 > COL || y + 1 > ROW){
initGame();
}
//否则如果点击的圆圈的状态是可点击的,就将此圆圈的状态设置为障碍,并将猫进行移动
else if (getDot(x,y).getStatus() == Dot.STATUS_OFF){
getDot(x,y).setStatus(Dot.STATUS_ON);
move();
}
redraw();
//
}
return true;
} private void move() {
//如果猫已在矩阵边缘,则游戏失败
if (isAtEdge(cat)){
lose();
return;
}
//猫可以移动的圆圈
Vector<Dot> available = new Vector<Dot>();
//猫可以移动的到矩阵边缘没有障碍的圆圈
Vector<Dot> positive = new Vector<Dot>();
HashMap<Dot,Integer> al = new HashMap<Dot,Integer>();
for (int i =1;i<7;i++){
Dot n = neighbour(cat,i);
if(n.getStatus() == Dot.STATUS_OFF){
available.add(n);
al.put(n,i);
if (getDistance(n,i) > 0){
positive.add(n);
}
}
}
//如果猫没有可以移动的圆圈,则游戏成功
if (available.size() == 0){
win();
}
//如果猫只有一个可以移动的圆圈,则移动到此圆圈
else if (available.size() == 1){
moveTo(available.get(0));
}
//否则选最优的圆圈进行移动
else{
Dot best = null;
//如果存在可以直接到达屏幕边缘的走向
if (positive.size() != 0){
System.out.println("向前进");
int min = 999;
for (int i = 0;i < positive.size();i ++){
int a = getDistance(positive.get(i), al.get(positive.get(i)));
if (a < min){
min = a;
best = positive.get(i);
}
}
}
//所有路径均有路障
else{
System.out.println("躲路障");
int max = 0;
for (int i = 0; i < available.size();i ++){
int k = getDistance(available.get(i),al.get(available.get(i)));
if (k < max){
max = k;
best = available.get(i);
}
}
} if(best != null) {
moveTo(best);
}
else{
moveTo(available.get(0));
} // Dot d = available.get(0);
// for (int i = 1;i<available.size();i++){
// if ( Math.min(available.get(i).getX(), available.get(i).getY()) < Math.min(d.getX(),d.getY()) ){
// d = available.get(i);
// }
// }
// moveTo(d);
}
}
//赢得游戏
private void win() {
Toast.makeText(getContext(),"YOU HAVE WON THE GAME!",Toast.LENGTH_SHORT).show();
}
//游戏失败
private void lose() {
Toast.makeText(getContext(),"YOU HAVE LOST THE GAME!",Toast.LENGTH_SHORT).show();
}
} 注:由于本项目只是用于简单学习交流,代码中难免会有bug出现,请自行调试修改。

作者:caobotao
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

Android实战源码--围住神经猫的更多相关文章

  1. Android项目源码分享

    http://blog.csdn.net/gao_chun/article/details/47263063 Android项目源码分享 给大家分享几个Android开发项目源码,大部分功能相信可以在 ...

  2. 45个android实例源码

    分享45个android实例源码,很好很强大http://www.apkbus.com/android-20978-1-1.html andriod闹钟源代码http://www.apkbus.com ...

  3. 分享45个android实例源码,很好很强大

    分享45个android实例源码,很好很强大 http://www.apkbus.com/android-20978-1-1.html 分享45个android实例源码,很好很强大http://www ...

  4. 将Android系统源码导入ecplise

    Android系统源码中带有个IDE的配置文件,目录为:development/ide/ 如果要用eclipse导入查看系统源码,则将development/ide/eclipse/.classpat ...

  5. Android 如何在Eclipse中查看Android API源码 及 support包源码

    当我们阅读android API开发文档时候,上面的每个类,以及类的各个方法都是已经写好的方法和控件,可是我们只是在搬来使用,不知道它的原理,它是如何被实现的.android系统是开源的,所以谷歌官方 ...

  6. Android之源码之模块编译和调试

    Android之源码之模块编译调试 (一) 进行源码模块修改进行编译的调试 1.首先是从git或者svn上拉一套完整的工程下来,然后全编一下,一般这个时间比较长,大概会得2,3个小时左右, 2,编译成 ...

  7. 关于查看Android系统源码【Written By KillerLegend】

    可能你会想下载Android系统源码,但是我不知道你会看多少系统的源码,如果你对源码只是偶尔看一次的话,推荐你在线看Android的系统源码,下面提供几种查看android系统源码的方法. 1:打开这 ...

  8. 【转】Android 如何在Eclipse中查看Android API源码 及 support包源码

    原文网址:http://blog.csdn.net/vipzjyno1/article/details/22954775 当我们阅读android API开发文档时候,上面的每个类,以及类的各个方法都 ...

  9. 将android Settings 源码 导入到 eclipse工程

    1.  新建 android 项目 拷贝源码/packages/apps/Settings到你的其它目录. 在eclipse中,新建项目,但是要从exitting source选择: 2. 导入相关的 ...

随机推荐

  1. MathExam

    MathExam 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 575 605 • Est ...

  2. NOIP2017提高组day2T1题解(奶酪)

    题目链接:奶酪 这道题还是很水的,在下拿了满分. 并没有用什么高级的算法,我讲一下基本思路. 我们把每个洞都视为一个节点. 我们读入相关数据后,就先进行预处理,通过每个节点的信息和题目的规定,建立一张 ...

  3. LCA(最近公共祖先)模板

    Tarjan版本 /* gyt Live up to every day */ #pragma comment(linker,"/STACK:1024000000,1024000000&qu ...

  4. Quartz(强大的定时器)

    1.关于Quartz的配置文件说明 # # Quartz会优先读取项目下我们自定义这个quartz.properties配置文件 否则会去读取quartzjar包下org.quatrz包# 下面的那个 ...

  5. linux之网络

    一 什么是网络,网络能干什么 网络出现的主要目的就是实现主机和主机之间的通信,而互联网协议(Internet Protocol Suite)就是连接两台计算机之间的internet一系列统一的标准.互 ...

  6. Ubuntu下 QT添加外部链接库(.so文件)示例

    参考:https://blog.csdn.net/KKALL1314/article/details/81915354 https://forum.qt.io/topic/80301/file-not ...

  7. (20)The most mysterious star in the universe

    https://www.ted.com/talks/tabetha_boyajian_the_most_mysterious_star_in_the_universe/transcript00:12E ...

  8. SVN previous operation has not finished

    svn提交遇到恶心的问题,可能是因为上次cleanup中断后,进入死循环了. 错误如下: 解决方法:清空svn的队列 1.下载sqlite3.exe 2.找到你项目的.svn文件,查看是否存在wc.d ...

  9. 通过domoticz restful接口更新数据 c# 控制台程序

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...

  10. Alpha阶段敏捷冲刺(八)

    1.站立式会议 提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 祁泽文:写了关于统计的按钮的代码. 徐璐琳:完善了&q ...