Форум программистов, компьютерный форум, киберфорум
Lisishkas
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

Игрушка

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

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

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

Только сильно не критикуйте(можно мягко и действительно в тему что и как "не то"), ОК?
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 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 вне форума
 
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru