Существует множество вариаций этой игры, но как ее сделать самому — это совершенно другое, но на самом деле очень просто и не трудно.
Мой вариант это Android — самый простой способ написать мобильное приложение. Все писалось на скорую руку, без какой-либо подготовки, то есть все просто — захотел, сел написал. Поэтому некоторый код может быть выглядеть очень бредово и нелепо, но на то он и скелет — просто суть, без красоты 🙂
Структура базы
Данные любой игры необходимо хранить. Большой плюс платформы Android это возможность работы с базой SQLite — на ней и будет работать игра. Схема мне виделась такой — две таблицы, в одной список элементов, в другой список рецептов (упростим возможно задачу, но в рецепте только два элемента)
alchemyEngine
Теперь необходимо реализовать класс для работы с этой базой — самое первое объявим все необходимые процедуры
private static final int DB_VERSION = 1; private static final String DB_NAME = Environment.getExternalStorageDirectory().getPath() +"/Alchemy/alchemy.db"; public alchemyEngine(Context context){ super(context, DB_NAME, null, DB_VERSION); }
Тут все понятно — версия БД и путь к БД.
Для примера работы в базе будут следующие элементы:
1. name1
2. name2
3. name3
4. name4
5. name5
6. name6
Причем name1 и name2 будут доступны сразу и это именно их надо смешивать, для получения других элементов.
Теперь рецепты — они будут такие:
1. name1 + name2 = name4
2. name1 + name4 = name3
3. name3 + name1 = name6 + name5
А процедура onCreate, в которой будет создаваться база будет иметь такой код:
public void onCreate(SQLiteDatabase db) { String QUERY; QUERY = "CREATE TABLE elements(" + "_id INTEGER PRIMARY KEY," + "name TEXT NOT NULL," + "open INTEGER NOT NULL);"; db.execSQL(QUERY); QUERY = "CREATE TABLE receptions(" + "_id INTEGER PRIMARY KEY," + "el1_id INTEGER NOT NULL," + "el2_id INTEGER NOT NULL," + "result_id INTEGER NOT NULL);"; db.execSQL(QUERY); //// Elements // name1, name2, name3, name4, name5, name6 QUERY = "INSERT INTO elements(name, open) VALUES('name1', 1);"; db.execSQL(QUERY); QUERY = "INSERT INTO elements(name, open) VALUES('name2', 1);"; db.execSQL(QUERY); QUERY = "INSERT INTO elements(name, open) VALUES('name3', 0);"; db.execSQL(QUERY); QUERY = "INSERT INTO elements(name, open) VALUES('name4', 0);"; db.execSQL(QUERY); QUERY = "INSERT INTO elements(name, open) VALUES('name5', 0);"; db.execSQL(QUERY); QUERY = "INSERT INTO elements(name, open) VALUES('name6', 0);"; db.execSQL(QUERY); //// Receptions // name1 + name2 = name4 // name1 + name4 = name3 // name3 + name1 = name6 + name5 // QUERY = "INSERT INTO receptions(el1_id, el2_id, result_id) VALUES(1, 2, 4);"; db.execSQL(QUERY); QUERY = "INSERT INTO receptions(el1_id, el2_id, result_id) VALUES(1, 4, 3);"; db.execSQL(QUERY); QUERY = "INSERT INTO receptions(el1_id, el2_id, result_id) VALUES(3, 1, 6);"; db.execSQL(QUERY); QUERY = "INSERT INTO receptions(el1_id, el2_id, result_id) VALUES(3, 1, 5);"; db.execSQL(QUERY); }
Выбор элементов для смешивания будет реализован через Spinner (это же скелет). В него будут выводиться лишь строковые названия элементов, а смешивать будет по ID этих элементов — поэтому необходимо добавить две процедуры для поиска имени по ID и поиска ID по имени
public int getIDbyName(String name){ int id = 0; SQLiteDatabase db = this.getReadableDatabase(); Cursor c = db.rawQuery("SELECT _id FROM elements WHERE name = '" + name.trim() + "'", null); c.moveToNext(); id = c.getInt(0); return id; } public String getNameByID(int id){ String name = ""; SQLiteDatabase db = this.getReadableDatabase(); Cursor c = db.rawQuery("SELECT name FROM elements WHERE _id = " + String.valueOf(id)+ ";", null); c.moveToNext(); name = c.getString(0); return name; }
Теперь осталось лишь реализовать процедуры для «открытия» элемента (проставление у стоблца open значения 1)
public void openElement(int id){ SQLiteDatabase db = this.getWritableDatabase(); String QUERY = "UPDATE elements SET open = 1 WHERE _id = " + String.valueOf(id) + ";"; db.execSQL(QUERY); }
И самая основная функция — соединение элементов. Функция будет возвращать список, а не просто ID элемента. Все потому что мы можешь «смешать» два элемента, а получить не один, а два или три (смотри Рецепт #3)
public List<String> mixUp(int id1, int id2) { List<String> elementsList = new ArrayList<String>(); String QUERY = "SELECT result_id FROM receptions WHERE (el1_id = " +String.valueOf(id1) + " AND el2_id = " + String.valueOf(id2) + ") OR (el1_id = " +String.valueOf(id2) + " AND el2_id = " + String.valueOf(id1) + ")"; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(QUERY, null); if(cursor.moveToFirst()){ do { elementsList.add(cursor.getString(0)); }while(cursor.moveToNext()); } return elementsList; }
И само собой нужна функция для вывода списка доступных элементов, которая будет формировать список имен этих элементов
public List<String> elementesList() { List<String> elementsList = new ArrayList<String>(); String SelectQuery = "SELECT _id, name FROM elements WHERE open = 1"; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(SelectQuery, null); if(cursor.moveToFirst()){ do { elementsList.add(cursor.getString(1)); }while(cursor.moveToNext()); } return elementsList; }
На это процедуры и функции класса alchemyEngine закончились.
Теперь необходимо описать Activity и все — игра готова 🙂
Activity
Как было сказано выше, на форме будет два Spinner и одна кнопка — в spinner будет выводиться имя элемента, а по нажатию на кнопку будет происходить «смешивание» элементов из обоих spinner. И лучше и проще через Toast вывести результаты этого смешивания.
Для каждого spinner напишем две процедуры для обновления данных в них:
public void _updateSpinner1(){ List<String> elementsList = new ArrayList<String>(); elementsList = engine.elementesList(); Spinner my_spin = (Spinner)findViewById(R.id.spinner1); my_spin.setOnItemSelectedListener(this); ArrayAdapter<String> aa = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, elementsList); aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); my_spin.setAdapter(aa); } public void _updateSpinner2(){ List<String> elementsList = new ArrayList<String>(); elementsList = engine.elementesList(); Spinner my_spin = (Spinner)findViewById(R.id.spinner2); my_spin.setOnItemSelectedListener(this); ArrayAdapter<String> aa = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, elementsList); aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); my_spin.setAdapter(aa); }
Для работы со spinner у нас одна процедура onItemSelected, но она должна обрабатывать сразу два spinner — я нашел такой способ для решения этой задачи:
public void onItemSelected(AdapterView<?> parent, View arg1, int pos, long arg3) { Spinner spinner = (Spinner) parent; if(spinner.getId() == R.id.spinner1) { element1 = spinner.getSelectedItem().toString(); } else if(spinner.getId() == R.id.spinner2) { element2 = spinner.getSelectedItem().toString(); } }
И осталась сама я важная процедура — «смешивание» элементов.
Суть простая — берем имена из spinner перегоняем их в ID этих элементов, вызываем процедуру mixUp, в которую передаем два ID элементов и в ответ получаем список новых полученных элементов…или ничего. Код такой:
public void mixElements(View v){ int id1 = engine.getIDbyName(element1); int id2 = engine.getIDbyName(element2); String out = ""; mixEl = new ArrayList<String>(); mixEl = engine.mixUp(id1, id2); if(mixEl.isEmpty()){ Toast toast = Toast.makeText(getApplicationContext(), "Ничего не получилось!", Toast.LENGTH_SHORT); toast.show(); } else { for (String temp : mixEl) { int el_id = Integer.parseInt(temp); engine.openElement(el_id); String elName = engine.getNameByID(el_id); out = out + elName + " "; } Toast toast = Toast.makeText(getApplicationContext(), "Получились элементы: " + out, Toast.LENGTH_SHORT); toast.show(); _updateSpinner1(); _updateSpinner2(); } }
На этом получается вроде все. Основные моменты описаны, как и сама идея. Скачать архив с исходниками можно тут.
Всем успехов 😉