当前位置:   article > 正文

Android studio中国象棋,下棋思路与代码实现_android 中国象棋开发

android 中国象棋开发

(下载资源在文末)


实现中国象棋之类的游戏都会自定义一个View,本次用到SurfaceView,不了解的小伙伴可以自己了解一下。

  1. 象棋的运行思路

执行过程:点击屏幕(屏幕监听) ——>是否到自己走棋(是) ——>判断是否已经选中棋子(是) ——>判断点击位置是否有自己的棋子(是)——>选中该棋子(true)——>再次点击屏幕——>判断位置是否符合下棋规则(点击位置有对方棋子或空位)——>可以移动,改变棋盘(数组)。

  1. 代码实现

实现棋盘所有功能(1、显示棋盘 2、新局、悔棋、设置、返回功能 )

activity_pvm.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:id="@+id/relativeLayout"
  8. android:background="@drawable/background"
  9. tools:context="com.example.a77304.chessgame.PvMActivity">
  10. </RelativeLayout>

button_group.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:layout_alignParentStart="true">
  6. <Button
  7. android:id="@+id/btn_retry"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_toLeftOf="@+id/btn_recall"
  11. android:layout_centerVertical="true"
  12. android:layout_margin="5dp"
  13. android:background="@drawable/selector_btn2"
  14. android:textSize="24dp"
  15. android:text="新局" />
  16. <Button
  17. android:id="@+id/btn_recall"
  18. android:soundEffectsEnabled="false"
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. android:layout_toLeftOf="@+id/btn_null"
  22. android:layout_centerVertical="true"
  23. android:layout_margin="5dp"
  24. android:background="@drawable/selector_btn2"
  25. android:textSize="24dp"
  26. android:text="悔棋" />
  27. <Button
  28. android:id="@+id/btn_null"
  29. android:layout_width="0dp"
  30. android:layout_height="wrap_content"
  31. android:layout_centerInParent="true"
  32. android:text="" />
  33. <Button
  34. android:id="@+id/btn_setting"
  35. android:soundEffectsEnabled="false"
  36. android:layout_width="wrap_content"
  37. android:layout_height="wrap_content"
  38. android:layout_toRightOf="@+id/btn_null"
  39. android:layout_centerVertical="true"
  40. android:layout_margin="5dp"
  41. android:background="@drawable/selector_btn2"
  42. android:textSize="24dp"
  43. android:text="设置" />
  44. <Button
  45. android:id="@+id/btn_back"
  46. android:soundEffectsEnabled="false"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:layout_toRightOf="@+id/btn_setting"
  50. android:layout_centerVertical="true"
  51. android:layout_margin="5dp"
  52. android:background="@drawable/selector_btn2"
  53. android:textSize="24dp"
  54. android:text="返回" />
  55. </RelativeLayout>

PvMActivity.java

  1. import android.content.SharedPreferences;
  2. import android.os.Looper;
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.view.Gravity;
  7. import android.view.KeyEvent;
  8. import android.view.LayoutInflater;
  9. import android.view.MotionEvent;
  10. import android.view.View;
  11. import android.widget.Button;
  12. import android.widget.RelativeLayout;
  13. import android.widget.Toast;
  14. import AICore.AI;
  15. import AICore.KnowledgeBase;
  16. import AICore.Move;
  17. import AICore.TransformTable;
  18. import ChessMove.Rule;
  19. import CustomDialog.CommonDialog;
  20. import CustomDialog.RetryDialog;
  21. import CustomDialog.SettingDialog_PvM;
  22. import CustomView.RoundView;
  23. import Info.ChessInfo;
  24. import Info.InfoSet;
  25. import Info.Pos;
  26. import Info.SaveInfo;
  27. import CustomView.ChessView;
  28. import static AICore.AI.getBestMove;
  29. import static com.example.a77304.chessgame.HomeActivity.MIN_CLICK_DELAY_TIME;
  30. import static com.example.a77304.chessgame.HomeActivity.backMusic;
  31. import static com.example.a77304.chessgame.HomeActivity.checkMusic;
  32. import static com.example.a77304.chessgame.HomeActivity.clickMusic;
  33. import static com.example.a77304.chessgame.HomeActivity.curClickTime;
  34. import static com.example.a77304.chessgame.HomeActivity.lastClickTime;
  35. import static com.example.a77304.chessgame.HomeActivity.playEffect;
  36. import static com.example.a77304.chessgame.HomeActivity.playMusic;
  37. import static com.example.a77304.chessgame.HomeActivity.selectMusic;
  38. import static com.example.a77304.chessgame.HomeActivity.setting;
  39. import static com.example.a77304.chessgame.HomeActivity.sharedPreferences;
  40. import static com.example.a77304.chessgame.HomeActivity.stopMusic;
  41. import static com.example.a77304.chessgame.HomeActivity.winMusic;
  42. public class PvMActivity extends AppCompatActivity implements View.OnTouchListener, View.OnClickListener {
  43. public RelativeLayout relativeLayout;
  44. public ChessInfo chessInfo;
  45. public InfoSet infoSet;
  46. public ChessView chessView; // 自定义的View,用于绘制棋盘、棋子
  47. public RoundView roundView; // 自定义View(显示 红方回合、黑方回合)
  48. public static KnowledgeBase knowledgeBase;
  49. public static TransformTable transformTable;
  50. public Thread AIThread = new Thread(new Runnable() {
  51. @Override
  52. public void run() {
  53. AIMove(chessInfo.IsRedGo, chessInfo.status);
  54. }
  55. });
  56. @Override
  57. protected void onCreate(Bundle savedInstanceState) {
  58. super.onCreate(savedInstanceState);
  59. setContentView(R.layout.activity_pvm);
  60. relativeLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
  61. chessInfo = new ChessInfo();
  62. infoSet = new InfoSet();
  63. transformTable = new TransformTable();
  64. knowledgeBase = new KnowledgeBase();
  65. roundView = new RoundView(this, chessInfo);
  66. //添加View(红方回合、黑方回合)
  67. relativeLayout.addView(roundView);
  68. RelativeLayout.LayoutParams paramsRound = (RelativeLayout.LayoutParams) roundView.getLayoutParams();
  69. paramsRound.addRule(RelativeLayout.CENTER_IN_PARENT);
  70. paramsRound.addRule(RelativeLayout.ALIGN_PARENT_TOP);
  71. paramsRound.setMargins(30, 30, 30, 30);
  72. roundView.setLayoutParams(paramsRound);
  73. roundView.setId(R.id.roundView);
  74. chessView = new ChessView(this, chessInfo);
  75. chessView.setOnTouchListener(this);
  76. //添加View(绘制棋盘、棋子)
  77. relativeLayout.addView(chessView);
  78. RelativeLayout.LayoutParams paramsChess = (RelativeLayout.LayoutParams) chessView.getLayoutParams();
  79. paramsChess.addRule(RelativeLayout.BELOW, R.id.roundView);
  80. chessView.setLayoutParams(paramsChess);
  81. chessView.setId(R.id.chessView);
  82. LayoutInflater inflater = LayoutInflater.from(this);
  83. RelativeLayout buttonGroup = (RelativeLayout) inflater.inflate(R.layout.button_group, relativeLayout, false);
  84. //添加View(新局、悔棋、设置、返回)
  85. relativeLayout.addView(buttonGroup);
  86. RelativeLayout.LayoutParams paramsV = (RelativeLayout.LayoutParams) buttonGroup.getLayoutParams();
  87. paramsV.addRule(RelativeLayout.BELOW, R.id.chessView);
  88. buttonGroup.setLayoutParams(paramsV);
  89. for (int i = 0; i < buttonGroup.getChildCount(); i++) {
  90. Button btn = (Button) buttonGroup.getChildAt(i);
  91. btn.setOnClickListener(this);
  92. }
  93. }
  94. /**
  95. * 屏幕监听
  96. * @param view
  97. * @param event
  98. * @return
  99. */
  100. @Override
  101. public boolean onTouch(View view, MotionEvent event) {
  102. lastClickTime = System.currentTimeMillis();
  103. if (lastClickTime - curClickTime < MIN_CLICK_DELAY_TIME) {
  104. return false;
  105. }
  106. curClickTime = lastClickTime;
  107. if (event.getAction() == MotionEvent.ACTION_DOWN) {
  108. float x = event.getX();
  109. float y = event.getY();
  110. if (chessInfo.status == 1) {
  111. if (x >= 0 && x <= chessView.Board_width && y >= 0 && y <= chessView.Board_height) {
  112. chessInfo.Select = getPos(event);
  113. Pos realPos = Rule.reversePos(new Pos(chessInfo.Select[0], chessInfo.Select[1]), chessInfo.IsReverse);
  114. int i = realPos.x, j = realPos.y;
  115. if (i >= 0 && i <= 8 && j >= 0 && j <= 9) {
  116. if (chessInfo.IsRedGo == true && setting.isPlayerRed == true) {
  117. if (chessInfo.IsChecked == false) {
  118. if (chessInfo.piece[j][i] >= 8 && chessInfo.piece[j][i] <= 14) {
  119. chessInfo.prePos = new Pos(i, j);
  120. chessInfo.IsChecked = true;
  121. chessInfo.ret = Rule.PossibleMoves(chessInfo.piece, i, j, chessInfo.piece[j][i]);
  122. playEffect(selectMusic);
  123. }
  124. } else {
  125. if (chessInfo.piece[j][i] >= 8 && chessInfo.piece[j][i] <= 14) {
  126. chessInfo.prePos = new Pos(i, j);
  127. chessInfo.ret = Rule.PossibleMoves(chessInfo.piece, i, j, chessInfo.piece[j][i]);
  128. playEffect(selectMusic);
  129. } else if (chessInfo.ret.contains(new Pos(i, j))) {
  130. int tmp = chessInfo.piece[j][i];
  131. chessInfo.piece[j][i] = chessInfo.piece[chessInfo.prePos.y][chessInfo.prePos.x];
  132. chessInfo.piece[chessInfo.prePos.y][chessInfo.prePos.x] = 0;
  133. if (Rule.isKingDanger(chessInfo.piece, true)) {
  134. chessInfo.piece[chessInfo.prePos.y][chessInfo.prePos.x] = chessInfo.piece[j][i];
  135. chessInfo.piece[j][i] = tmp;
  136. Toast toast = Toast.makeText(PvMActivity.this, "帅被将军", Toast.LENGTH_SHORT);
  137. toast.setGravity(Gravity.CENTER, 0, 0);
  138. toast.show();
  139. } else {
  140. chessInfo.IsChecked = false;
  141. chessInfo.IsRedGo = false;
  142. chessInfo.curPos = new Pos(i, j);
  143. chessInfo.updateAllInfo(chessInfo.prePos, chessInfo.curPos, chessInfo.piece[j][i], tmp);
  144. try {
  145. infoSet.pushInfo(chessInfo);
  146. } catch (CloneNotSupportedException e) {
  147. e.printStackTrace();
  148. }
  149. playEffect(clickMusic);
  150. int key = 0;
  151. if (Rule.isKingDanger(chessInfo.piece, false)) {
  152. key = 1;
  153. }
  154. if (Rule.isDead(chessInfo.piece, false)) {
  155. key = 2;
  156. }
  157. if (key == 1) {
  158. playEffect(checkMusic);
  159. Toast toast = Toast.makeText(PvMActivity.this, "将军", Toast.LENGTH_SHORT);
  160. toast.setGravity(Gravity.CENTER, 0, 0);
  161. toast.show();
  162. } else if (key == 2) {
  163. playEffect(winMusic);
  164. chessInfo.status = 2;
  165. Toast toast = Toast.makeText(PvMActivity.this, "红方获得胜利", Toast.LENGTH_SHORT);
  166. toast.setGravity(Gravity.CENTER, 0, 0);
  167. toast.show();
  168. }
  169. if (chessInfo.status == 1) {
  170. if (chessInfo.peaceRound >= 60) {
  171. chessInfo.status = 2;
  172. Toast toast = Toast.makeText(PvMActivity.this, "双方60回合内未吃子,此乃和棋", Toast.LENGTH_SHORT);
  173. toast.setGravity(Gravity.CENTER, 0, 0);
  174. toast.show();
  175. } else if (chessInfo.attackNum_B == 0 && chessInfo.attackNum_R == 0) {
  176. chessInfo.status = 2;
  177. Toast toast = Toast.makeText(PvMActivity.this, "双方都无攻击性棋子,此乃和棋", Toast.LENGTH_SHORT);
  178. toast.setGravity(Gravity.CENTER, 0, 0);
  179. toast.show();
  180. } else if (infoSet.ZobristInfo.get(chessInfo.ZobristKeyCheck) >= 4) {
  181. chessInfo.status = 2;
  182. Toast toast = Toast.makeText(PvMActivity.this, "重复局面出现4次,此乃和棋", Toast.LENGTH_SHORT);
  183. toast.setGravity(Gravity.CENTER, 0, 0);
  184. toast.show();
  185. }
  186. }
  187. AIThread = new Thread(new Runnable() {
  188. @Override
  189. public void run() {
  190. try {
  191. Thread.sleep(400);
  192. } catch (InterruptedException e) {
  193. e.printStackTrace();
  194. }
  195. chessInfo.isMachine = true;
  196. AIMove(chessInfo.IsRedGo, chessInfo.status);
  197. }
  198. });
  199. AIThread.start();
  200. }
  201. }
  202. }
  203. } else if (chessInfo.IsRedGo == false && setting.isPlayerRed == false) {
  204. if (chessInfo.IsChecked == false) {
  205. if (chessInfo.piece[j][i] >= 1 && chessInfo.piece[j][i] <= 7) {
  206. chessInfo.prePos = new Pos(i, j);
  207. chessInfo.IsChecked = true;
  208. chessInfo.ret = Rule.PossibleMoves(chessInfo.piece, i, j, chessInfo.piece[j][i]);
  209. playEffect(selectMusic);
  210. }
  211. } else {
  212. if (chessInfo.piece[j][i] >= 1 && chessInfo.piece[j][i] <= 7) {
  213. chessInfo.prePos = new Pos(i, j);
  214. chessInfo.ret = Rule.PossibleMoves(chessInfo.piece, i, j, chessInfo.piece[j][i]);
  215. playEffect(selectMusic);
  216. } else if (chessInfo.ret.contains(new Pos(i, j))) {
  217. int tmp = chessInfo.piece[j][i];
  218. chessInfo.piece[j][i] = chessInfo.piece[chessInfo.prePos.y][chessInfo.prePos.x];
  219. chessInfo.piece[chessInfo.prePos.y][chessInfo.prePos.x] = 0;
  220. if (Rule.isKingDanger(chessInfo.piece, false)) {
  221. chessInfo.piece[chessInfo.prePos.y][chessInfo.prePos.x] = chessInfo.piece[j][i];
  222. chessInfo.piece[j][i] = tmp;
  223. Toast toast = Toast.makeText(PvMActivity.this, "将被将军", Toast.LENGTH_SHORT);
  224. toast.setGravity(Gravity.CENTER, 0, 0);
  225. toast.show();
  226. } else {
  227. chessInfo.IsChecked = false;
  228. chessInfo.IsRedGo = true;
  229. chessInfo.curPos = new Pos(i, j);
  230. chessInfo.updateAllInfo(chessInfo.prePos, chessInfo.curPos, chessInfo.piece[j][i], tmp);
  231. try {
  232. infoSet.pushInfo(chessInfo);
  233. } catch (CloneNotSupportedException e) {
  234. e.printStackTrace();
  235. }
  236. playEffect(clickMusic);
  237. int key = 0;
  238. if (Rule.isKingDanger(chessInfo.piece, true)) {
  239. key = 1;
  240. }
  241. if (Rule.isDead(chessInfo.piece, true)) {
  242. key = 2;
  243. }
  244. if (key == 1) {
  245. playEffect(checkMusic);
  246. Toast toast = Toast.makeText(PvMActivity.this, "将军", Toast.LENGTH_SHORT);
  247. toast.setGravity(Gravity.CENTER, 0, 0);
  248. toast.show();
  249. try {
  250. Thread.sleep(1000);
  251. } catch (InterruptedException e) {
  252. e.printStackTrace();
  253. }
  254. } else if (key == 2) {
  255. playEffect(winMusic);
  256. chessInfo.status = 2;
  257. Toast toast = Toast.makeText(PvMActivity.this, "黑方获得胜利", Toast.LENGTH_SHORT);
  258. toast.setGravity(Gravity.CENTER, 0, 0);
  259. toast.show();
  260. }
  261. if (chessInfo.status == 1) {
  262. if (chessInfo.peaceRound >= 60) {
  263. chessInfo.status = 2;
  264. Toast toast = Toast.makeText(PvMActivity.this, "双方60回合内未吃子,此乃和棋", Toast.LENGTH_SHORT);
  265. toast.setGravity(Gravity.CENTER, 0, 0);
  266. toast.show();
  267. } else if (chessInfo.attackNum_B == 0 && chessInfo.attackNum_R == 0) {
  268. chessInfo.status = 2;
  269. Toast toast = Toast.makeText(PvMActivity.this, "双方都无攻击性棋子,此乃和棋", Toast.LENGTH_SHORT);
  270. toast.setGravity(Gravity.CENTER, 0, 0);
  271. toast.show();
  272. } else if (infoSet.ZobristInfo.get(chessInfo.ZobristKeyCheck) >= 4) {
  273. chessInfo.status = 2;
  274. Toast toast = Toast.makeText(PvMActivity.this, "重复局面出现4次,此乃和棋", Toast.LENGTH_SHORT);
  275. toast.setGravity(Gravity.CENTER, 0, 0);
  276. toast.show();
  277. }
  278. }
  279. AIThread = new Thread(new Runnable() {
  280. @Override
  281. public void run() {
  282. try {
  283. Thread.sleep(400);
  284. } catch (InterruptedException e) {
  285. e.printStackTrace();
  286. }
  287. chessInfo.isMachine = true;
  288. AIMove(chessInfo.IsRedGo, chessInfo.status);
  289. }
  290. });
  291. AIThread.start();
  292. }
  293. }
  294. }
  295. }
  296. }
  297. }
  298. }
  299. }
  300. return false;
  301. }
  302. public int[] getPos(MotionEvent e) {
  303. int[] pos = new int[2];
  304. double x = e.getX();
  305. double y = e.getY();
  306. int[] dis = new int[]{
  307. chessView.Scale(3), chessView.Scale(41), chessView.Scale(80), chessView.Scale(85)
  308. };
  309. x = x - dis[0];
  310. y = y - dis[1];
  311. if (x % dis[3] <= dis[2] && y % dis[3] <= dis[2]) {
  312. pos[0] = (int) Math.floor(x / dis[3]);
  313. pos[1] = (int) Math.floor(y / dis[3]);
  314. if (pos[0] >= 9 || pos[1] >= 10) {
  315. pos[0] = pos[1] = -1;
  316. }
  317. } else {
  318. pos[0] = pos[1] = -1;
  319. }
  320. return pos;
  321. }
  322. @Override
  323. public void onClick(View view) {
  324. lastClickTime = System.currentTimeMillis();
  325. if (lastClickTime - curClickTime < MIN_CLICK_DELAY_TIME) {
  326. return;
  327. }
  328. curClickTime = lastClickTime;
  329. playEffect(selectMusic);
  330. switch (view.getId()) {
  331. case R.id.btn_retry:
  332. if (chessInfo.isMachine == true && chessInfo.status == 1) {
  333. Toast toast = Toast.makeText(PvMActivity.this, "请等待电脑思考", Toast.LENGTH_SHORT);
  334. toast.setGravity(Gravity.CENTER, 0, 0);
  335. toast.show();
  336. break;
  337. }
  338. final RetryDialog retryDialog = new RetryDialog(this);
  339. retryDialog.setOnClickBottomListener(new RetryDialog.OnClickBottomListener() {
  340. @Override
  341. public void onPositiveClick() {
  342. playEffect(selectMusic);
  343. try {
  344. chessInfo.setInfo(new ChessInfo());
  345. infoSet.newInfo();
  346. transformTable.transformInfos.clear();
  347. } catch (CloneNotSupportedException e) {
  348. e.printStackTrace();
  349. }
  350. SharedPreferences.Editor editor = sharedPreferences.edit();
  351. if (setting.isPlayerRed != retryDialog.isPlayerRed) {
  352. setting.isPlayerRed = retryDialog.isPlayerRed;
  353. editor.putBoolean("isPlayerRed", retryDialog.isPlayerRed);
  354. editor.commit();
  355. }
  356. retryDialog.dismiss();
  357. chessInfo.IsReverse = (setting.isPlayerRed == true) ? false : true;
  358. if (chessInfo.IsReverse == true) {
  359. try {
  360. infoSet.curInfo.setInfo(chessInfo);
  361. } catch (CloneNotSupportedException e) {
  362. e.printStackTrace();
  363. }
  364. }
  365. if (setting.isPlayerRed == false) {
  366. try {
  367. Thread.sleep(400);
  368. } catch (InterruptedException e) {
  369. e.printStackTrace();
  370. }
  371. AIFirstGo();
  372. }
  373. }
  374. @Override
  375. public void onNegtiveClick() {
  376. playEffect(selectMusic);
  377. retryDialog.dismiss();
  378. }
  379. });
  380. retryDialog.show();
  381. break;
  382. case R.id.btn_recall:
  383. if (chessInfo.isMachine == true && chessInfo.status == 1) {
  384. Toast toast = Toast.makeText(PvMActivity.this, "请等待电脑思考", Toast.LENGTH_SHORT);
  385. toast.setGravity(Gravity.CENTER, 0, 0);
  386. toast.show();
  387. break;
  388. }
  389. int cnt = 0;
  390. int total = 2;
  391. if (chessInfo.status == 2 && chessInfo.isMachine == true) {
  392. total = 1;
  393. }
  394. if (infoSet.preInfo.size() < total) {
  395. break;
  396. }
  397. while (!infoSet.preInfo.empty()) {
  398. ChessInfo tmp = infoSet.preInfo.pop();
  399. cnt++;
  400. try {
  401. infoSet.recallZobristInfo(chessInfo.ZobristKeyCheck);
  402. chessInfo.setInfo(tmp);
  403. infoSet.curInfo.setInfo(tmp);
  404. } catch (CloneNotSupportedException e) {
  405. e.printStackTrace();
  406. }
  407. if (cnt >= total) {
  408. break;
  409. }
  410. }
  411. break;
  412. case R.id.btn_setting:
  413. final SettingDialog_PvM settingDialog_pvm = new SettingDialog_PvM(this);
  414. settingDialog_pvm.setOnClickBottomListener(new SettingDialog_PvM.OnClickBottomListener() {
  415. @Override
  416. public void onPositiveClick() {
  417. playEffect(selectMusic);
  418. SharedPreferences.Editor editor = sharedPreferences.edit();
  419. boolean flag = false;
  420. if (setting.isMusicPlay != settingDialog_pvm.isMusicPlay) {
  421. setting.isMusicPlay = settingDialog_pvm.isMusicPlay;
  422. if (setting.isMusicPlay) {
  423. playMusic(backMusic);
  424. } else {
  425. stopMusic(backMusic);
  426. }
  427. editor.putBoolean("isMusicPlay", settingDialog_pvm.isMusicPlay);
  428. flag = true;
  429. }
  430. if (setting.isEffectPlay != settingDialog_pvm.isEffectPlay) {
  431. setting.isEffectPlay = settingDialog_pvm.isEffectPlay;
  432. editor.putBoolean("isEffectPlay", settingDialog_pvm.isEffectPlay);
  433. flag = true;
  434. }
  435. if (setting.mLevel != settingDialog_pvm.mLevel) {
  436. setting.mLevel = settingDialog_pvm.mLevel;
  437. editor.putInt("mLevel", settingDialog_pvm.mLevel);
  438. flag = true;
  439. }
  440. if (flag) {
  441. editor.commit();
  442. }
  443. settingDialog_pvm.dismiss();
  444. }
  445. @Override
  446. public void onNegtiveClick() {
  447. playEffect(selectMusic);
  448. settingDialog_pvm.dismiss();
  449. }
  450. });
  451. settingDialog_pvm.show();
  452. break;
  453. case R.id.btn_back:
  454. final CommonDialog backDialog = new CommonDialog(this, "返回", "确认要返回吗");
  455. backDialog.setOnClickBottomListener(new CommonDialog.OnClickBottomListener() {
  456. @Override
  457. public void onPositiveClick() {
  458. playEffect(selectMusic);
  459. backDialog.dismiss();
  460. finish();
  461. }
  462. @Override
  463. public void onNegtiveClick() {
  464. playEffect(selectMusic);
  465. backDialog.dismiss();
  466. }
  467. });
  468. backDialog.show();
  469. break;
  470. default:
  471. break;
  472. }
  473. }
  474. public void AIMove(boolean isRed, int status) {
  475. if (status != 1) return;
  476. int depth = setting.mLevel * 2;
  477. if (isRed == true) {
  478. // AI获取最佳走法
  479. Move move = knowledgeBase.readBestMoves(chessInfo.ZobristKey, chessInfo.ZobristKeyCheck, depth);
  480. if (move == null) {
  481. long t1 = System.currentTimeMillis();
  482. move = getBestMove(chessInfo.piece, true, depth, chessInfo.ZobristKey, chessInfo.ZobristKeyCheck, infoSet.ZobristInfo);
  483. long t2 = System.currentTimeMillis();
  484. Log.i("AI思考", "AI思考的时间:" + String.valueOf(t2 - t1) + "ms");
  485. knowledgeBase.saveBestMove(chessInfo.ZobristKey, chessInfo.ZobristKeyCheck, depth, move);
  486. }
  487. Pos fromPos = move.fromPos;
  488. Pos toPos = move.toPos;
  489. int tmp = chessInfo.piece[toPos.y][toPos.x];
  490. chessInfo.piece[toPos.y][toPos.x] = chessInfo.piece[fromPos.y][fromPos.x];
  491. chessInfo.piece[fromPos.y][fromPos.x] = 0;
  492. chessInfo.IsChecked = false;
  493. chessInfo.IsRedGo = false;
  494. chessInfo.Select = new int[]{-1, -1};
  495. chessInfo.ret.clear();
  496. chessInfo.prePos = new Pos(fromPos.x, fromPos.y);
  497. chessInfo.curPos = new Pos(toPos.x, toPos.y);
  498. chessInfo.updateAllInfo(chessInfo.prePos, chessInfo.curPos, chessInfo.piece[toPos.y][toPos.x], tmp);
  499. chessInfo.isMachine = false;
  500. try {
  501. infoSet.pushInfo(chessInfo);
  502. } catch (CloneNotSupportedException e) {
  503. e.printStackTrace();
  504. }
  505. playEffect(clickMusic);
  506. int key = 0;
  507. if (Rule.isKingDanger(chessInfo.piece, false)) {
  508. key = 1;
  509. }
  510. if (Rule.isDead(chessInfo.piece, false)) {
  511. key = 2;
  512. }
  513. if (key == 1) {
  514. playEffect(checkMusic);
  515. Looper.prepare();
  516. Toast toast = Toast.makeText(PvMActivity.this, "将军", Toast.LENGTH_SHORT);
  517. toast.setGravity(Gravity.CENTER, 0, 0);
  518. toast.show();
  519. Looper.loop();
  520. } else if (key == 2) {
  521. playEffect(winMusic);
  522. chessInfo.status = 2;
  523. Looper.prepare();
  524. Toast toast = Toast.makeText(PvMActivity.this, "红方获得胜利", Toast.LENGTH_SHORT);
  525. toast.setGravity(Gravity.CENTER, 0, 0);
  526. toast.show();
  527. Looper.loop();
  528. }
  529. if (chessInfo.status == 1) {
  530. if (chessInfo.peaceRound >= 60) {
  531. chessInfo.status = 2;
  532. Looper.prepare();
  533. Toast toast = Toast.makeText(PvMActivity.this, "双方60回合内未吃子,此乃和棋", Toast.LENGTH_SHORT);
  534. toast.setGravity(Gravity.CENTER, 0, 0);
  535. toast.show();
  536. Looper.loop();
  537. } else if (chessInfo.attackNum_B == 0 && chessInfo.attackNum_R == 0) {
  538. chessInfo.status = 2;
  539. Looper.prepare();
  540. Toast toast = Toast.makeText(PvMActivity.this, "双方都无攻击性棋子,此乃和棋", Toast.LENGTH_SHORT);
  541. toast.setGravity(Gravity.CENTER, 0, 0);
  542. toast.show();
  543. Looper.loop();
  544. } else if (infoSet.ZobristInfo.get(chessInfo.ZobristKeyCheck) >= 4) {
  545. chessInfo.status = 2;
  546. Looper.prepare();
  547. Toast toast = Toast.makeText(PvMActivity.this, "重复局面出现4次,此乃和棋", Toast.LENGTH_SHORT);
  548. toast.setGravity(Gravity.CENTER, 0, 0);
  549. toast.show();
  550. Looper.loop();
  551. }
  552. }
  553. } else {
  554. Move move = knowledgeBase.readBestMoves(chessInfo.ZobristKey, chessInfo.ZobristKeyCheck, depth);
  555. if (move == null) {
  556. long t1 = System.currentTimeMillis();
  557. move = getBestMove(chessInfo.piece, false, depth, chessInfo.ZobristKey, chessInfo.ZobristKeyCheck, infoSet.ZobristInfo);
  558. long t2 = System.currentTimeMillis();
  559. Log.i("AI思考", "AI思考的时间:" + String.valueOf(t2 - t1) + "ms");
  560. knowledgeBase.saveBestMove(chessInfo.ZobristKey, chessInfo.ZobristKeyCheck, depth, move);
  561. }
  562. Pos fromPos = move.fromPos;
  563. Pos toPos = move.toPos;
  564. int tmp = chessInfo.piece[toPos.y][toPos.x];
  565. chessInfo.piece[toPos.y][toPos.x] = chessInfo.piece[fromPos.y][fromPos.x];
  566. chessInfo.piece[fromPos.y][fromPos.x] = 0;
  567. chessInfo.IsChecked = false;
  568. chessInfo.IsRedGo = true;
  569. chessInfo.Select = new int[]{-1, -1};
  570. chessInfo.ret.clear();
  571. chessInfo.prePos = new Pos(fromPos.x, fromPos.y);
  572. chessInfo.curPos = new Pos(toPos.x, toPos.y);
  573. chessInfo.updateAllInfo(chessInfo.prePos, chessInfo.curPos, chessInfo.piece[toPos.y][toPos.x], tmp);
  574. chessInfo.isMachine = false;
  575. try {
  576. infoSet.pushInfo(chessInfo);
  577. } catch (CloneNotSupportedException e) {
  578. e.printStackTrace();
  579. }
  580. playEffect(clickMusic);
  581. int key = 0;
  582. if (Rule.isKingDanger(chessInfo.piece, true)) {
  583. key = 1;
  584. }
  585. if (Rule.isDead(chessInfo.piece, true)) {
  586. key = 2;
  587. }
  588. if (key == 1) {
  589. playEffect(checkMusic);
  590. Looper.prepare();
  591. Toast toast = Toast.makeText(PvMActivity.this, "将军", Toast.LENGTH_SHORT);
  592. toast.setGravity(Gravity.CENTER, 0, 0);
  593. toast.show();
  594. Looper.loop();
  595. } else if (key == 2) {
  596. playEffect(winMusic);
  597. chessInfo.status = 2;
  598. Looper.prepare();
  599. Toast toast = Toast.makeText(PvMActivity.this, "黑方获得胜利", Toast.LENGTH_SHORT);
  600. toast.setGravity(Gravity.CENTER, 0, 0);
  601. toast.show();
  602. Looper.loop();
  603. }
  604. if (chessInfo.status == 1) {
  605. if (chessInfo.peaceRound >= 60) {
  606. chessInfo.status = 2;
  607. Looper.prepare();
  608. Toast toast = Toast.makeText(PvMActivity.this, "双方60回合内未吃子,此乃和棋", Toast.LENGTH_SHORT);
  609. toast.setGravity(Gravity.CENTER, 0, 0);
  610. toast.show();
  611. Looper.loop();
  612. } else if (chessInfo.attackNum_B == 0 && chessInfo.attackNum_R == 0) {
  613. chessInfo.status = 2;
  614. Looper.prepare();
  615. Toast toast = Toast.makeText(PvMActivity.this, "双方都无攻击性棋子,此乃和棋", Toast.LENGTH_SHORT);
  616. toast.setGravity(Gravity.CENTER, 0, 0);
  617. toast.show();
  618. Looper.loop();
  619. } else if (infoSet.ZobristInfo.get(chessInfo.ZobristKeyCheck) >= 4) {
  620. chessInfo.status = 2;
  621. Looper.prepare();
  622. Toast toast = Toast.makeText(PvMActivity.this, "重复局面出现4次,此乃和棋", Toast.LENGTH_SHORT);
  623. toast.setGravity(Gravity.CENTER, 0, 0);
  624. toast.show();
  625. Looper.loop();
  626. }
  627. }
  628. }
  629. }
  630. public void AIFirstGo() {
  631. Move[] firstMoves = new Move[8];
  632. firstMoves[0] = new Move(new Pos(1, 9), new Pos(2, 7)); //走马
  633. firstMoves[1] = new Move(new Pos(7, 9), new Pos(6, 7)); //走马
  634. firstMoves[2] = new Move(new Pos(2, 9), new Pos(4, 7)); //走相
  635. firstMoves[3] = new Move(new Pos(6, 9), new Pos(4, 7)); //走相
  636. firstMoves[4] = new Move(new Pos(1, 7), new Pos(4, 7)); //走炮
  637. firstMoves[5] = new Move(new Pos(7, 7), new Pos(4, 7)); //走炮
  638. firstMoves[6] = new Move(new Pos(2, 6), new Pos(2, 5)); //走兵
  639. firstMoves[7] = new Move(new Pos(6, 6), new Pos(6, 5)); //走兵
  640. int num = (int) (Math.random() * firstMoves.length);
  641. //Log.e("chen",String.valueOf(num));
  642. Move firstMove = firstMoves[num];
  643. Pos fromPos = firstMove.fromPos;
  644. Pos toPos = firstMove.toPos;
  645. int tmp = chessInfo.piece[toPos.y][toPos.x];
  646. chessInfo.piece[toPos.y][toPos.x] = chessInfo.piece[fromPos.y][fromPos.x];
  647. chessInfo.piece[fromPos.y][fromPos.x] = 0;
  648. chessInfo.IsChecked = false;
  649. chessInfo.IsRedGo = false;
  650. chessInfo.Select = new int[]{-1, -1};
  651. chessInfo.ret.clear();
  652. chessInfo.prePos = new Pos(fromPos.x, fromPos.y);
  653. chessInfo.curPos = new Pos(toPos.x, toPos.y);
  654. chessInfo.updateAllInfo(chessInfo.prePos, chessInfo.curPos, chessInfo.piece[toPos.y][toPos.x], tmp);
  655. try {
  656. infoSet.pushInfo(chessInfo);
  657. } catch (CloneNotSupportedException e) {
  658. e.printStackTrace();
  659. }
  660. playEffect(clickMusic);
  661. }
  662. @Override
  663. public boolean onKeyDown(int keyCode, KeyEvent event) {
  664. if (keyCode == KeyEvent.KEYCODE_BACK) {
  665. final CommonDialog backDialog = new CommonDialog(this, "返回", "确认要返回吗");
  666. backDialog.setOnClickBottomListener(new CommonDialog.OnClickBottomListener() {
  667. @Override
  668. public void onPositiveClick() {
  669. playEffect(selectMusic);
  670. backDialog.dismiss();
  671. finish();
  672. }
  673. @Override
  674. public void onNegtiveClick() {
  675. playEffect(selectMusic);
  676. backDialog.dismiss();
  677. }
  678. });
  679. backDialog.show();
  680. return true;
  681. }
  682. return super.onKeyDown(keyCode, event);
  683. }
  684. @Override
  685. protected void onPause() {
  686. stopMusic(backMusic);
  687. super.onPause();
  688. }
  689. @Override
  690. protected void onStop() {
  691. /* try {
  692. SaveInfo.SerializeChessInfo(chessInfo, "ChessInfo_pvm.bin");
  693. SaveInfo.SerializeInfoSet(infoSet, "InfoSet_pvm.bin");
  694. SaveInfo.SerializeKnowledgeBase(knowledgeBase, "KnowledgeBase.bin");
  695. SaveInfo.SerializeTransformTable(transformTable, "TransformTable.bin");
  696. } catch (Exception e) {
  697. Log.e("chen", e.toString());
  698. }*/
  699. super.onStop();
  700. }
  701. @Override
  702. protected void onStart() {
  703. playMusic(backMusic);
  704. if (chessInfo.isMachine) {
  705. if (AIThread.isAlive() == false) {
  706. AIThread = new Thread(new Runnable() {
  707. @Override
  708. public void run() {
  709. AIMove(chessInfo.IsRedGo, chessInfo.status);
  710. }
  711. });
  712. AIThread.start();
  713. }
  714. }
  715. super.onStart();
  716. }
  717. }

