Форум программистов, компьютерный форум, киберфорум
Наши страницы
Lisishkas
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Игрушка

Запись от Lisishkas размещена 02.08.2019 в 23:13

Всем доброго времени суток, решил опробовать блогерство.

Так вот, стоя ехал в общественном транспорте, смотрел как чудак режется в игру какую-то.
Потом вспомнил через время об этой игре и решил узнать насколько такая игра увлекательна. Написал свой вариант, чисто "для себя" и по мотивам.
Ради спортивного интереса.
Назвал её "nums".

Как играть: стрелками влево-вправо-вверх-вниз(или клавишами ASDE) сдвигаете все числа к стенке поля(нажали вверх - значит к верхней и т.д.). Если два одинаковых числа встречаются - они суммируются. Тип того.

Выложу исходник, писалось по-быстрячку и "для себя" - я уже когда "нарезался", потом чуть-чуть поправил код и дописал немного комментариев - вдруг кто-то заюсает и будет счастлив.

Что нужно для сборки: язык C#, NF ~3.5. Создаем проект, в нем "грохаем" файлы сгенерированные для Form, открываем Program.cs, вставляем туда код и запускаем. Примерно так.

[CSHARP]using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace nums
{
partial class Program : Form
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Program());
}

static int
H = 4, // клеток 4х4
S = 60; // сторона клетки в пикселах

int CH = SystemInformation.CaptionHeight + 10; // высота заголовка формы + отступ
int FBS = SystemInformation.FrameBorderSize.Width; // ширина границы формы

Random rand = new Random();
int[,] map; // массив значений в клетках
int score; // очки
int[] nums = {2, 4, 8}; // появляющиеся числа
int start_nums_count = 3; // количество чисел вначале

Font font = new Font("Times", 18);

[Serializable]
public class record // класс рекорда
{
public int score; // очки
public DateTime dt = DateTime.Now; // время
public record(int score)
{
this.score = score;
}
}
List<record> records = new List<record>(); // рекорды
int max_records = 10; // максимально сохранять рекордов
string file_name = Application.StartupPath + "/rec.bin"; // файл для сохранения рекордов

Program()
{
InitializeComponent();
this.Text = "nums";

this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.StartPosition = FormStartPosition.CenterScreen;
this.MaximizeBox = false;
this.DoubleBuffered = true;

this.ClientSize = new Size(2 * FBS + H * S, FBS + CH + H * S);

this.Paint += new PaintEventHandler(Program_Paint);
this.KeyUp += new KeyEventHandler(Program_KeyUp);

Init();

LoadRecords();
}

void Init()
{
map = new int[H, H];
AddNum(start_nums_count);
score = 0;
}

void AddNum(int count)
{
for (int i = 0; i < count; i++)
{
int j = H * H * 10;
do {
int x = rand.Next(H);
int y = rand.Next(H);
if (map[x, y] == 0)
{
map[x, y] = nums[rand.Next(0, nums.Length)];
break;
}
}while (j-->0);
}
}

void Program_KeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyData)
{
case Keys.Up:
case Keys.W:
for (int z = 0; z < H; z++)
for (int i = 0; i < H; i++)
{
for (int j = 1; j < H; j++)
{
if (map[i, j - 1] == 0)
{
map[i, j - 1] = map[i, j];
map[i, j] = 0;
}
else if (map[i, j - 1] == map[i, j])
{
score += map[i, j];
map[i, j - 1] <<= 1;
map[i, j] = 0;
}
}
Foo();
}
break;
case Keys.Right:
case Keys.D:
for (int z = 0; z < H; z++)
for (int j = 0; j < H; j++)
{
for (int i = H - 2; i >= 0; i--)
{
if (map[i + 1, j] == 0)
{
map[i + 1, j] = map[i, j];
map[i, j] = 0;
}
else if (map[i + 1, j] == map[i, j])
{
score += map[i, j];
map[i + 1, j] <<= 1;
map[i, j] = 0;
}
}
Foo();
}
break;
case Keys.Down:
case Keys.S:
for (int z = 0; z < H; z++)
for (int i = 0; i < H; i++)
{
for (int j = H - 2; j >= 0; j--)
{
if (map[i, j + 1] == 0)
{
map[i, j + 1] = map[i, j];
map[i, j] = 0;
}
else if (map[i, j + 1] == map[i, j])
{
score += map[i, j];
map[i, j + 1] <<= 1;
map[i, j] = 0;
}
}
Foo();
}
break;
case Keys.Left:
case Keys.A:
for (int z = 0; z < H; z++)
for (int j = 0; j < H; j++)
{
for (int i = 1; i < H; i++)
{
if (map[i - 1, j] == 0)
{
map[i - 1, j] = map[i, j];
map[i, j] = 0;
}
else if (map[i - 1, j] == map[i, j])
{
score += map[i, j];
map[i - 1, j] <<= 1;
map[i, j] = 0;
}
}
Foo();
}
break;
case Keys.Escape:
this.Close();
break;
case Keys.F1:
ShowRecords();
break;
default:
return;
}
AddNum(1);
Invalidate();

if (IsEnd())
{
AddAndSaveRecords(score);
ShowRecords();
Init();
Invalidate();
}
}

bool IsEnd()
{
//пустые поля
for (int i = 0; i < H; i++)
for (int j = 0; j < H; j++)
if (map[i, j] == 0)
return false;

//рядом одинаковые
for (int i = 0; i < H; i++)
for (int j = 1; j < H; j++)
if (map[i, j - 1] == map[i, j])
return false;
for (int i = 1; i < H; i++)
for (int j = 0; j < H; j++)
if (map[i - 1, j] == map[i, j])
return false;

return true;
}

void Foo()
{
//здесь может будет логика отрисовки
System.Threading.Thread.Sleep(5 / H); // при больших H закомментировать
Invalidate();
Application.DoEvents();
}

void AddAndSaveRecords(int score)
{
records.Add(new record(score));
records.Sort(delegate(record r1, record r2)
{
return r2.score.CompareTo(r1.score);
});
if (records.Count > max_records)
records.RemoveRange(max_records, records.Count - max_records);
using (Stream stream = new FileStream(file_name, FileMode.Create, FileAccess.Write, FileShare.None))
new BinaryFormatter().Serialize(stream, records);
}

void LoadRecords()
{
if (File.Exists(file_name))
{
using (Stream stream = new FileStream(file_name, FileMode.Open, FileAccess.Read, FileShare.None))
records = (List<record>)new BinaryFormatter().Deserialize(stream);
}
}

void ShowRecords()
{
string str = "Вы набрали " + score.ToString() + " очков";
if (records.Count > 0)
{
str += "\n\r\n\rТаблица рекордов:";
for (int i = 0; i < records.Count; i++)
{
str += "\n\r" + records[i].score.ToString() + "\t" + records[i].dt.ToString("dd-MM-yyyy HH:mm");
}
}
MessageBox.Show(str);
}

void Program_Paint(object sender, PaintEventArgs e)
{
// сетка
for(int i = 0; i <= H; i++)
e.Graphics.DrawLine(new Pen(Color.Black), FBS + i * S, CH, FBS + i * S, CH + H * S);
for (int j = 0; j <= H; j++)
e.Graphics.DrawLine(new Pen(Color.Black), FBS, CH + j * S, FBS + H * S, CH + j * S);

// числа
for (int i = 0; i < H; i++)
for (int j = 0; j < H; j++)
if (map[i, j] != 0)
{
SizeF sf = e.Graphics.MeasureString(map[i, j].ToString(), font);
e.Graphics.DrawString(map[i, j].ToString(), font, Brushes.Blue
, FBS + i * S + (S - sf.Width) / 2, CH + j * S + (S - sf.Height) / 2);
}
// очки
e.Graphics.DrawString("Очки - " + score.ToString(), font, Brushes.Blue, FBS, 0);
}

private void InitializeComponent()
{
this.SuspendLayout();
//
// Program
//
this.ResumeLayout(false);
}
}
}[/CSHARP]

