Сайт разработчика Александр Климова

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Арифметическая игра

Дети не любят учиться, а предпочитают играть. Но надо их приучать к математике и другим дисциплинам. Напишем арифметическую игру на сложение, вычитание, деление и умножение.

Игроку будет предложено решить выражение и дать правильный ответ. Поехали.

Создадим новую папку res/drawable и разместим в ней файл app_back.xml, который послужит фоном для экрана приложения:


<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true" >

    <gradient
        android:angle="90"
        android:endColor="#ff003333"
        android:startColor="#ff006666" />

</shape>

В этой же папке создадим файл num_back.xml, который будет использоваться в качестве фона у кнопок:


<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true" >

    <gradient
        android:angle="90"
        android:endColor="#ff009966"
        android:startColor="#ff003333" />

    <corners android:radius="20dp" />

    <stroke
        android:width="2dp"
        android:color="#ff003333" />

</shape>

Ещё один файл enter_back.xml послужит фоном для кнопки Enter


<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true" >

    <gradient
        android:angle="90"
        android:endColor="#ff99ffcc"
        android:startColor="#ff669999" />

    <corners android:radius="20dp" />

    <stroke
        android:width="2dp"
        android:color="#ff003333" />

</shape>

Создадим разметку для первой активности (у нас будет несколько экранов):


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/app_back"
    android:padding="10dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

        <ImageView
            android:id="@+id/operators"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:contentDescription="operators"
            android:padding="5dp"
            android:src="@drawable/operators" />

        <TextView
            android:id="@+id/intro"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/operators"
            android:layout_centerHorizontal="true"
            android:padding="20dp"
            android:text="@string/app_name"
            android:textColor="#ffffffff"
            android:textSize="20sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/play_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/intro"
            android:layout_centerHorizontal="true"
            android:layout_margin="5dp"
            android:background="@drawable/enter_back"
            android:padding="20dp"
            android:text="Play"
            android:textColor="#ff333333"
            android:textSize="20sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/help_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/play_btn"
            android:layout_centerHorizontal="true"
            android:layout_margin="5dp"
            android:background="@drawable/enter_back"
            android:padding="20dp"
            android:text="How to Play"
            android:textColor="#ff333333"
            android:textSize="20sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/high_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/help_btn"
            android:layout_centerHorizontal="true"
            android:layout_margin="5dp"
            android:background="@drawable/enter_back"
            android:padding="20dp"
            android:text="High Scores"
            android:textColor="#ff333333"
            android:textSize="20sp"
            android:textStyle="bold" />
    </RelativeLayout>

</ScrollView>

Внешний вид первого экрана будет следующим:

Создадим разметку для второй активности, где будет происходить сама игра - файл res/layout/activity_playgame.xml:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/app_back"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <ImageView
            android:id="@+id/response"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center|left"
            android:layout_weight="1"
            android:contentDescription="result"
            android:src="@drawable/tick" />

        <TextView
            android:id="@+id/score"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center|right"
            android:paddingRight="20dp"
            android:text="Score: 0"
            android:textColor="#ffffffff"
            android:textSize="20sp"
            android:textStyle="bold" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/question"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginBottom="2dp"
            android:layout_marginLeft="2dp"
            android:layout_marginTop="2dp"
            android:layout_weight="1"
            android:background="#ffffffff"
            android:gravity="center|right"
            android:padding="5dp"
            android:text="0 + 0"
            android:textColor="#ff333333"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/answer"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginBottom="2dp"
            android:layout_marginRight="2dp"
            android:layout_marginTop="2dp"
            android:layout_weight="1"
            android:background="#ffffffff"
            android:gravity="center|left"
            android:padding="5dp"
            android:text="= ?"
            android:textColor="#ff333333"
            android:textSize="30sp" />

        <Button
            android:id="@+id/clear"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/enter_back"
            android:gravity="center"
            android:padding="5dp"
            android:text="C"
            android:textColor="#ff333333"
            android:textSize="30sp"
            android:textStyle="bold" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn7"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="7"
            android:text="7"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn8"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="8"
            android:text="8"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn9"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="9"
            android:text="9"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn4"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="4"
            android:text="4"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn5"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="5"
            android:text="5"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn6"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="6"
            android:text="6"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="1"
            android:text="1"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="2"
            android:text="2"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btn3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="3"
            android:text="3"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn0"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="1"
            android:background="@drawable/num_back"
            android:gravity="center"
            android:padding="5dp"
            android:tag="0"
            android:text="0"
            android:textColor="#ffcccccc"
            android:textSize="30sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/enter"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="1dp"
            android:layout_weight="2"
            android:background="@drawable/enter_back"
            android:gravity="center"
            android:padding="5dp"
            android:text="Enter"
            android:textColor="#ff333333"
            android:textSize="30sp"
            android:textStyle="bold" />
    </LinearLayout>

</LinearLayout>

Внешний вид второй активности:

Создадим разметку для третьей активности - файл activity_how.xml:


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/app_back"
    android:padding="10dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

        <ImageView
            android:id="@+id/operators"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:contentDescription="operators"
            android:src="@drawable/operators" />

        <TextView
            android:id="@+id/intro"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/operators"
            android:layout_centerHorizontal="true"
            android:padding="20dp"
            android:text="@string/app_name"
            android:textColor="#ffffffff"
            android:textSize="20sp"
            android:textStyle="bold" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/intro"
            android:layout_centerHorizontal="true"
            android:padding="10dp"
            android:text="@string/help_info"
            android:textColor="#ffffffff"
            android:textSize="16sp" />
    </RelativeLayout>

</ScrollView>

Добавим строковый ресурс в файл res/values/strings.xml:


<string name="help_info">You Do The Math! is an arithmetic game.\n\n
    Choose Easy, Medium or Hard level to begin.\n\n
    Answer the question by typing on the number pad displayed and pressing enter.\n\n
    Press the C button to clear an existing answer.\n\n
    Each question may be an addition, subtraction, multiplication or division.\n\n
    Your ten best scores will automatically be saved into the High Scores.</string>

Конечно, вы можете составить свой текст.

Внешний вид третьей активности:

И ещё один макет для четвёртой активности, в которой будет выводиться таблица рекордов - файл res/layout/activity_high.xml:


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/app_back"
    android:padding="10dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

        <ImageView
            android:id="@+id/operators"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:contentDescription="operators"
            android:src="@drawable/operators" />

        <TextView
            android:id="@+id/intro"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/operators"
            android:layout_centerHorizontal="true"
            android:padding="20dp"
            android:text="@string/app_name"
            android:textColor="#ffffffff"
            android:textSize="26sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/high_head"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/intro"
            android:layout_centerHorizontal="true"
            android:padding="20dp"
            android:text="HIGH SCORES"
            android:textColor="#ffffffff"
            android:textSize="24sp"
            android:textStyle="bold" />
            
        <TextView
            android:id="@+id/high_scores_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/high_head"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:padding="10dp"
            android:textColor="#ffffffff"
            android:textSize="22sp"
            android:textStyle="bold" />    
    </RelativeLayout>

</ScrollView>

Настало время создавать классы активностей - PlayGameActivity (подключите к ней разметку activity_playgame.xml), HowToPlayActivity и HighScoresActivity с соответствующими макетами.

Начнём писать код для первой активности MainActivity:


package ru.alexanderklimov.mathgame;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	private Button playBtn, helpBtn, highBtn;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		playBtn = (Button) findViewById(R.id.play_btn);
		helpBtn = (Button) findViewById(R.id.help_btn);
		highBtn = (Button) findViewById(R.id.high_btn);

		playBtn.setOnClickListener(this);
		helpBtn.setOnClickListener(this);
		highBtn.setOnClickListener(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public void onClick(View view) {
		// TODO Auto-generated method stub
		if (view.getId() == R.id.play_btn) {
			// play button
		} else if (view.getId() == R.id.help_btn) {
			// how to play button
		} else if (view.getId() == R.id.high_btn) {
			// high scores button
		}
	}
}

Мы создали ссылки на три кнопки и установили прослушку на нажатия кнопок.

Когда пользователь выбирает кнопку Play, то ему предлагается выбрать уровень сложности и начинается сама игра.

Подготовим массив из строк для выбора уровня игры.


private String[] levelNames = { "Easy", "Medium", "Hard" };

В обработчике нажатия кнопки вызываем диалоговое окно:


if (view.getId() == R.id.play_btn) {
	// play button
	AlertDialog.Builder builder = new AlertDialog.Builder(this);
	builder.setTitle("Choose a level").setSingleChoiceItems(levelNames,
			0, new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
					// start gameplay
					startPlay(which);
				}
			});
    AlertDialog ad = builder.create();
    ad.show();        
}

И добавим метод startPlay(), в котором будем запускать нужную активность и передавать выбранный уровень сложности.


private void startPlay(int chosenLevel) {
	// start gameplay
	Intent playIntent = new Intent(this, PlayGameActivity.class);
	playIntent.putExtra("level", chosenLevel);
	this.startActivity(playIntent);
}

Перейдём к активности PlayGameActivity. Зададим несколько переменных и констант класса:


private int level = 0, answer = 0, operator = 0, operand1 = 0,
		operand2 = 0;
private final int ADD_OPERATOR = 0, SUBTRACT_OPERATOR = 1,
		MULTIPLY_OPERATOR = 2, DIVIDE_OPERATOR = 3; 
private String[] operators = { "+", "-", "x", "/" };        

Далее создадим двухмерный массив:


private int[][] levelMin = { { 1, 11, 21 }, { 1, 5, 10 }, { 2, 5, 10 },
		{ 2, 3, 5 } };
private int[][] levelMax = { { 10, 25, 50 }, { 10, 20, 30 }, { 5, 10, 15 },
		{ 10, 50, 100 } };

Также нам понадобится переменная для генерации случайного числа.


private Random random;

Объявим все используемые компоненты и инициализируем их в методе onCreate(). Там же получим передаваемый уровень сложности


Bundle extras = getIntent().getExtras();
if (extras != null) {
	int passedLevel = extras.getInt("level", -1);
	if (passedLevel >= 0)
		level = passedLevel;
}

Напишем вспомогательный метод chooseQuestion(), который позволит выбирать вопрос, а также метод getOperand().


private void chooseQuestion() {
	// get a question
	answerTxt.setText("= ?");
	operator = random.nextInt(operators.length);
	operand1 = getOperand();
	operand2 = getOperand();
    
    if (operator == SUBTRACT_OPERATOR) {
		while (operand2 > operand1) {
			operand1 = getOperand();
			operand2 = getOperand();
		}
	} else if (operator == DIVIDE_OPERATOR) {
		while ((((double) operand1 / (double) operand2) % 1 > 0)
				|| (operand1 == operand2)) {
			operand1 = getOperand();
			operand2 = getOperand();
		}
	}
    
    switch (operator) {
	case ADD_OPERATOR:
		answer = operand1 + operand2;
		break;
	case SUBTRACT_OPERATOR:
		answer = operand1 - operand2;
		break;
	case MULTIPLY_OPERATOR:
		answer = operand1 * operand2;
		break;
	case DIVIDE_OPERATOR:
		answer = operand1 / operand2;
		break;
	default:
		break;
	}
    
    question.setText(operand1 + " " + operators[operator] + " " + operand2);
}

private int getOperand() {
	// return operand number
	return random.nextInt(levelMax[operator][level]
			- levelMin[operator][level] + 1)
			+ levelMin[operator][level];
}

Теперь надо обрабатывать нажатия кнопок. Полностью код класса активности будет следующим.


package ru.alexanderklimov.mathgame;

import java.util.Random;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class PlayGameActivity extends Activity implements OnClickListener {

	private int level = 0, answer = 0, operator = 0, operand1 = 0,
			operand2 = 0;
	private final int ADD_OPERATOR = 0, SUBTRACT_OPERATOR = 1,
			MULTIPLY_OPERATOR = 2, DIVIDE_OPERATOR = 3;
	private String[] operators = { "+", "-", "x", "/" };

	private int[][] levelMin = { { 1, 11, 21 }, { 1, 5, 10 }, { 2, 5, 10 },
			{ 2, 3, 5 } };
	private int[][] levelMax = { { 10, 25, 50 }, { 10, 20, 30 }, { 5, 10, 15 },
			{ 10, 50, 100 } };

	private Random random;

	private TextView question, answerTxt, scoreTxt;
	private ImageView response;
	private Button btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0,
			enterBtn, clearBtn;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_playgame);

		question = (TextView) findViewById(R.id.question);
		answerTxt = (TextView) findViewById(R.id.answer);
		response = (ImageView) findViewById(R.id.response);
		scoreTxt = (TextView) findViewById(R.id.score);
		response.setVisibility(View.INVISIBLE);
		btn1 = (Button) findViewById(R.id.btn1);
		btn2 = (Button) findViewById(R.id.btn2);
		btn3 = (Button) findViewById(R.id.btn3);
		btn4 = (Button) findViewById(R.id.btn4);
		btn5 = (Button) findViewById(R.id.btn5);
		btn6 = (Button) findViewById(R.id.btn6);
		btn7 = (Button) findViewById(R.id.btn7);
		btn8 = (Button) findViewById(R.id.btn8);
		btn9 = (Button) findViewById(R.id.btn9);
		btn0 = (Button) findViewById(R.id.btn0);
		enterBtn = (Button) findViewById(R.id.enter);
		clearBtn = (Button) findViewById(R.id.clear);
		btn1.setOnClickListener(this);
		btn2.setOnClickListener(this);
		btn3.setOnClickListener(this);
		btn4.setOnClickListener(this);
		btn5.setOnClickListener(this);
		btn6.setOnClickListener(this);
		btn7.setOnClickListener(this);
		btn8.setOnClickListener(this);
		btn9.setOnClickListener(this);
		btn0.setOnClickListener(this);
		enterBtn.setOnClickListener(this);
		clearBtn.setOnClickListener(this);

		Bundle extras = getIntent().getExtras();
		if (extras != null) {
			int passedLevel = extras.getInt("level", -1);
			if (passedLevel >= 0)
				level = passedLevel;
		}

		random = new Random();
		chooseQuestion();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.play_game, menu);
		return true;
	}

	@Override
	public void onClick(View view) {
		// TODO Auto-generated method stub
		if (view.getId() == R.id.enter) {
			// enter button
			String answerContent = answerTxt.getText().toString();
			if(!answerContent.endsWith("?"))
			{
			    //we have an answer
				int enteredAnswer = Integer.parseInt(answerContent.substring(2));
				int exScore = getScore();
				if(enteredAnswer==answer){
				    //correct
					scoreTxt.setText("Score: "+(exScore+1));
					response.setImageResource(R.drawable.tick);
					response.setVisibility(View.VISIBLE);
				}else{
				    //incorrect
					scoreTxt.setText("Score: 0");
					response.setImageResource(R.drawable.cross);
					response.setVisibility(View.VISIBLE);
				}
				chooseQuestion();
			}
		} else if (view.getId() == R.id.clear) {
			// clear button
			answerTxt.setText("= ?");
		} else {
			// number button
			response.setVisibility(View.INVISIBLE);
			int enteredNum = Integer.parseInt(view.getTag().toString());
			if (answerTxt.getText().toString().endsWith("?"))
				answerTxt.setText("= " + enteredNum);
			else
				answerTxt.append("" + enteredNum);
		}
	}

	private void chooseQuestion() {
		// get a question
		answerTxt.setText("= ?");
		operator = random.nextInt(operators.length);
		operand1 = getOperand();
		operand2 = getOperand();

		if (operator == SUBTRACT_OPERATOR) {
			while (operand2 > operand1) {
				operand1 = getOperand();
				operand2 = getOperand();
			}
		} else if (operator == DIVIDE_OPERATOR) {
			while ((((double) operand1 / (double) operand2) % 1 > 0)
					|| (operand1 == operand2)) {
				operand1 = getOperand();
				operand2 = getOperand();
			}
		}

		switch (operator) {
		case ADD_OPERATOR:
			answer = operand1 + operand2;
			break;
		case SUBTRACT_OPERATOR:
			answer = operand1 - operand2;
			break;
		case MULTIPLY_OPERATOR:
			answer = operand1 * operand2;
			break;
		case DIVIDE_OPERATOR:
			answer = operand1 / operand2;
			break;
		default:
			break;
		}

		question.setText(operand1 + " " + operators[operator] + " " + operand2);
	}

	private int getOperand() {
		// return operand number
		return random.nextInt(levelMax[operator][level]
				- levelMin[operator][level] + 1)
				+ levelMin[operator][level];
	}
	
	private int getScore(){
	    String scoreStr = scoreTxt.getText().toString();
	    return Integer.parseInt(scoreStr.substring(scoreStr.lastIndexOf(" ")+1));
	}
}

На данном этапе можно уже поиграть.

Поработаем теперь с таблицей рекордов, за которую отвечает класс HighScoresActivity.

Для начала в классе PlayGameActivity напишем код, сохраняющий результат. Добавим две новые переменные:


private SharedPreferences gamePrefs;
public static final String GAME_PREFS = "ArithmeticFile";

В методе onCreate() сразу после загрузки разметки добавим строку кода:


setContentView(R.layout.activity_playgame);
// Добавьте эту строчку
gamePrefs = getSharedPreferences(GAME_PREFS, 0);

Подготовим новый метод для работы с результатами:


private void setHighScore() {
	// set high score
	int exScore = getScore();
	if (exScore > 0) {
		SharedPreferences.Editor scoreEdit = gamePrefs.edit();
		DateFormat dateForm = new SimpleDateFormat("dd MMMM yyyy");
		String dateOutput = dateForm.format(new Date());
		String scores = gamePrefs.getString("highScores", "");

		if (scores.length() > 0) {
			// we have existing scores
			List<Score> scoreStrings = new ArrayList<Score>();
			String[] exScores = scores.split("\\|");
			for (String eSc : exScores) {
				String[] parts = eSc.split(" - ");
				scoreStrings.add(new Score(parts[0], Integer
						.parseInt(parts[1])));
			}

			Score newScore = new Score(dateOutput, exScore);
			scoreStrings.add(newScore);
			Collections.sort(scoreStrings);

			StringBuilder scoreBuild = new StringBuilder("");
			for (int s = 0; s < scoreStrings.size(); s++) {
				if (s >= 10)
					break;// only want ten
				if (s > 0)
					scoreBuild.append("|");// pipe separate the score
											// strings
				scoreBuild.append(scoreStrings.get(s).getScoreText());
			}
			// write to prefs
			scoreEdit.putString("highScores", scoreBuild.toString());
			scoreEdit.commit();
		} else {
			// no existing scores
			scoreEdit.putString("highScores", "" + dateOutput + " - "
					+ exScore);
			scoreEdit.commit();
		}
	}
}    

Метод записывает новый результат в файл настроек, если результатов ещё нет. Если результаты уже есть, то устраивается небольшая проверка. Если новый результат лучше, чем один из десяти предыдущих результатов, то он обновляется. Для удобства создаётся отдельный класс Score.


package ru.alexanderklimov.mathgame;

public class Score implements Comparable<Score> {
	private String scoreDate;
	public int scoreNum;

	public Score(String date, int num) {
		scoreDate = date;
		scoreNum = num;
	}

	public int compareTo(Score sc) {
		// return 0 if equal
		// 1 if passed greater than this
		// -1 if this greater than passed
		return sc.scoreNum > scoreNum ? 1 : sc.scoreNum < scoreNum ? -1 : 0;
	}

	public String getScoreText() {
		return scoreDate + " - " + scoreNum;
	}
}

Применим написанный метод записи результатов в блок else у кнопки Enter перед сбросом результатов:


setHighScore();
scoreTxt.setText("Score: 0");

А также запишем результат при уничтожении активности.


protected void onDestroy() {
	setHighScore();
	super.onDestroy();
}

Чтобы данные не терялись при поворотах, добавим в манифест небольшую защиту:


<activity
    android:name="ru.alexanderklimov.mathgame.PlayGameActivity"
    android:configChanges="keyboardHidden|orientation|screenSize"
    android:label="@string/title_activity_play_game" >

Для сохранения результатов между различными состояниями активности добавим код:


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
	// save state
	int exScore = getScore();
	savedInstanceState.putInt("score", exScore);
	savedInstanceState.putInt("level", level);
	super.onSaveInstanceState(savedInstanceState);
}

Соответственно, в onCreate() нужно восстановить данные. Заменим один фрагмент кода на другой.


// Bundle extras = getIntent().getExtras();
// if (extras != null) {
// int passedLevel = extras.getInt("level", -1);
// if (passedLevel >= 0)
// level = passedLevel;
// }

if (savedInstanceState != null) {
	// restore state
    level = savedInstanceState.getInt("level");
	int exScore = savedInstanceState.getInt("score");
	scoreTxt.setText("Score: " + exScore);
} else {
	Bundle extras = getIntent().getExtras();
	if (extras != null) {
		int passedLevel = extras.getInt("level", -1);
		if (passedLevel >= 0)
			level = passedLevel;
	}
}

С этой активностью закончили. Теперь поработаем над активностью таблицы рекордов. Для просмотра таблицы нам нужно попасть на этот экран с первой активности.


else if (view.getId() == R.id.high_btn) {
	// high scores button
	Intent highIntent = new Intent(this, HighScoresActivity.class);
	this.startActivity(highIntent);
}

Открываем код активности HighScoresActivity. При загрузке активности нам нужно извлечь результаты из файла настроек и вывести их на экран.


@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_high);

	TextView scoreView = (TextView) findViewById(R.id.high_scores_list);
	SharedPreferences scorePrefs = getSharedPreferences(
			PlayGameActivity.GAME_PREFS, 0);
	String[] savedScores = scorePrefs.getString("highScores", "").split(
			"\\|");
	StringBuilder scoreBuild = new StringBuilder("");
	for (String score : savedScores) {
		scoreBuild.append(score + "\n");
	}
	scoreView.setText(scoreBuild.toString());
}

Игра готова. Осталось только запустить активность с правилами игры.


else if (view.getId() == R.id.help_btn) {
	// how to play button
	Intent helpIntent = new Intent(this, HowToPlayActivity.class);
	this.startActivity(helpIntent);
}

По мотивам цикла статей Android SDK: Create an Arithmetic Game - Setup and Interface Creation с небольшими изменениями. Там же можно скачать исходники.

Реклама