Home | History | Annotate | Download | only in library
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.tictactoe.library;
     18 
     19 import java.util.Random;
     20 
     21 import android.app.Activity;
     22 import android.os.Bundle;
     23 import android.os.Handler;
     24 import android.os.Message;
     25 import android.os.Handler.Callback;
     26 import android.view.View;
     27 import android.view.View.OnClickListener;
     28 import android.widget.Button;
     29 import android.widget.TextView;
     30 
     31 import com.example.android.tictactoe.library.GameView.ICellListener;
     32 import com.example.android.tictactoe.library.GameView.State;
     33 
     34 
     35 public class GameActivity extends Activity {
     36 
     37     /** Start player. Must be 1 or 2. Default is 1. */
     38     public static final String EXTRA_START_PLAYER =
     39         "com.example.android.tictactoe.library.GameActivity.EXTRA_START_PLAYER";
     40 
     41     private static final int MSG_COMPUTER_TURN = 1;
     42     private static final long COMPUTER_DELAY_MS = 500;
     43 
     44     private Handler mHandler = new Handler(new MyHandlerCallback());
     45     private Random mRnd = new Random();
     46     private GameView mGameView;
     47     private TextView mInfoView;
     48     private Button mButtonNext;
     49 
     50     /** Called when the activity is first created. */
     51     @Override
     52     public void onCreate(Bundle bundle) {
     53         super.onCreate(bundle);
     54 
     55         /*
     56          * IMPORTANT: all resource IDs from this library will eventually be merged
     57          * with the resources from the main project that will use the library.
     58          *
     59          * If the main project and the libraries define the same resource IDs,
     60          * the application project will always have priority and override library resources
     61          * and IDs defined in multiple libraries are resolved based on the libraries priority
     62          * defined in the main project.
     63          *
     64          * An intentional consequence is that the main project can override some resources
     65          * from the library.
     66          * (TODO insert example).
     67          *
     68          * To avoid potential conflicts, it is suggested to add a prefix to the
     69          * library resource names.
     70          */
     71         setContentView(R.layout.lib_game);
     72 
     73         mGameView = (GameView) findViewById(R.id.game_view);
     74         mInfoView = (TextView) findViewById(R.id.info_turn);
     75         mButtonNext = (Button) findViewById(R.id.next_turn);
     76 
     77         mGameView.setFocusable(true);
     78         mGameView.setFocusableInTouchMode(true);
     79         mGameView.setCellListener(new MyCellListener());
     80 
     81         mButtonNext.setOnClickListener(new MyButtonListener());
     82     }
     83 
     84     @Override
     85     protected void onResume() {
     86         super.onResume();
     87 
     88         State player = mGameView.getCurrentPlayer();
     89         if (player == State.UNKNOWN) {
     90             player = State.fromInt(getIntent().getIntExtra(EXTRA_START_PLAYER, 1));
     91             if (!checkGameFinished(player)) {
     92                 selectTurn(player);
     93             }
     94         }
     95         if (player == State.PLAYER2) {
     96             mHandler.sendEmptyMessageDelayed(MSG_COMPUTER_TURN, COMPUTER_DELAY_MS);
     97         }
     98         if (player == State.WIN) {
     99             setWinState(mGameView.getWinner());
    100         }
    101     }
    102 
    103 
    104     private State selectTurn(State player) {
    105         mGameView.setCurrentPlayer(player);
    106         mButtonNext.setEnabled(false);
    107 
    108         if (player == State.PLAYER1) {
    109             mInfoView.setText(R.string.player1_turn);
    110             mGameView.setEnabled(true);
    111 
    112         } else if (player == State.PLAYER2) {
    113             mInfoView.setText(R.string.player2_turn);
    114             mGameView.setEnabled(false);
    115         }
    116 
    117         return player;
    118     }
    119 
    120     private class MyCellListener implements ICellListener {
    121         public void onCellSelected() {
    122             if (mGameView.getCurrentPlayer() == State.PLAYER1) {
    123                 int cell = mGameView.getSelection();
    124                 mButtonNext.setEnabled(cell >= 0);
    125             }
    126         }
    127     }
    128 
    129     private class MyButtonListener implements OnClickListener {
    130 
    131         public void onClick(View v) {
    132             State player = mGameView.getCurrentPlayer();
    133 
    134             if (player == State.WIN) {
    135                 GameActivity.this.finish();
    136 
    137             } else if (player == State.PLAYER1) {
    138                 int cell = mGameView.getSelection();
    139                 if (cell >= 0) {
    140                     mGameView.stopBlink();
    141                     mGameView.setCell(cell, player);
    142                     finishTurn();
    143                 }
    144             }
    145         }
    146     }
    147 
    148     private class MyHandlerCallback implements Callback {
    149         public boolean handleMessage(Message msg) {
    150             if (msg.what == MSG_COMPUTER_TURN) {
    151 
    152                 // Pick a non-used cell at random. That's about all the AI you need for this game.
    153                 State[] data = mGameView.getData();
    154                 int used = 0;
    155                 while (used != 0x1F) {
    156                     int index = mRnd.nextInt(9);
    157                     if (((used >> index) & 1) == 0) {
    158                         used |= 1 << index;
    159                         if (data[index] == State.EMPTY) {
    160                             mGameView.setCell(index, mGameView.getCurrentPlayer());
    161                             break;
    162                         }
    163                     }
    164                 }
    165 
    166                 finishTurn();
    167                 return true;
    168             }
    169             return false;
    170         }
    171     }
    172 
    173     private State getOtherPlayer(State player) {
    174         return player == State.PLAYER1 ? State.PLAYER2 : State.PLAYER1;
    175     }
    176 
    177     private void finishTurn() {
    178         State player = mGameView.getCurrentPlayer();
    179         if (!checkGameFinished(player)) {
    180             player = selectTurn(getOtherPlayer(player));
    181             if (player == State.PLAYER2) {
    182                 mHandler.sendEmptyMessageDelayed(MSG_COMPUTER_TURN, COMPUTER_DELAY_MS);
    183             }
    184         }
    185     }
    186 
    187     public boolean checkGameFinished(State player) {
    188         State[] data = mGameView.getData();
    189         boolean full = true;
    190 
    191         int col = -1;
    192         int row = -1;
    193         int diag = -1;
    194 
    195         // check rows
    196         for (int j = 0, k = 0; j < 3; j++, k += 3) {
    197             if (data[k] != State.EMPTY && data[k] == data[k+1] && data[k] == data[k+2]) {
    198                 row = j;
    199             }
    200             if (full && (data[k] == State.EMPTY ||
    201                          data[k+1] == State.EMPTY ||
    202                          data[k+2] == State.EMPTY)) {
    203                 full = false;
    204             }
    205         }
    206 
    207         // check columns
    208         for (int i = 0; i < 3; i++) {
    209             if (data[i] != State.EMPTY && data[i] == data[i+3] && data[i] == data[i+6]) {
    210                 col = i;
    211             }
    212         }
    213 
    214         // check diagonals
    215         if (data[0] != State.EMPTY && data[0] == data[1+3] && data[0] == data[2+6]) {
    216             diag = 0;
    217         } else  if (data[2] != State.EMPTY && data[2] == data[1+3] && data[2] == data[0+6]) {
    218             diag = 1;
    219         }
    220 
    221         if (col != -1 || row != -1 || diag != -1) {
    222             setFinished(player, col, row, diag);
    223             return true;
    224         }
    225 
    226         // if we get here, there's no winner but the board is full.
    227         if (full) {
    228             setFinished(State.EMPTY, -1, -1, -1);
    229             return true;
    230         }
    231         return false;
    232     }
    233 
    234     private void setFinished(State player, int col, int row, int diagonal) {
    235 
    236         mGameView.setCurrentPlayer(State.WIN);
    237         mGameView.setWinner(player);
    238         mGameView.setEnabled(false);
    239         mGameView.setFinished(col, row, diagonal);
    240 
    241         setWinState(player);
    242     }
    243 
    244     private void setWinState(State player) {
    245         mButtonNext.setEnabled(true);
    246         mButtonNext.setText("Back");
    247 
    248         String text;
    249 
    250         if (player == State.EMPTY) {
    251             text = getString(R.string.tie);
    252         } else if (player == State.PLAYER1) {
    253             text = getString(R.string.player1_win);
    254         } else {
    255             text = getString(R.string.player2_win);
    256         }
    257         mInfoView.setText(text);
    258     }
    259 }
    260