Только сильно не критикуйте(можно мягко и действительно в тему что и как "не то"), ОК?
Размещено в Без категории
Просмотров 327 Комментарии 4
Всего комментариев 4
Комментарии
  1. Старый комментарий
    Аватар для SoftIce
    Это называется 2048.

    Правила

    Цитата:
    В каждом раунде появляется плитка номинала «2» (с вероятностью 90%) или «4» (с вероятностью 10%)[11]
    Нажатием стрелки игрок может скинуть все плитки игрового поля в одну из 4 сторон. Если при сбрасывании две плитки одного номинала «налетают» одна на другую, то они слипаются в одну, номинал которой равен сумме соединившихся плиток. После каждого хода на свободной секции поля появляется новая плитка номиналом «2» или «4». Если при нажатии кнопки местоположение плиток или их номинал не изменится, то ход не совершается.
    Если в одной строчке или в одном столбце находится более двух плиток одного номинала, то при сбрасывании они начинают слипаться с той стороны, в которую были направлены. Например, находящиеся в одной строке плитки (4, 4, 4) после хода влево они превратятся в (8, 4), а после хода вправо — в (4, 8). Данная обработка неоднозначности позволяет более точно формировать стратегию игры.
    За каждое соединение игровые очки увеличиваются на номинал получившейся плитки.
    Игра заканчивается поражением, если после очередного хода невозможно совершить действие.
    Запись от SoftIce размещена 03.08.2019 в 06:14 SoftIce вне форума
  2. Старый комментарий
    Спасибо что разъяснил.

    Тогда моя реализация отличается от 2048, и\или имеет свои особенности и плюшки:
    1) Нет таймера - сколько угодно можно думать над ходом.(отвлекли - через время вернулся и продолжил)
    2) Практически равновероятно появляются 2, 4, 8.(Не тестил, но думаю легко можно сделать только 2 и 4). Можно хоть и 1,3,7 сделать - такое тестил.
    3) Параметром H меняется размер поля: H=4 - значит 4х4, 10 - значит 10х10. (Понравились "блицы" 2х2 и 3х3).
    4) За один ход собираются, например, 4-2-2-8 в 16, хоть влево хоть вправо.
    5) "Если при нажатии кнопки местоположение плиток или их номинал не изменится, то ход не совершается." - а смысл? Тогда можно жамкать одну кнопку и новые числа не будут появляться.

    Запускал на исполнение?

    [B]SoftIce[/B],
    Как код и стиль программирования, потянет? Я просто программист-одиночка и один на предприятии, коллег программистов нет(1С-ники есть, но...).


    Есть смысл продолжать блоггерство?
    Например, для решатора яп. кроссвордов еще один блок нужно прописать, чтоб решал и 5-го уровня. 1-4 решает норм. Нужно добавить еще один алгоритм. Когда добавлю, выложить?
    Запись от Lisishkas размещена 03.08.2019 в 17:08 Lisishkas вне форума
  3. Старый комментарий
    Аватар для SoftIce
    Цитата:
    Запускал на исполнение?
    Да, запускал.

    Цитата:
    "Если при нажатии кнопки местоположение плиток или их номинал не изменится, то ход не совершается." - а смысл? Тогда можно жамкать одну кнопку и новые числа не будут появляться.
    Смысл в том, что если на поле ничего не изменилось, то не должны фишки появляться. Я вот запустил, пару раз промахнулся мимо клавиши, нажал не туда, и на поле появилось 4 лишние плитки, что совсем не добавляет интереса к игре, а вызывает раздражение и недоумение.
    Извините, написал с точки зрения обычного пользователя.
    Запись от SoftIce размещена 04.08.2019 в 17:31 SoftIce вне форума
  4. Старый комментарий
    [QUOTE=SoftIce;bt22249]Да, запускал.

    Смысл в том, что если на поле ничего не изменилось, то не должны фишки появляться. Я вот запустил, пару раз промахнулся мимо клавиши, нажал не туда, и на поле появилось 4 лишние плитки, что совсем не добавляет интереса к игре, а вызывает раздражение и недоумение.
    Извините, написал с точки зрения обычного пользователя.[/QUOTE]
    Спасибо за тест.

    [QUOTE=SoftIce;bt22249]Смысл в том, что если на поле ничего не изменилось, то не должны фишки появляться.[/QUOTE]
    Если все фишки стоят возле правой границы и ты не хочешь, менять их расположение - логично для появления новой фишки нажать "->". И новые фишки появляются, да.

    Еще раз напомню, это не Бест-версия в продакшн, написано ради спортивного интереса.
    Попробую пофиксить, если пойму прикол. Я здесь поставил себе лимит - уложиться в 300 строк.

    И вообще это кроме типа NDA по работе - просто баловство(Если интересуетесь не с точки зрения простого юзера). Ну, тип того :).

    А как "код" - читаемый? Не говнокодище часом? Вот здесь хотелось бы вашу рецензию.
    Запись от Lisishkas размещена 16.08.2019 в 21:33 Lisishkas вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru