package edu.gricar.brezskrbnik.krizciKrozci; import java.util.Random; import edu.gricar.brezskrbnik.R; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Handler.Callback; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import edu.gricar.brezskrbnik.krizciKrozci.GameView.ICellListener; import edu.gricar.brezskrbnik.krizciKrozci.GameView.State; public class GameActivity extends Activity { /** Start player. Must be 1 or 2. Default is 1. */ public static final String EXTRA_START_PLAYER = "edu.gricar.brezskbrnik.krizciKrozci.GameActivity.EXTRA_START_PLAYER"; private static final int MSG_COMPUTER_TURN = 1; private static final long COMPUTER_DELAY_MS = 1500; private Handler mHandler = new Handler(new MyHandlerCallback()); private GameView mGameView; private TextView mInfoView; private Button mButtonNext; /** Called when the activity is first created. */ @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.lib_game); mGameView = (GameView) findViewById(R.id.game_view); mInfoView = (TextView) findViewById(R.id.info_turn); mButtonNext = (Button) findViewById(R.id.next_turn); mGameView.setFocusable(true); mGameView.setFocusableInTouchMode(true); mGameView.setCellListener(new MyCellListener()); mButtonNext.setOnClickListener(new MyButtonListener()); } /* * P - trenutni polo�aj igralec - igralec na potezi d - preostala globina * alfa - spodnja meja ocene beta - zgornja meja ocene */ public int minimaks(int P, String igralec, int d, int alfa, int beta) { if (d == 0) { return 9; // preostala globina preiskovanja je 9 } if (igralec.equalsIgnoreCase("MAX")) { alfa = -100; } else { beta = 100; } // nastavimo zgornjo oz spodnjo mejo ocene State[] data = mGameView.getData(); // pogledamo na katerem polju imajo igralci postavljeno int ocena = 0; int naPotezi = 0; for (int i = 0; i < P; i++) { if (data[i] == State.EMPTY) { if (igralec.equalsIgnoreCase("MIN")) { // �e je igralec MIN ocena = hevristika("MAX", i); // vrnemo oceno hevristike if (ocena > alfa) { // pogledamo �e se spla�a postaviti tja alfa = ocena; naPotezi = i; } } else { ocena = hevristika("MIN", i); if (ocena < beta) { beta = ocena; naPotezi = i; } } } if (alfa >= beta) // re�emo vejo v primeru da je alfa ve�ji od beta, torej se nam // se spla�a gledati naprej return naPotezi; } return naPotezi; /* * izhod (ocena, poteza) vrednost minimaks drevesa in najbolj�a * naslednja poteza */ } public int naPotezi() { int naPotezi = 0; String igralec; if (State.PLAYER1 == mGameView.getCurrentPlayer()) igralec = "MAX"; else igralec = "MIN"; naPotezi = minimaks(9, igralec, 9, -100, 100); // vrnemo kam �eli postaviti ra�unalnik na polje return naPotezi; } public int hevristika(String igralec, int ind) { int krizec = 0; int krozec = 0; State[] data = mGameView.getData(); if (igralec.equalsIgnoreCase("MAX")) { mGameView.setCell(ind, State.PLAYER1); } else { mGameView.setCell(ind, State.PLAYER2); } /* * POLJE[0,1,2] * [3,4,5] * [6,7,8] */ // diagonala levo proti desni if (data[0] == State.PLAYER1 || data[0] == State.EMPTY) { if ((data[4] == State.PLAYER1 || data[4] == State.EMPTY)) { if ((data[8] == State.PLAYER1 || data[8] == State.EMPTY)) { krizec++; } } } // diagonala desno proti levi if (data[2] == State.PLAYER1 || data[2] == State.EMPTY) { if (data[4] == State.PLAYER1 || data[4] == State.EMPTY) { if (data[6] == State.PLAYER1 || data[6] == State.EMPTY) { krizec++; } } } // prva vrstica if (data[0] == State.PLAYER1 || data[0] == State.EMPTY) { if (data[1] == State.PLAYER1 || data[1] == State.EMPTY) { if (data[2] == State.PLAYER1 || data[2] == State.EMPTY) { krizec++; } } } // druga if (data[3] == State.PLAYER1 || data[3] == State.EMPTY) { if (data[4] == State.PLAYER1 || data[4] == State.EMPTY) { if (data[5] == State.PLAYER1 || data[5] == State.EMPTY) { krizec++; } } } // tretja if (data[6] == State.PLAYER1 || data[6] == State.EMPTY) { if (data[7] == State.PLAYER1 || data[7] == State.EMPTY) { if (data[8] == State.PLAYER1 || data[8] == State.EMPTY) { krizec++; } } } // diagonala levo proti desni if (data[0] == State.PLAYER2 || data[0] == State.EMPTY) { if (data[4] == State.PLAYER2 || data[4] == State.EMPTY) { if (data[8] == State.PLAYER2 || data[8] == State.EMPTY) { krozec++; } } } // diagonala desno proti levi if (data[2] == State.PLAYER2 || data[2] == State.EMPTY) { if (data[4] == State.PLAYER2 || data[4] == State.EMPTY) { if (data[6] == State.PLAYER2 || data[6] == State.EMPTY) { krozec++; } } } // prva vrstica if (data[0] == State.PLAYER2 || data[0] == State.EMPTY) { if (data[1] == State.PLAYER2 || data[1] == State.EMPTY) { if (data[2] == State.PLAYER2 || data[2] == State.EMPTY) { krozec++; } } } // druga vrstica if (data[3] == State.PLAYER2 || data[3] == State.EMPTY) { if (data[4] == State.PLAYER2 || data[4] == State.EMPTY) { if (data[5] == State.PLAYER2 || data[5] == State.EMPTY) { krozec++; } } } // tretja vrstica if (data[6] == State.PLAYER2 || data[6] == State.EMPTY) { if (data[7] == State.PLAYER2 || data[7] == State.EMPTY) { if (data[8] == State.PLAYER2 || data[8] == State.EMPTY) { krozec++; } } } // stolpci gledam dol, kateri ima prednost if (data[0] == State.PLAYER1 || data[0] == State.EMPTY) { if (data[3] == State.PLAYER1 || data[3] == State.EMPTY) { if (data[6] == State.PLAYER1 || data[6] == State.EMPTY) { krizec++; } } } if (data[1] == State.PLAYER1 || data[1] == State.EMPTY) { if (data[4] == State.PLAYER1 || data[4] == State.EMPTY) { if (data[7] == State.PLAYER1 || data[7] == State.EMPTY) { krizec++; } } } if (data[2] == State.PLAYER1 || data[2] == State.EMPTY) { if (data[5] == State.PLAYER1 || data[5] == State.EMPTY) { if (data[8] == State.PLAYER1 || data[8] == State.EMPTY) { krizec++; } } } if (data[0] == State.PLAYER2 || data[0] == State.EMPTY) { if (data[3] == State.PLAYER2 || data[3] == State.EMPTY) { if (data[6] == State.PLAYER2 || data[6] == State.EMPTY) { krozec++; } } } if (data[1] == State.PLAYER2 || data[1] == State.EMPTY) { if (data[4] == State.PLAYER2 || data[4] == State.EMPTY) { if (data[7] == State.PLAYER2 || data[7] == State.EMPTY) { krozec++; } } } if (data[2] == State.PLAYER2 || data[2] == State.EMPTY) { if (data[5] == State.PLAYER2 || data[5] == State.EMPTY) { if (data[8] == State.PLAYER2 || data[8] == State.EMPTY) { krozec++; } } } mGameView.setCell(ind, State.EMPTY); return krizec - krozec; } @Override protected void onResume() { super.onResume(); State player = mGameView.getCurrentPlayer(); if (player == State.UNKNOWN) { player = State.fromInt(getIntent().getIntExtra(EXTRA_START_PLAYER, 1)); if (!checkGameFinished(player)) { selectTurn(player); } } if (player == State.PLAYER2) { mHandler.sendEmptyMessageDelayed(MSG_COMPUTER_TURN, COMPUTER_DELAY_MS); } if (player == State.WIN) { setWinState(mGameView.getWinner()); } } private State selectTurn(State player) { mGameView.setCurrentPlayer(player); mButtonNext.setEnabled(false); if (player == State.PLAYER1) { mInfoView.setText(R.string.player1_turn); mGameView.setEnabled(true); } else if (player == State.PLAYER2) { mInfoView.setText(R.string.player2_turn); mGameView.setEnabled(false); } return player; } private class MyCellListener implements ICellListener { public void onCellSelected() { if (mGameView.getCurrentPlayer() == State.PLAYER1) { int cell = mGameView.getSelection(); mButtonNext.setEnabled(cell >= 0); } } } private class MyButtonListener implements OnClickListener { public void onClick(View v) { State player = mGameView.getCurrentPlayer(); if (player == State.WIN) { GameActivity.this.finish(); } else if (player == State.PLAYER1) { int cell = mGameView.getSelection(); if (cell >= 0) { mGameView.stopBlink(); mGameView.setCell(cell, player); finishTurn(); } } } } private class MyHandlerCallback implements Callback { public boolean handleMessage(Message msg) { if (msg.what == MSG_COMPUTER_TURN) { // Pick a non-used cell at random. That's about all the AI you // need for this game. State[] data = mGameView.getData(); int used = 0; while (used != 0x1F) { int a = naPotezi(); int index = a; if (((used >> index) & 1) == 0) { used |= 1 << index; if (data[index] == State.EMPTY) { mGameView.setCell(index, mGameView.getCurrentPlayer()); break; } } } finishTurn(); return true; } return false; } } private State getOtherPlayer(State player) { return player == State.PLAYER1 ? State.PLAYER2 : State.PLAYER1; } private void finishTurn() { State player = mGameView.getCurrentPlayer(); if (!checkGameFinished(player)) { player = selectTurn(getOtherPlayer(player)); if (player == State.PLAYER2) { mHandler.sendEmptyMessageDelayed(MSG_COMPUTER_TURN, COMPUTER_DELAY_MS); } } } public boolean checkGameFinished(State player) { State[] data = mGameView.getData(); boolean full = true; int col = -1; int row = -1; int diag = -1; // check rows for (int j = 0, k = 0; j < 3; j++, k += 3) { if (data[k] != State.EMPTY && data[k] == data[k + 1] && data[k] == data[k + 2]) { row = j; } if (full && (data[k] == State.EMPTY || data[k + 1] == State.EMPTY || data[k + 2] == State.EMPTY)) { full = false; } } // check columns for (int i = 0; i < 3; i++) { if (data[i] != State.EMPTY && data[i] == data[i + 3] && data[i] == data[i + 6]) { col = i; } } // check diagonals if (data[0] != State.EMPTY && data[0] == data[1 + 3] && data[0] == data[2 + 6]) { diag = 0; } else if (data[2] != State.EMPTY && data[2] == data[1 + 3] && data[2] == data[0 + 6]) { diag = 1; } if (col != -1 || row != -1 || diag != -1) { setFinished(player, col, row, diag); return true; } // if we get here, there's no winner but the board is full. if (full) { setFinished(State.EMPTY, -1, -1, -1); return true; } return false; } private void setFinished(State player, int col, int row, int diagonal) { mGameView.setCurrentPlayer(State.WIN); mGameView.setWinner(player); mGameView.setEnabled(false); mGameView.setFinished(col, row, diagonal); setWinState(player); } private void setWinState(State player) { mButtonNext.setEnabled(true); mButtonNext.setText("Nazaj"); String text; if (player == State.EMPTY) { text = getString(R.string.tie); } else if (player == State.PLAYER1) { text = getString(R.string.player1_win); } else { text = getString(R.string.player2_win); } mInfoView.setText(text); } }