规则类 Rule.java

  1. import android.util.Log;
  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. import java.util.List;
  5. import Info.Pos;
  6. public class Rule {
  7. public static int[][] area = new int[][]{
  8. {1, 1, 1, 2, 2, 2, 1, 1, 1},
  9. {1, 1, 1, 2, 2, 2, 1, 1, 1},
  10. {1, 1, 1, 2, 2, 2, 1, 1, 1},
  11. {1, 1, 1, 1, 1, 1, 1, 1, 1},
  12. {1, 1, 1, 1, 1, 1, 1, 1, 1},
  13. {3, 3, 3, 3, 3, 3, 3, 3, 3},
  14. {3, 3, 3, 3, 3, 3, 3, 3, 3},
  15. {3, 3, 3, 4, 4, 4, 3, 3, 3},
  16. {3, 3, 3, 4, 4, 4, 3, 3, 3},
  17. {3, 3, 3, 4, 4, 4, 3, 3, 3},
  18. };
  19. //走棋规则
  20. public static int[][] offsetX = new int[][]{
  21. {0, 0, 1, -1}, //帅 将
  22. {1, 1, -1, -1}, //仕 士
  23. {2, 2, -2, -2}, //相 象
  24. {1, 1, -1, -1}, //象眼
  25. {1, 1, -1, -1, 2, 2, -2, -2}, //马
  26. {0, 0, 0, 0, 1, 1, -1, -1}, //蹩马腿
  27. {0}, //卒
  28. {-1, 0, 1}, //过河卒
  29. {0}, //兵
  30. {-1, 0, 1}, //过河兵
  31. {1, 1, -1, -1, 1, 1, -1, -1}, //反向蹩马腿
  32. };
  33. public static int[][] offsetY = new int[][]{
  34. {1, -1, 0, 0}, //帅 将
  35. {1, -1, 1, -1}, //仕 士
  36. {2, -2, 2, -2}, //相 象
  37. {1, -1, 1, -1}, //象眼
  38. {2, -2, 2, -2, 1, -1, 1, -1}, //马
  39. {1, -1, 1, -1, 0, 0, 0, 0}, //蹩马腿
  40. {1}, //卒
  41. {0, 1, 0}, //过河卒
  42. {-1}, //兵
  43. {0, -1, 0}, //过河兵
  44. {1, -1, 1, -1, 1, -1, 1, -1}, //反向蹩马腿
  45. };
  46. //生成某个位置的棋子的所有可能走法的位置
  47. public static List<Pos> PossibleMoves(int[][] piece, int fromX, int fromY, int PieceID) {
  48. List<Pos> ret = new ArrayList<Pos>();
  49. int num;
  50. switch (PieceID) {
  51. case 1://黑将
  52. num = 0;
  53. for (int i = 0; i < offsetX[num].length; i++) {
  54. int toX = fromX + offsetX[num][i];
  55. int toY = fromY + offsetY[num][i];
  56. if (InArea(toX, toY) == 2 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  57. ret.add(new Pos(toX, toY));
  58. }
  59. }
  60. Pos eatPos1 = flyKing(1, fromX, fromY, piece);
  61. if (eatPos1.equals(new Pos(-1, -1)) == false) {
  62. ret.add(eatPos1);
  63. }
  64. break;
  65. case 2://黑士
  66. num = 1;
  67. for (int i = 0; i < offsetX[num].length; i++) {
  68. int toX = fromX + offsetX[num][i];
  69. int toY = fromY + offsetY[num][i];
  70. if (InArea(toX, toY) == 2 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  71. ret.add(new Pos(toX, toY));
  72. }
  73. }
  74. break;
  75. case 3://黑象
  76. num = 2;
  77. for (int i = 0; i < offsetX[num].length; i++) {
  78. int toX = fromX + offsetX[num][i];
  79. int toY = fromY + offsetY[num][i];
  80. int blockX = fromX + offsetX[num + 1][i];
  81. int blockY = fromY + offsetY[num + 1][i];
  82. if (InArea(toX, toY) >= 1 && InArea(toX, toY) <= 2 && IsSameSide(PieceID, piece[toY][toX]) == false && piece[blockY][blockX] == 0) {
  83. ret.add(new Pos(toX, toY));
  84. }
  85. }
  86. break;
  87. case 4://黑马
  88. case 11://红马
  89. num = 4;
  90. for (int i = 0; i < offsetX[num].length; i++) {
  91. int toX = fromX + offsetX[num][i];
  92. int toY = fromY + offsetY[num][i];
  93. int blockX = fromX + offsetX[num + 1][i];
  94. int blockY = fromY + offsetY[num + 1][i];
  95. if (InArea(toX, toY) != 0 && IsSameSide(PieceID, piece[toY][toX]) == false && piece[blockY][blockX] == 0) {
  96. ret.add(new Pos(toX, toY));
  97. }
  98. }
  99. break;
  100. case 5://黑车
  101. case 12: //红车
  102. for (int i = fromY + 1; i < 10; i++) {//向下走
  103. if (CanMove(1, fromX, fromY, fromX, i, piece)) { //可以走时
  104. ret.add(new Pos(fromX, i));
  105. } else {//不可以走时直接 break
  106. break;
  107. }
  108. }
  109. for (int i = fromY - 1; i > -1; i--) {//向上走
  110. if (CanMove(1, fromX, fromY, fromX, i, piece)) {//可以走时
  111. ret.add(new Pos(fromX, i));
  112. } else {//不可以走时
  113. break;
  114. }
  115. }
  116. for (int j = fromX - 1; j > -1; j--) {//向走走
  117. if (CanMove(1, fromX, fromY, j, fromY, piece)) {//可以走时
  118. ret.add(new Pos(j, fromY));
  119. } else {//不可以走时
  120. break;
  121. }
  122. }
  123. for (int j = fromX + 1; j < 9; j++) {//向右走
  124. if (CanMove(1, fromX, fromY, j, fromY, piece)) {//可以走时
  125. ret.add(new Pos(j, fromY));
  126. } else {//不可以走时
  127. break;
  128. }
  129. }
  130. /*for (int i = 0; i < 9; i++) {
  131. for (int j = 0; j < 10; j++) {
  132. if (i != fromX || j != fromY) {
  133. if (CanMove(1, fromX, fromY, i, j, piece)) {
  134. ret.add(new Pos(i, j));
  135. }
  136. }
  137. }
  138. }*/
  139. break;
  140. case 6://黑炮
  141. case 13://红炮
  142. for (int i = fromY + 1; i < 10; i++) {//向下走
  143. if (CanMove(2, fromX, fromY, fromX, i, piece)) { //可以走时
  144. ret.add(new Pos(fromX, i));
  145. }
  146. }
  147. for (int i = fromY - 1; i > -1; i--) {//向上走
  148. if (CanMove(2, fromX, fromY, fromX, i, piece)) {//可以走时
  149. ret.add(new Pos(fromX, i));
  150. }
  151. }
  152. for (int j = fromX - 1; j > -1; j--) {//向走走
  153. if (CanMove(2, fromX, fromY, j, fromY, piece)) {//可以走时
  154. ret.add(new Pos(j, fromY));
  155. }
  156. }
  157. for (int j = fromX + 1; j < 9; j++) {//向右走
  158. if (CanMove(2, fromX, fromY, j, fromY, piece)) {//可以走时
  159. ret.add(new Pos(j, fromY));
  160. }
  161. }
  162. /*for (int i = 0; i < 9; i++) {
  163. for (int j = 0; j < 10; j++) {
  164. if (i != fromX || j != fromY) {
  165. if (CanMove(2, fromX, fromY, i, j, piece)) {
  166. ret.add(new Pos(i, j));
  167. }
  168. }
  169. }
  170. }*/
  171. break;
  172. case 7://黑卒
  173. if (InArea(fromX, fromY) == 1) {
  174. num = 6;
  175. for (int i = 0; i < offsetX[num].length; i++) {
  176. int toX = fromX + offsetX[num][i];
  177. int toY = fromY + offsetY[num][i];
  178. if (InArea(toX, toY) != 0 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  179. ret.add(new Pos(toX, toY));
  180. }
  181. }
  182. } else {
  183. num = 7;
  184. for (int i = 0; i < offsetX[num].length; i++) {
  185. int toX = fromX + offsetX[num][i];
  186. int toY = fromY + offsetY[num][i];
  187. if (InArea(toX, toY) != 0 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  188. ret.add(new Pos(toX, toY));
  189. }
  190. }
  191. }
  192. break;
  193. case 8://红帅
  194. num = 0;
  195. for (int i = 0; i < offsetX[num].length; i++) {
  196. int toX = fromX + offsetX[num][i];
  197. int toY = fromY + offsetY[num][i];
  198. if (InArea(toX, toY) == 4 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  199. ret.add(new Pos(toX, toY));
  200. }
  201. }
  202. Pos eatPos2 = flyKing(2, fromX, fromY, piece);
  203. if (eatPos2.equals(new Pos(-1, -1)) == false) {
  204. ret.add(eatPos2);
  205. }
  206. break;
  207. case 9://红士
  208. num = 1;
  209. for (int i = 0; i < offsetX[num].length; i++) {
  210. int toX = fromX + offsetX[num][i];
  211. int toY = fromY + offsetY[num][i];
  212. if (InArea(toX, toY) == 4 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  213. ret.add(new Pos(toX, toY));
  214. }
  215. }
  216. break;
  217. case 10://红象
  218. num = 2;
  219. for (int i = 0; i < offsetX[num].length; i++) {
  220. int toX = fromX + offsetX[num][i];
  221. int toY = fromY + offsetY[num][i];
  222. int blockX = fromX + offsetX[num + 1][i];
  223. int blockY = fromY + offsetY[num + 1][i];
  224. if (InArea(toX, toY) >= 3 && InArea(toX, toY) <= 4 && IsSameSide(PieceID, piece[toY][toX]) == false && piece[blockY][blockX] == 0) {
  225. ret.add(new Pos(toX, toY));
  226. }
  227. }
  228. break;
  229. case 14://红兵
  230. if (InArea(fromX, fromY) == 3) {
  231. num = 8;
  232. for (int i = 0; i < offsetX[num].length; i++) {
  233. int toX = fromX + offsetX[num][i];
  234. int toY = fromY + offsetY[num][i];
  235. if (InArea(toX, toY) != 0 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  236. ret.add(new Pos(toX, toY));
  237. }
  238. }
  239. } else {
  240. num = 9;
  241. for (int i = 0; i < offsetX[num].length; i++) {
  242. int toX = fromX + offsetX[num][i];
  243. int toY = fromY + offsetY[num][i];
  244. if (InArea(toX, toY) != 0 && IsSameSide(PieceID, piece[toY][toX]) == false) {
  245. ret.add(new Pos(toX, toY));
  246. }
  247. }
  248. }
  249. break;
  250. default:
  251. break;
  252. }
  253. return ret;
  254. }
  255. //判断将、帅是否已经被将军
  256. public static boolean isKingDanger(int[][] piece, boolean isRedKing) {
  257. int num = 4;
  258. int op_block_num = 10;
  259. if (isRedKing == true) {
  260. int x = 0, y = 0;
  261. boolean flag = false;
  262. for (y = 7; y <= 9; y++) {
  263. for (x = 3; x <= 5; x++) {
  264. if (piece[y][x] == 8) {
  265. flag = true;
  266. break;
  267. }
  268. }
  269. if (flag) break;
  270. }
  271. for (int i = 0; i < offsetX[num].length; i++) { //马
  272. int toX = x + offsetX[num][i];
  273. int toY = y + offsetY[num][i];
  274. int blockX = x + offsetX[op_block_num][i];
  275. int blockY = y + offsetY[op_block_num][i];
  276. if (InArea(toX, toY) != 0 && piece[toY][toX] == 4 && piece[blockY][blockX] == 0) {
  277. return true;
  278. }
  279. }
  280. for (int i = 5; i <= 6; i++) { //车 炮
  281. List<Pos> moves = PossibleMoves(piece, x, y, i + 7);
  282. Iterator<Pos> it = moves.iterator();
  283. while (it.hasNext()) {
  284. Pos pos = it.next();
  285. if (piece[pos.y][pos.x] == i) {
  286. return true;
  287. }
  288. }
  289. }
  290. if (flyKing(2, x, y, piece).equals(new Pos(-1, -1)) == false) { //将
  291. return true;
  292. }
  293. if (piece[y - 1][x] == 7 || piece[y][x - 1] == 7 || piece[y][x + 1] == 7) {
  294. return true;
  295. }
  296. } else {
  297. int x = 0, y = 0;
  298. boolean flag = false;
  299. for (y = 0; y <= 2; y++) {
  300. for (x = 3; x <= 5; x++) {
  301. if (piece[y][x] == 1) {
  302. flag = true;
  303. break;
  304. }
  305. }
  306. if (flag) break;
  307. }
  308. for (int i = 0; i < offsetX[num].length; i++) { //马
  309. int toX = x + offsetX[num][i];
  310. int toY = y + offsetY[num][i];
  311. int blockX = x + offsetX[op_block_num][i];
  312. int blockY = y + offsetY[op_block_num][i];
  313. if (InArea(toX, toY) != 0 && piece[toY][toX] == 11 && piece[blockY][blockX] == 0) {
  314. return true;
  315. }
  316. }
  317. for (int i = 12; i <= 13; i++) { //车 炮
  318. List<Pos> moves = PossibleMoves(piece, x, y, i - 7);
  319. Iterator<Pos> it = moves.iterator();
  320. while (it.hasNext()) {
  321. Pos pos = it.next();
  322. if (piece[pos.y][pos.x] == i) {
  323. return true;
  324. }
  325. }
  326. }
  327. if (flyKing(1, x, y, piece).equals(new Pos(-1, -1)) == false) { //将
  328. return true;
  329. }
  330. if (piece[y + 1][x] == 14 || piece[y][x - 1] == 14 || piece[y][x + 1] == 14) {
  331. return true;
  332. }
  333. }
  334. return false;
  335. }
  336. //判断将、帅是否已经被将军
  337. public static boolean isDead(int[][] piece, boolean isRedKing) {
  338. if (isRedKing == true) {
  339. for (int i = 0; i <= 9; i++) {
  340. for (int j = 0; j <= 8; j++) {
  341. if (piece[i][j] >= 8 && piece[i][j] <= 14) {
  342. List<Pos> moves = PossibleMoves(piece, j, i, piece[i][j]);
  343. Iterator<Pos> it = moves.iterator();
  344. while (it.hasNext()) {
  345. Pos pos = it.next();
  346. int tmp = piece[pos.y][pos.x];
  347. if (tmp == 1) {
  348. return false;
  349. }
  350. piece[pos.y][pos.x] = piece[i][j];
  351. piece[i][j] = 0;
  352. if (isKingDanger(piece, true) == false) {
  353. piece[i][j] = piece[pos.y][pos.x];
  354. piece[pos.y][pos.x] = tmp;
  355. return false;
  356. }
  357. piece[i][j] = piece[pos.y][pos.x];
  358. piece[pos.y][pos.x] = tmp;
  359. }
  360. }
  361. }
  362. }
  363. } else {
  364. for (int i = 0; i <= 9; i++) {
  365. for (int j = 0; j <= 8; j++) {
  366. if (piece[i][j] >= 1 && piece[i][j] <= 7) {
  367. List<Pos> moves = PossibleMoves(piece, j, i, piece[i][j]);
  368. Iterator<Pos> it = moves.iterator();
  369. while (it.hasNext()) {
  370. Pos pos = it.next();
  371. int tmp = piece[pos.y][pos.x];
  372. if (tmp == 8) {
  373. return false;
  374. }
  375. piece[pos.y][pos.x] = piece[i][j];
  376. piece[i][j] = 0;
  377. if (isKingDanger(piece, false) == false) {
  378. piece[i][j] = piece[pos.y][pos.x];
  379. piece[pos.y][pos.x] = tmp;
  380. return false;
  381. }
  382. piece[i][j] = piece[pos.y][pos.x];
  383. piece[pos.y][pos.x] = tmp;
  384. }
  385. }
  386. }
  387. }
  388. }
  389. return true;
  390. }
  391. //0 棋盘外 1 黑盘 2 黑十字(九宫) 3 红盘 4 红十字(九宫)
  392. public static int InArea(int x, int y) {
  393. if (x < 0 || x > 8 || y < 0 || y > 9) {
  394. return 0;
  395. }
  396. return area[y][x];
  397. }
  398. //判断棋子是否为同一方
  399. public static boolean IsSameSide(int fromID, int toID) {
  400. if (toID == 0) {
  401. return false;
  402. }
  403. if ((fromID <= 7 && toID <= 7) || (fromID >= 8 && toID >= 8)) {
  404. return true;
  405. } else {
  406. return false;
  407. }
  408. }
  409. //判断将、帅是否见面
  410. public static Pos flyKing(int id, int fromX, int fromY, int[][] piece) {
  411. int cnt = 0;
  412. boolean flag = false;
  413. int i;
  414. if (id == 1) { //将
  415. for (i = fromY + 1; i <= 9; i++) {
  416. if (piece[i][fromX] > 0 && piece[i][fromX] != 8) {
  417. cnt++;
  418. } else if (piece[i][fromX] == 8) {
  419. flag = true;
  420. break;
  421. }
  422. }
  423. } else { //帅
  424. for (i = fromY - 1; i >= 0; i--) {
  425. if (piece[i][fromX] > 0 && piece[i][fromX] != 1) {
  426. cnt++;
  427. } else if (piece[i][fromX] == 1) {
  428. flag = true;
  429. break;
  430. }
  431. }
  432. }
  433. if (cnt == 0 && flag == true) {
  434. return new Pos(fromX, i);
  435. } else {
  436. return new Pos(-1, -1);
  437. }
  438. }
  439. //判断是否可以移动
  440. public static boolean CanMove(int id, int fromX, int fromY, int toX, int toY, int[][] piece) {
  441. if (fromX == 10 || fromY == 10 || toX == 10 || toY == 10) {
  442. Log.e("chen", String.valueOf(fromX) + " " + String.valueOf(fromY) + " " + String.valueOf(toX) + " " + String.valueOf(toY));
  443. }
  444. if ((fromX != toX && fromY != toY) || IsSameSide(piece[fromY][fromX], piece[toY][toX]) == true) {
  445. return false;
  446. }
  447. if (id == 1) { //车
  448. int start, finish;
  449. if (fromX == toX) {
  450. if (fromY < toY) {
  451. start = fromY + 1;
  452. finish = toY;
  453. } else {
  454. start = toY + 1;
  455. finish = fromY;
  456. }
  457. for (int i = start; i < finish; i++) {
  458. if (piece[i][fromX] != 0) {
  459. return false;
  460. }
  461. }
  462. } else {
  463. if (fromX < toX) {
  464. start = fromX + 1;
  465. finish = toX;
  466. } else {
  467. start = toX + 1;
  468. finish = fromX;
  469. }
  470. for (int i = start; i < finish; i++) {
  471. if (piece[fromY][i] != 0) {
  472. return false;
  473. }
  474. }
  475. }
  476. } else { //炮
  477. if (piece[toY][toX] == 0) {
  478. int start, finish;
  479. if (fromX == toX) {
  480. if (fromY < toY) {
  481. start = fromY + 1;
  482. finish = toY;
  483. } else {
  484. start = toY + 1;
  485. finish = fromY;
  486. }
  487. for (int i = start; i < finish; i++) {
  488. if (piece[i][fromX] != 0) {
  489. return false;
  490. }
  491. }
  492. } else {
  493. if (fromX < toX) {
  494. start = fromX + 1;
  495. finish = toX;
  496. } else {
  497. start = toX + 1;
  498. finish = fromX;
  499. }
  500. for (int i = start; i < finish; i++) {
  501. if (piece[fromY][i] != 0) {
  502. return false;
  503. }
  504. }
  505. }
  506. } else {
  507. int start, finish;
  508. int count = 0;
  509. if (fromX == toX) {
  510. if (fromY < toY) {
  511. start = fromY + 1;
  512. finish = toY;
  513. } else {
  514. start = toY + 1;
  515. finish = fromY;
  516. }
  517. for (int i = start; i < finish; i++) {
  518. if (piece[i][fromX] != 0) {
  519. count++;
  520. }
  521. }
  522. } else {
  523. if (fromX < toX) {
  524. start = fromX + 1;
  525. finish = toX;
  526. } else {
  527. start = toX + 1;
  528. finish = fromX;
  529. }
  530. for (int i = start; i < finish; i++) {
  531. if (piece[fromY][i] != 0) {
  532. count++;
  533. }
  534. }
  535. }
  536. if (count != 1) {
  537. return false;
  538. }
  539. }
  540. }
  541. return true;
  542. }
  543. //判断是否为红方,如果不是,则反转。
  544. public static Pos reversePos(Pos pos, boolean IsReverse) {
  545. return (IsReverse == false) ? pos : new Pos(8 - pos.x, 9 - pos.y);
  546. }
  547. }

AI.java

  1. import Info.Pos;
  2. import ChessMove.Rule;
  3. import java.util.Iterator;
  4. import java.util.LinkedList;
  5. import java.util.List;
  6. import java.util.Map;
  7. import static com.example.a77304.chessgame.HomeActivity.zobrist;
  8. import static com.example.a77304.chessgame.PvMActivity.transformTable;
  9. public class AI {
  10. //棋子力价值表
  11. public static int[][][] pieceValue = new int[][][]{
  12. //黑将
  13. {
  14. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  15. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  16. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  17. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  18. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  19. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  20. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  21. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  22. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  23. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  24. },
  25. //黑士
  26. {
  27. {0, 0, 0, 20, 0, 20, 0, 0, 0},
  28. {0, 0, 0, 0, 23, 0, 0, 0, 0},
  29. {0, 0, 0, 20, 0, 20, 0, 0, 0},
  30. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  31. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  32. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  33. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  34. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  35. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  36. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  37. },
  38. //黑象
  39. {
  40. {0, 0, 20, 0, 0, 0, 20, 0, 0},
  41. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  42. {18, 0, 0, 0, 23, 0, 0, 0, 18},
  43. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  44. {0, 0, 20, 0, 0, 0, 20, 0, 0},
  45. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  46. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  47. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  48. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  49. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  50. },
  51. //黑马
  52. {
  53. {88, 85, 90, 88, 90, 88, 90, 85, 88},
  54. {85, 90, 92, 93, 78, 93, 92, 90, 85},
  55. {93, 92, 94, 95, 92, 95, 94, 92, 93},
  56. {92, 94, 98, 95, 98, 95, 98, 94, 92},
  57. {90, 98, 101, 102, 103, 102, 101, 98, 90},
  58. {90, 100, 99, 103, 104, 103, 99, 100, 90},
  59. {93, 108, 100, 107, 100, 107, 100, 108, 93},
  60. {92, 98, 99, 103, 99, 103, 99, 98, 92},
  61. {90, 96, 103, 97, 94, 97, 103, 96, 90},
  62. {90, 90, 90, 96, 90, 96, 90, 90, 90},
  63. },
  64. //黑车
  65. {
  66. {194, 206, 204, 212, 200, 212, 204, 206, 194},
  67. {200, 208, 206, 212, 200, 212, 206, 208, 200},
  68. {198, 208, 204, 212, 212, 212, 204, 208, 198},
  69. {204, 209, 204, 212, 214, 212, 204, 209, 204},
  70. {208, 212, 212, 214, 215, 214, 212, 212, 208},
  71. {208, 211, 211, 214, 215, 214, 211, 211, 208},
  72. {206, 213, 213, 216, 216, 216, 213, 213, 206},
  73. {206, 208, 207, 214, 216, 214, 207, 208, 206},
  74. {206, 212, 209, 216, 233, 216, 209, 212, 206},
  75. {206, 208, 207, 213, 214, 213, 207, 208, 206},
  76. },
  77. //黑炮
  78. {
  79. {96, 96, 97, 99, 99, 99, 97, 96, 96},
  80. {96, 97, 98, 98, 98, 98, 98, 97, 96},
  81. {97, 96, 100, 99, 101, 99, 100, 96, 97},
  82. {96, 96, 96, 96, 96, 96, 96, 96, 96},
  83. {95, 96, 99, 96, 100, 96, 99, 96, 95},
  84. {96, 96, 96, 96, 100, 96, 96, 96, 96},
  85. {96, 99, 99, 98, 100, 98, 99, 99, 96},
  86. {97, 97, 96, 91, 92, 91, 96, 97, 97},
  87. {98, 98, 96, 92, 89, 92, 96, 98, 98},
  88. {100, 100, 96, 91, 90, 91, 96, 100, 100},
  89. },
  90. //黑卒
  91. {
  92. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  93. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  94. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  95. {7, 0, 7, 0, 15, 0, 7, 0, 7},
  96. {7, 0, 13, 0, 16, 0, 13, 0, 7},
  97. {14, 18, 20, 27, 29, 27, 20, 18, 14},
  98. {19, 23, 27, 29, 30, 29, 27, 23, 19},
  99. {19, 24, 32, 37, 37, 37, 32, 24, 19},
  100. {19, 24, 34, 42, 44, 42, 34, 24, 19},
  101. {9, 9, 9, 11, 13, 11, 9, 9, 9},
  102. },
  103. //红帅
  104. {
  105. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  106. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  107. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  108. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  109. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  110. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  111. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  112. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  113. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0},
  114. {0, 0, 0, 8888, 8888, 8888, 0, 0, 0}
  115. },
  116. //红士
  117. {
  118. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  119. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  120. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  121. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  122. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  123. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  124. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  125. {0, 0, 0, 20, 0, 20, 0, 0, 0},
  126. {0, 0, 0, 0, 23, 0, 0, 0, 0},
  127. {0, 0, 0, 20, 0, 20, 0, 0, 0}
  128. },
  129. //红象
  130. {
  131. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  132. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  133. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  134. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  135. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  136. {0, 0, 20, 0, 0, 0, 20, 0, 0},
  137. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  138. {18, 0, 0, 0, 23, 0, 0, 0, 18},
  139. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  140. {0, 0, 20, 0, 0, 0, 20, 0, 0}
  141. },
  142. //红马
  143. {
  144. {90, 90, 90, 96, 90, 96, 90, 90, 90},
  145. {90, 96, 103, 97, 94, 97, 103, 96, 90},
  146. {92, 98, 99, 103, 99, 103, 99, 98, 92},
  147. {93, 108, 100, 107, 100, 107, 100, 108, 93},
  148. {90, 100, 99, 103, 104, 103, 99, 100, 90},
  149. {90, 98, 101, 102, 103, 102, 101, 98, 90},
  150. {92, 94, 98, 95, 98, 95, 98, 94, 92},
  151. {93, 92, 94, 95, 92, 95, 94, 92, 93},
  152. {85, 90, 92, 93, 78, 93, 92, 90, 85},
  153. {88, 85, 90, 88, 90, 88, 90, 85, 88}
  154. },
  155. //红车
  156. {
  157. {206, 208, 207, 213, 214, 213, 207, 208, 206},
  158. {206, 212, 209, 216, 233, 216, 209, 212, 206},
  159. {206, 208, 207, 214, 216, 214, 207, 208, 206},
  160. {206, 213, 213, 216, 216, 216, 213, 213, 206},
  161. {208, 211, 211, 214, 215, 214, 211, 211, 208},
  162. {208, 212, 212, 214, 215, 214, 212, 212, 208},
  163. {204, 209, 204, 212, 214, 212, 204, 209, 204},
  164. {198, 208, 204, 212, 212, 212, 204, 208, 198},
  165. {200, 208, 206, 212, 200, 212, 206, 208, 200},
  166. {194, 206, 204, 212, 200, 212, 204, 206, 194}
  167. },
  168. //红炮
  169. {
  170. {100, 100, 96, 91, 90, 91, 96, 100, 100},
  171. {98, 98, 96, 92, 89, 92, 96, 98, 98},
  172. {97, 97, 96, 91, 92, 91, 96, 97, 97},
  173. {96, 99, 99, 98, 100, 98, 99, 99, 96},
  174. {96, 96, 96, 96, 100, 96, 96, 96, 96},
  175. {95, 96, 99, 96, 100, 96, 99, 96, 95},
  176. {96, 96, 96, 96, 96, 96, 96, 96, 96},
  177. {97, 96, 100, 99, 101, 99, 100, 96, 97},
  178. {96, 97, 98, 98, 98, 98, 98, 97, 96},
  179. {96, 96, 97, 99, 99, 99, 97, 96, 96}
  180. },
  181. //红兵
  182. {
  183. {9, 9, 9, 11, 13, 11, 9, 9, 9},
  184. {19, 24, 34, 42, 44, 42, 34, 24, 19},
  185. {19, 24, 32, 37, 37, 37, 32, 24, 19},
  186. {19, 23, 27, 29, 30, 29, 27, 23, 19},
  187. {14, 18, 20, 27, 29, 27, 20, 18, 14},
  188. {7, 0, 13, 0, 16, 0, 13, 0, 7},
  189. {7, 0, 7, 0, 15, 0, 7, 0, 7},
  190. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  191. {0, 0, 0, 0, 0, 0, 0, 0, 0},
  192. {0, 0, 0, 0, 0, 0, 0, 0, 0}
  193. }
  194. };
  195. public static final int INF = 0x3f3f3f3f; //正无穷大
  196. public static final int Win = 88888;
  197. public static final int hashfEXACT = 1;
  198. public static final int hashfALPHA = 2;
  199. public static final int hashfBETA = 3;
  200. public static boolean isMachineRed;
  201. public static int ZobristKey;
  202. public static long ZobristKeyCheck;
  203. public static int maxDepth;
  204. public static int goodValue;
  205. public static int[][][][] historyTable = new int[9][10][9][10]; //历史表
  206. public static int searchCnt = 0;
  207. public AI() {
  208. }
  209. //迭代加深
  210. public static Move getBestMove(int[][] piece, boolean isRedGo, int depth, int startZobristKey, long startZobristKeyCheck, Map<Long, Integer> ZobristInfo) {
  211. int[][] pieceClone = new int[10][9];
  212. for (int i = 0; i <= 9; i++) {
  213. pieceClone[i] = piece[i].clone();
  214. }
  215. searchCnt = 0;
  216. Move goodMove = new Move(new Pos(-1, -1), new Pos(-1, -1));
  217. Move bestMove = new Move(new Pos(-1, -1), new Pos(-1, -1));
  218. clearHistory();
  219. for (int i = 2; i <= depth; i += 2) {
  220. goodMove = getGoodMove(pieceClone, isRedGo, i, startZobristKey, startZobristKeyCheck, ZobristInfo);
  221. if (goodValue >= -Win / 2) {
  222. bestMove = goodMove;
  223. }
  224. }
  225. if (bestMove.fromPos.equals(new Pos(-1, -1)) == true) {
  226. bestMove = getLegalMove(pieceClone, isRedGo);
  227. }
  228. //Log.i("博弈树搜索算法比对","搜索结点数:"+String.valueOf(searchCnt));
  229. return bestMove;
  230. }
  231. //PVS+置换表+历史表
  232. public static Move getGoodMove(int[][] piece, boolean isRedGo, int depth, int startZobristKey, long startZobristKeyCheck, Map<Long, Integer> ZobristInfo) {
  233. Move goodMove = new Move(new Pos(-1, -1), new Pos(-1, -1));
  234. isMachineRed = isRedGo;
  235. boolean FoundPv = false;
  236. int value = -INF;
  237. int alpha = -INF, beta = INF;
  238. boolean isKingAlive = true;
  239. ZobristKey = startZobristKey;
  240. ZobristKeyCheck = startZobristKeyCheck;
  241. maxDepth = depth;
  242. LinkedList<Move> sortedMoves = allPossibleMoves(piece, isRedGo, depth, alpha, beta);
  243. Iterator<Move> it = sortedMoves.iterator();
  244. while (it.hasNext()) {
  245. Move move = it.next();
  246. Pos fromPos = move.fromPos;
  247. Pos toPos = move.toPos;
  248. int pieceID = piece[toPos.y][toPos.x];
  249. piece[toPos.y][toPos.x] = piece[fromPos.y][fromPos.x];
  250. piece[fromPos.y][fromPos.x] = 0;
  251. updateZobrist(fromPos, toPos, piece[toPos.y][toPos.x], pieceID);
  252. if (pieceID == 1 || pieceID == 8) {
  253. isKingAlive = false;
  254. }
  255. if (ZobristInfo.get(ZobristKeyCheck) != null) {
  256. value = -INF;
  257. } else {
  258. if (FoundPv) {
  259. value = -PVS(piece, (isRedGo == true) ? false : true, depth - 1, -alpha - 1, -alpha, isKingAlive);
  260. if ((value > alpha) && (value < beta)) {
  261. value = -PVS(piece, (isRedGo == true) ? false : true, depth - 1, -beta, -alpha, isKingAlive);
  262. }
  263. } else {
  264. value = -PVS(piece, (isRedGo == true) ? false : true, depth - 1, -beta, -alpha, isKingAlive);
  265. }
  266. }
  267. updateZobrist(fromPos, toPos, piece[toPos.y][toPos.x], pieceID);
  268. piece[fromPos.y][fromPos.x] = piece[toPos.y][toPos.x];
  269. piece[toPos.y][toPos.x] = pieceID;
  270. if (pieceID == 1 || pieceID == 8) {
  271. isKingAlive = true;
  272. }
  273. if (value > alpha) {
  274. alpha = value;
  275. FoundPv = true;
  276. goodMove = new Move(fromPos, toPos);
  277. }
  278. }
  279. goodValue = alpha;
  280. addHistory(goodMove.fromPos, goodMove.toPos, (maxDepth - depth + 1) * (maxDepth - depth + 1));
  281. return goodMove;
  282. }
  283. //通过算法获得最佳结果
  284. public static int PVS(int[][] piece, boolean isRedGo, int depth, int alpha, int beta, boolean isKingAlive) {
  285. int value = transformTable.readTransformTable(ZobristKey, ZobristKeyCheck, maxDepth - depth, alpha, beta); //局面评分
  286. if (value != INF) {
  287. return value;
  288. }
  289. if (isKingAlive == false) {
  290. if (isMachineRed == true && isRedGo == true) {
  291. return -Win + (maxDepth - depth);
  292. } else if (isMachineRed == true && isRedGo == false) {
  293. return Win - (maxDepth - depth);
  294. } else if (isMachineRed == false && isRedGo == true) {
  295. return Win - (maxDepth - depth);
  296. } else {
  297. return -Win + (maxDepth - depth);
  298. }
  299. }
  300. if (depth <= 0) {
  301. searchCnt++;
  302. if (Rule.isDead(piece, isMachineRed)) {
  303. value = -Win + (maxDepth - depth + 2);
  304. } else {
  305. value = evaluate(piece);
  306. }
  307. return value;
  308. }
  309. boolean FoundPv = false;
  310. int hashf = hashfALPHA;
  311. int fatherZobristKey = ZobristKey;
  312. long fatherZobristKeyCheck = ZobristKeyCheck;
  313. value = -INF;
  314. Move goodMove = new Move(new Pos(-1, -1), new Pos(-1, -1));
  315. LinkedList<Move> sortedMoves = allPossibleMoves(piece, isRedGo, depth, alpha, beta);
  316. Iterator<Move> it = sortedMoves.iterator();
  317. while (it.hasNext()) {
  318. Move move = it.next();
  319. Pos fromPos = move.fromPos;
  320. Pos toPos = move.toPos;
  321. int pieceID = piece[toPos.y][toPos.x];
  322. if (maxDepth == 6 && depth == 1 && pieceID == 0) continue;
  323. piece[toPos.y][toPos.x] = piece[fromPos.y][fromPos.x];
  324. piece[fromPos.y][fromPos.x] = 0;
  325. updateZobrist(fromPos, toPos, piece[toPos.y][toPos.x], pieceID);
  326. if (pieceID == 1 || pieceID == 8) {
  327. isKingAlive = false;
  328. }
  329. if (FoundPv) {
  330. value = -PVS(piece, (isRedGo == true) ? false : true, depth - 1, -alpha - 1, -alpha, isKingAlive);
  331. if ((value > alpha) && (value < beta)) {
  332. value = -PVS(piece, (isRedGo == true) ? false : true, depth - 1, -beta, -alpha, isKingAlive);
  333. }
  334. } else {
  335. value = -PVS(piece, (isRedGo == true) ? false : true, depth - 1, -beta, -alpha, isKingAlive);
  336. }
  337. updateZobrist(fromPos, toPos, piece[toPos.y][toPos.x], pieceID);
  338. piece[fromPos.y][fromPos.x] = piece[toPos.y][toPos.x];
  339. piece[toPos.y][toPos.x] = pieceID;
  340. if (pieceID == 1 || pieceID == 8) {
  341. isKingAlive = true;
  342. }
  343. if (value >= beta) {
  344. transformTable.saveTransformTable(fatherZobristKey, fatherZobristKeyCheck, maxDepth - depth, beta, hashfBETA);
  345. addHistory(fromPos, toPos, (maxDepth - depth + 1) * (maxDepth - depth + 1));
  346. return beta;
  347. }
  348. if (value > alpha) {
  349. alpha = value;
  350. FoundPv = true;
  351. hashf = hashfEXACT;
  352. goodMove = new Move(fromPos, toPos);
  353. }
  354. }
  355. transformTable.saveTransformTable(fatherZobristKey, fatherZobristKeyCheck, maxDepth - depth, alpha, hashf);
  356. if (hashf == hashfEXACT) {
  357. addHistory(goodMove.fromPos, goodMove.toPos, (maxDepth - depth + 1) * (maxDepth - depth + 1));
  358. }
  359. return alpha;
  360. }
  361. //生成所有可能走法
  362. public static LinkedList<Move> allPossibleMoves(int[][] piece, boolean isRedGo, int depth, int alpha, int beta) {
  363. LinkedList<Move> sortedMoves = new LinkedList<Move>();
  364. LinkedList<Move> transformMoves = new LinkedList<Move>();
  365. LinkedList<Move> eatMoves = new LinkedList<Move>();
  366. LinkedList<Move> historyMoves = new LinkedList<Move>();
  367. //遍历整个棋盘
  368. for (int i = 0; i <= 9; i++) {
  369. for (int j = 0; j <= 8; j++) {
  370. if ((isRedGo == false && piece[i][j] >= 1 && piece[i][j] <= 7) || (isRedGo == true && piece[i][j] >= 8 && piece[i][j] <= 14)) {
  371. List<Pos> ret = Rule.PossibleMoves(piece, j, i, piece[i][j]); //某个位置的棋子的全部走法
  372. Pos fromPos = new Pos(j, i);
  373. Iterator<Pos> it = ret.iterator();
  374. while (it.hasNext()) {
  375. Pos toPos = it.next();
  376. updateZobrist(fromPos, toPos, piece[fromPos.y][fromPos.x], piece[toPos.y][toPos.x]);
  377. if (transformTable.readTransformTable(ZobristKey, ZobristKeyCheck, maxDepth - depth, alpha, beta) != INF) {
  378. transformMoves.add(new Move(fromPos, toPos));
  379. } else {
  380. if (piece[toPos.y][toPos.x] != 0) {
  381. eatMoves.add(new Move(fromPos, toPos));
  382. } else {
  383. if (historyMoves.isEmpty()) {
  384. historyMoves.add(new Move(fromPos, toPos));
  385. } else {
  386. Move firstMove = historyMoves.getFirst();
  387. int firstVal = getHistory(firstMove.fromPos, firstMove.toPos);
  388. int curVal = getHistory(fromPos, toPos);
  389. if (curVal >= firstVal) {
  390. historyMoves.addFirst(new Move(fromPos, toPos));
  391. } else {
  392. historyMoves.addLast(new Move(fromPos, toPos));
  393. }
  394. }
  395. }
  396. }
  397. updateZobrist(fromPos, toPos, piece[fromPos.y][fromPos.x], piece[toPos.y][toPos.x]);
  398. }
  399. }
  400. }
  401. }
  402. sortedMoves.addAll(transformMoves);
  403. sortedMoves.addAll(eatMoves);
  404. sortedMoves.addAll(historyMoves);
  405. return sortedMoves;
  406. }
  407. public static void clearHistory() {
  408. for (int i = 0; i < 9; i++) {
  409. for (int j = 0; j < 10; j++) {
  410. for (int k = 0; k < 9; k++) {
  411. for (int p = 0; p < 10; p++) {
  412. historyTable[i][j][k][p] = historyTable[i][j][k][p] = 0;
  413. }
  414. }
  415. }
  416. }
  417. }
  418. public static int getHistory(Pos fromPos, Pos toPos) {
  419. return historyTable[fromPos.x][fromPos.y][toPos.x][toPos.y];
  420. }
  421. public static void addHistory(Pos fromPos, Pos toPos, int val) {
  422. historyTable[fromPos.x][fromPos.y][toPos.x][toPos.y] += val;
  423. }
  424. public static void updateZobrist(Pos fromPos, Pos toPos, int fromID, int toID) {
  425. ZobristKey = ZobristKey ^ zobrist.ZobristTable[fromID - 1][fromPos.y][fromPos.x];
  426. ZobristKeyCheck = ZobristKeyCheck ^ zobrist.ZobristTableCheck[fromID - 1][fromPos.y][fromPos.x];
  427. ZobristKey = ZobristKey ^ zobrist.ZobristTable[fromID - 1][toPos.y][toPos.x];
  428. ZobristKeyCheck = ZobristKeyCheck ^ zobrist.ZobristTableCheck[fromID - 1][toPos.y][toPos.x];
  429. if (toID > 0) {
  430. ZobristKey = ZobristKey ^ zobrist.ZobristTable[toID - 1][toPos.y][toPos.x];
  431. ZobristKeyCheck = ZobristKeyCheck ^ zobrist.ZobristTableCheck[toID - 1][toPos.y][toPos.x];
  432. }
  433. }
  434. //局面评分
  435. public static int evaluate(int[][] piece) {
  436. int score = 0;
  437. for (int i = 0; i <= 9; i++) {
  438. for (int j = 0; j <= 8; j++) {
  439. if (piece[i][j] >= 1 && piece[i][j] <= 7) {
  440. score += pieceValue[piece[i][j] - 1][i][j];
  441. } else if (piece[i][j] >= 8 && piece[i][j] <= 14) {
  442. score -= pieceValue[piece[i][j] - 1][i][j];
  443. }
  444. }
  445. }
  446. if (isMachineRed) score *= -1;
  447. return score;
  448. }
  449. //判断是否有杀招走法
  450. public static Move getLegalMove(int piece[][], boolean isRedKing) { //参数true表示红棋
  451. if (isRedKing == true) {
  452. for (int i = 0; i <= 9; i++) {
  453. for (int j = 0; j <= 8; j++) {
  454. if (piece[i][j] >= 8 && piece[i][j] <= 14) {
  455. //生成某个位置的棋子的所有走法的位置
  456. List<Pos> moves = Rule.PossibleMoves(piece, j, i, piece[i][j]);
  457. Iterator<Pos> it = moves.iterator();
  458. while (it.hasNext()) {
  459. Pos pos = it.next();
  460. int tmp = piece[pos.y][pos.x]; //标记可以走的位置的其他棋子号
  461. if (tmp == 1) { //当前棋子下一步可以吃掉黑方将
  462. return new Move(new Pos(j, i), pos); //返回杀招的走法
  463. }
  464. piece[pos.y][pos.x] = piece[i][j];
  465. piece[i][j] = 0;
  466. if (Rule.isKingDanger(piece, true) == false) { //非当前棋子的可以吃掉将
  467. piece[i][j] = piece[pos.y][pos.x];
  468. piece[pos.y][pos.x] = tmp;
  469. return new Move(new Pos(j, i), pos); //返回杀招的走法
  470. }
  471. piece[i][j] = piece[pos.y][pos.x];
  472. piece[pos.y][pos.x] = tmp;
  473. }
  474. }
  475. }
  476. }
  477. } else { //参数false表示黑棋
  478. for (int i = 0; i <= 9; i++) {
  479. for (int j = 0; j <= 8; j++) {
  480. if (piece[i][j] >= 1 && piece[i][j] <= 7) {
  481. List<Pos> moves = Rule.PossibleMoves(piece, j, i, piece[i][j]);
  482. Iterator<Pos> it = moves.iterator();
  483. while (it.hasNext()) {
  484. Pos pos = it.next();
  485. int tmp = piece[pos.y][pos.x];
  486. if (tmp == 8) {
  487. return new Move(new Pos(j, i), pos);
  488. }
  489. piece[pos.y][pos.x] = piece[i][j];
  490. piece[i][j] = 0;
  491. if (Rule.isKingDanger(piece, false) == false) {
  492. piece[i][j] = piece[pos.y][pos.x];
  493. piece[pos.y][pos.x] = tmp;
  494. return new Move(new Pos(j, i), pos);
  495. }
  496. piece[i][j] = piece[pos.y][pos.x];
  497. piece[pos.y][pos.x] = tmp;
  498. }
  499. }
  500. }
  501. }
  502. }
  503. return new Move(new Pos(-1, -1), new Pos(-1, -1));
  504. }
  505. }

未完......

点击下载资源

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号