added double jump and sitting state

master
nihonium 2 years ago
parent 2e5c5a8dde
commit 90d07dde3f
No known key found for this signature in database
GPG Key ID: 0251623741027CFC

Binary file not shown.

@ -0,0 +1,14 @@
#include <iostream>
using std::cout;
namespace myspace {
void print_n_times(char str[], int n = 10) {
for (int i = 0; i < n; ++i)
cout << str;
}
}
int main() {
char s[] = "nya\n";
myspace::print_n_times(s);
}

@ -0,0 +1,11 @@
#include <iostream>
using std::cout, std::endl;
int cubeV(int x) {
return x * x * x;
}
int main() {
int x = 3;
cout << cubeV(x) << endl;
}

@ -0,0 +1,12 @@
#include <iostream>
using std::cout, std::endl;
int cubeR(int& x) {
return x * x * x;
}
int main() {
int x = 3;
cout << cubeR(x) << endl;
}

@ -0,0 +1,26 @@
#include <iostream>
using std::cout, std::endl;
void count_letters(char str[], int& n_letters, int& n_digits, int& n_other) {
while (*str) {
if (*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z') {
n_letters += 1;
}
else if (*str >= '0' && *str <= '9') {
n_digits += 1;
}
else {
n_other += 1;
}
str += 1;
}
}
int main() {
int n_letters = 0, n_digits = 0, n_other = 0;
char s[] = "1n!2y#3a$";
count_letters(s, n_letters, n_digits, n_other);
cout << "letters: " << n_letters << endl << "digits: " << n_digits << endl << "n_other: " << n_other << endl;
}

@ -0,0 +1,20 @@
#include <iostream>
using std::cout, std::endl;
struct Book {
char title[100];
int pages;
float price;
};
void addPrice(Book& b, float x) {
b.price += x;
}
int main() {
Book b = {"One Hundred Years of Solitude", 456, 1200};
float x = 15.6;
addPrice(b, x);
cout << b.price << endl;
}

@ -0,0 +1,20 @@
#include <iostream>
using std::cout, std::endl;
struct Book {
char title[100];
int pages;
float price;
};
bool isExpensive(const Book& b) {
if (b.price > 1000) {
return true;
}
return false;
}
int main() {
Book b = {"One Hundred Years of Solitude", 456, 1200};
cout << isExpensive(b) << endl;
}

@ -0,0 +1,38 @@
#include <iostream>
#include "vector3f.h"
using namespace std;
int main() {
Vector3f a = {1.0, 2.0, -2.0};
Vector3f b = {4.0, -1.0, 3.0};
cout << "a = " << a << endl << "b = " << b << endl;
cout << "a + b = " << a + b << endl;
cout << "a - b = " << a - b << endl;
cout << "0.5 * a = " << 0.5 * a << endl;
cout << "a * 0.5 = " << a * 0.5 << endl;
cout << "(a, b) = " << a * b << endl;
cout << "a / 5 = " << a / 5 << endl;
cout << "-a = " << -a << endl;
cout << "+a = " << +a << endl;
cout << "a == b = " << (a == b) << endl;
cout << "a != b = " << (a != b) << endl;
a += b;
cout << "a += b: " << a << endl;
a -= b;
cout << "a -= b: " << a << endl;
a *= 2;
cout << "a *= 2: " << a << endl;
a /= 2;
cout << "a /= 2: " << a << endl;
normalize(a);
cout << "normalize(a): " << a << " |a| = " << norm(a) << endl;
}

@ -0,0 +1,96 @@
#pragma once
#include <cmath>
#include <iostream>
struct Vector3f {
float x;
float y;
float z;
};
Vector3f operator+(const Vector3f& a, const Vector3f& b) {
Vector3f result = {a.x + b.x, a.y + b.y, a.z + b.z};
return result;
}
Vector3f operator-(const Vector3f& a, const Vector3f& b) {
Vector3f result = {a.x - b.x, a.y - b.y, a.z - b.z};
return result;
}
Vector3f operator*(const Vector3f& a, float f) {
Vector3f result = {f * a.x, f * a.y, f * a.z};
return result;
}
Vector3f operator*(float f, const Vector3f& a) {
Vector3f result = {f * a.x, f * a.y, f * a.z};
return result;
}
int operator*(const Vector3f& a, const Vector3f& b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
Vector3f operator/(const Vector3f& a, float f) {
Vector3f result = {a.x / f, a.y / f, a.z / f};
return result;
}
Vector3f operator+(const Vector3f& a) {
return a;
}
Vector3f operator-(const Vector3f& a) {
Vector3f result = {-a.x, -a.y, -a.z};
return result;
}
bool operator==(const Vector3f& a, const Vector3f& b) {
if (a.x == b.x && a.y == b.y && a.z == b.z) {
return true;
}
return false;
}
bool operator!=(const Vector3f& a, const Vector3f& b) {
return not (a == b);
}
void operator+=(Vector3f& a, const Vector3f& b) {
a = a + b;
}
void operator-=(Vector3f& a, const Vector3f& b) {
a = a - b;
}
void operator*=(Vector3f& a, float f) {
a = f * a;
}
void operator/=(Vector3f& a, float f) {
a = a / f;
}
float squared_norm(const Vector3f& a) {
return a * a;
}
float norm(const Vector3f& a) {
return sqrt(squared_norm(a));
}
void normalize(Vector3f& a) {
a /= norm(a);
}
std::istream& operator>>(std::istream& in, Vector3f& a) {
in >> a.x >> a.y >> a.z;
return in;
}
std::ostream& operator<<(std::ostream& out, const Vector3f& a) {
out << "(" << a.x << ", " << a.y << ", " << a.z << ")";
return out;
}

@ -0,0 +1,189 @@
#pragma once
#include <cmath>
#include <iostream>
struct Complex {
float re;
float im;
};
// Передаёмм аргументы через ссылки
// В данном случае можно было передавать по значению
// (так как Complex имеет малый размер)
// Но в общем случае лучше для структур лучше
// всегда использовать ссылки
Complex operator+(const Complex& a, const Complex& b) {
Complex result = {a.re + b.re, a.im + b.im};
return result;
}
Complex operator-(const Complex& a, const Complex& b) {
Complex result = {a.re - b.re, a.im - b.im};
return result;
}
Complex operator*(const Complex& a, const Complex& b) {
Complex result = {a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re};
return result;
}
Complex operator/(const Complex& a, const Complex& b) {
float b_squared = b.re * b.re + b.im * b.im;
Complex result;
result.re = (a.re * b.re + a.im * b.im) / b_squared;
result.im = (a.im * b.re - a.re * b.im) / b_squared;
return result;
}
Complex& operator+=(Complex &a, const Complex &b) {
a.re += b.re;
a.im += b.im;
return a;
}
// Унарный оператор -
// То есть если z - комплексное число x + iy, то -z = - x - iy
Complex operator-(const Complex& a) {
Complex result;
result.re = -a.re;
result.im = -a.im;
return result;
}
// Унарный оператор +
// Ничего не меняет
Complex operator+(const Complex& a) {
Complex result = a;
return result;
}
// Унарный оператор *
// То есть если z - комплексное число x + iy, то *z = x - iy
// Оператор сопряжения
Complex operator*(const Complex& a) {
Complex result;
result.re = a.re;
result.im = -a.im;
return result;
}
// Число + комплексное число (в таком порядке)
Complex operator+(float a, const Complex& b) {
Complex result = b;
result.re += a;
return result;
}
// Комплексное число + число
Complex operator+(const Complex& a, float b) {
Complex result = a;
result.re += b;
return result;
}
// Число - комплексное число (в таком порядке)
Complex operator-(float a, const Complex& b) {
Complex result = -b;
result.re += a;
return result;
}
// Комплексное число - число
Complex operator-(const Complex& a, float b) {
Complex result = a;
result.re -= b;
return result;
}
// Комплексное число * число
Complex operator*(const Complex& a, float b) {
Complex result = a;
result.re *= b;
result.im *= b;
return result;
}
// Число * комплексное число
Complex operator*(float a, const Complex& b) {
Complex result = b;
result.re *= a;
result.im *= a;
return result;
}
// Комплексное число / число
Complex operator/(const Complex& a, float b) {
Complex result = a;
result.re /= b;
result.im /= b;
return result;
}
// Число / комплексное число
Complex operator/(float a, const Complex& b) {
float b_squared = b.re * b.re + b.im * b.im;
return (a * (*b)) / b_squared;
}
// Перегружаем оператор<< между типами
// std::ostream (такой тип имеет std::cout) и Complex
// Обратите внимание, что мы возвращаем ссылку на ostream
// Таким образом результатом выражения cout << a будет cout
// Поэтому можно делать так: cout << a << b << c ...
std::ostream& operator<<(std::ostream& out, const Complex& a) {
if (a.re != 0)
out << a.re;
if (a.im > 0) {
if (a.im != 1.0)
out << " + " << a.im << "i";
else
out << " + i";
}
else if (a.im < 0) {
if (a.im != -1.0)
out << " - " << -a.im << "i";
else
out << " - i";
}
return out;
}
std::istream& operator>>(std::istream& in, Complex& c) {
in >> c.re >> c.im;
return in;
}
float abs(const Complex& a) {
return sqrtf(a.re * a.re + a.im * a.im);
}
Complex exp(const Complex& a) {
Complex result;
result.re = expf(a.re) * cosf(a.im);
result.im = expf(a.re) * sinf(a.im);
return result;
}
Complex sin(const Complex& a) {
Complex result;
result.re = sinf(a.re) * coshf(a.im);
result.im = cosf(a.re) * sinhf(a.im);
return result;
}
Complex cos(const Complex& a) {
Complex result;
result.re = cosf(a.re) * coshf(a.im);
result.im = sinf(a.re) * sinhf(a.im);
return result;
}

@ -0,0 +1,56 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
// В этой программе мы рисуем в картинку комплексную функцию,
// которая задаётся в функции func
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z) {
Complex f = 100/(z - 1)*exp(z);
f.re = fabs(f.re);
f.im = fabs(f.im);
if (f.re > 255)
f.re = 255;
if (f.im > 255)
f.im = 255;
return f;
}
int main() {
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
// Выделяем память под пиксели
Color* data = (Color*)malloc(sizeof(Color) * width * height);
// data - это массив цветов размером width * height
// Задаём значения этого массива так, чтобы
// реальная часть функции func соответствовала зелёному цвету,
// а мнимая часть -- синей компоненте цвета
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
Complex z = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
Complex f = func(z);
data[i + width * j].r = 0;
data[i + width * j].g = f.re;
data[i + width * j].b = f.im;
}
}
// Сохраняем массив цветов data как картинку в формате .ppm
FILE* file = fopen("complex_image.ppm", "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
// Освобождаем память
free(data);
}

@ -0,0 +1,63 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
// Это программа создаёт анимацию (набор картинок)
// которая задаётся как меняющееся во времени
// комплексная функция (описана в функции func)
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z, int time) {
Complex f = 100/(z - (0.02f*time))*exp(z*sin(z));
f.re = fabs(f.re);
f.im = fabs(f.im);
if (f.re > 255)
f.re = 255;
if (f.im > 255)
f.im = 255;
return f;
}
int main() {
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
Color* data = (Color*)malloc(sizeof(Color) * width * height);
// Повторяем 200 раз
int max_time_steps = 200;
for (int time = 0; time < max_time_steps; time++)
{
// Задаём изображение в массиве data
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
Complex z = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
Complex f = func(z, time);
data[i + width * j].r = 0;
data[i + width * j].g = f.re;
data[i + width * j].b = f.im;
}
}
// Создаём в строке filename имя изображения
// Папка animation должна существовать!
char filename[100];
sprintf(filename, "animation/complex_%03d.ppm", time);
// Сохраняем изображение в картинке по имени filename
FILE* file = fopen(filename, "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
}
free(data);
}

@ -0,0 +1,38 @@
#include <iostream>
#include "complex.h"
using namespace std;
// Тут мы тестируем нашу реализацию комплексных чисел
int main() {
Complex a;
Complex b;
cin >> a >> b;
cout << "a = " << a << endl
<< "b = " << b << endl
<< "a + b = " << a + b << endl
<< "a - b = " << a - b << endl
<< "a * b = " << a * b << endl
<< "a / b = " << a / b << endl
<< "-a = " << -a << endl
<< "+a = " << +a << endl
<< "*a = " << *a << endl
<< "a + 5 = " << a + 5 << endl
<< "5 + a = " << 5 + a << endl
<< "a * 5 = " << a * 5 << endl
<< "5 * a = " << 5 * a << endl
<< "Exp(a) = " << exp(a) << endl
<< "Sin(a) = " << sin(a) << endl
<< "Cos(a) = " << cos(a) << endl
<< "Exp((a + b) / a) * Cos(a - b) = " << exp((a + b) / a) * cos(a - b) << endl;
a += b;
cout << "a += b; a = " << a << endl;
// Оператор = мы не перегружали, но это всё равно работает
b = a;
cout << "b = a; b = " << b << endl;
}

@ -0,0 +1,64 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z, Complex c) {
return z * z + c;
}
int main(int argc, char** argv) {
Complex c = {0, 0};
int n = 20;
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
if (argc < 4) {
cout << "usage: julia [re] [im] [n]" << endl
<< "using default values: 0 + 0i, n = 20 "<< endl;
}
else {
cout << argv[1] << " + " << argv[2] << "i" << endl << "n = " << n << endl;
sscanf(argv[1], "%f", &c.re);
sscanf(argv[2], "%f", &c.im);
sscanf(argv[3], "%d", &n);
}
Color* data = (Color*)malloc(sizeof(Color) * width * height);
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
Complex z = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
for (int k = 0; k < n; ++k) {
z = func(z, c);
}
float r = abs(z.re);
float b = abs(z.im);
if (r > 255) {
r = 255;
}
if (b > 255) {
b = 255;
}
data[i + width * j].r = 255 - r;
data[i + width * j].g = 0;
data[i + width * j].b = 255 - b;
}
}
FILE* file = fopen("julia.ppm", "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
free(data);
}

@ -0,0 +1,60 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z, Complex c) {
return z * z + c;
}
int main() {
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
int n = 20;
Color* data = (Color*)malloc(sizeof(Color) * width * height);
int max_time_steps = 500;
for (int time = 0; time < max_time_steps; time++)
{
Complex c = {-1.5 + (1.5 / max_time_steps) * time, -1.5 + (1.5 / max_time_steps) * time + 1};
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
Complex z = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
for (int k = 0; k < n; ++k) {
z = func(z, c);
}
float r = abs(z.re);
float b = abs(z.im);
if (r > 255) {
r = 255;
}
if (b > 255) {
b = 255;
}
data[i + width * j].r = 255 - r;
data[i + width * j].g = 0;
data[i + width * j].b = 255 - b;
}
}
char filename[100];
sprintf(filename, "animation/complex_%03d.ppm", time);
FILE* file = fopen(filename, "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
}
free(data);
}

@ -0,0 +1,54 @@
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include "complex.h"
using namespace std;
struct Color {
unsigned char r, g, b;
};
Complex func(Complex z, Complex c) {
return z * z + c;
}
int main(int argc, char** argv) {
int n = 20;
Complex z = {0, 0};
int width = 800, height = 800;
float x0 = -2.0f, x1 = 2.0f;
float y0 = -2.0f, y1 = 2.0f;
Color* data = (Color*)malloc(sizeof(Color) * width * height);
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
z = {0, 0};
Complex c = {x0 + (x1-x0) / width * i, y0 + (y1-y0) / width * j};
for (int k = 0; k < n; ++k) {
z = func(z, c);
}
float r = abs(z.re);
float b = abs(z.im);
if (r > 255) {
r = 255;
}
if (b > 255) {
b = 255;
}
data[i + width * j].r = 255 - r;
data[i + width * j].g = 0;
data[i + width * j].b = 255 - b;
}
}
FILE* file = fopen("mandelbrot.ppm", "wb");
fprintf(file, "P6\n%d %d\n255\n", width, height);
fwrite(data, sizeof(Color), height * width, file);
fclose(file);
free(data);
}

@ -0,0 +1,39 @@
#include <iostream>
#include <math.h>
#include <cstdlib>
#include "circle.h"
#include "point.h"
Circle::Circle(const Point& acenter, float aradius) {
mCenter = acenter;
mRadius = aradius;
}
Circle::Circle() {
mCenter = Point {0, 0};
mRadius = 1;
}
Circle::Circle(const Circle& circle) {
mCenter = circle.mCenter;
mRadius = circle.mRadius;
}
Point Circle::getCenter() const { return mCenter; }
float Circle::getRadius() const { return mRadius; }
void Circle::setCenter(const Point& p) {
mCenter = p;
}
void Circle::setRadius(float radius) {
mRadius = radius > 0 ? radius : 0;
}
float Circle::getArea() const {
return abs(mRadius * mRadius * M_PI);
}
float Circle::getDistance(const Point& p) {
return mCenter.distance(p) - mRadius;
}
bool Circle::isColliding(const Circle& c) const {
return (mCenter.distance(c.getCenter()) - (mRadius + c.getRadius()) > 0) ? false : true;
}
void Circle::move(const Point& p) {
mCenter = mCenter + p;
}

@ -0,0 +1,23 @@
#include "point.h"
class Circle
{
private:
Point mCenter;
float mRadius;
public:
Circle(const Point& acenter, float aradius);
Circle();
Circle(const Circle& circle);
Point getCenter() const;
float getRadius() const;
void setCenter(const Point& p);
void setRadius(float radius);
float getArea() const;
float getDistance(const Point& p);
bool isColliding(const Circle& c) const;
void move(const Point& p);
};

@ -0,0 +1,44 @@
#include <iostream>
#include "point.h"
#include "circle.h"
using std::cout, std::endl;
int main()
{
Point p = {7, -1};
Point q = {-4, 2};
cout << "Point p = " << p << endl;
cout << "Point q = " << q << endl;
cout << "p + q = " << p + q << endl;
Circle a {{4, 1}, 3};
Circle b;
// b = a;
cout << "Circle a: center: " << a.getCenter() << " radius: " << a.getRadius() << endl;
cout << "Circle b: center: " << b.getCenter() << " radius: " << b.getRadius() << endl;
cout << "Area of a = " << a.getArea() << endl;
cout << "Distance from point p to circle a = " << a.getDistance(p) << endl;
cout << "Collisions:" << endl;
if (a.isColliding(b))
cout << "Yes, a is colliding b" << endl;
else
cout << "No, a isn't colliding b" << endl;
cout << "Moving b by {1, 1}:" << endl;
b.move({1, 1});
if (a.isColliding(b))
cout << "Yes, a is colliding b" << endl;
else
cout << "No, a isn't colliding b" << endl;
}

@ -0,0 +1,82 @@
#include <iostream>
#include <cmath>
#include "point.h"
Point::Point(float x, float y)
{
mx = x;
my = y;
}
Point::Point()
{
mx = 0;
my = 0;
}
float Point::getX() const
{
return mx;
}
float Point::getY() const
{
return my;
}
void Point::setX(float x)
{
mx = x;
}
void Point::setY(float y)
{
my = y;
}
float Point::norm() const
{
return std::sqrt(mx * mx + my * my);
}
void Point::normalize()
{
float pnorm = norm();
mx /= pnorm;
my /= pnorm;
}
float Point::distance(const Point& p) const
{
return std::sqrt((p.mx - mx) * (p.mx - mx) + (p.my - my) * (p.my - my));
}
Point Point::operator+(const Point& right) const
{
Point result = {mx + right.mx, my + right.my};
return result;
}
Point Point::operator*(float a) const
{
Point result = {a * mx, a * my};
return result;
}
Point operator*(float a, const Point& p)
{
Point result = {a * p.mx, a * p.my};
return result;
}
std::ostream& operator<<(std::ostream& left, const Point& right)
{
left << "(" << right.mx << ", " << right.my << ")";
return left;
}

@ -0,0 +1,37 @@
#pragma once
/*
Поля x и y сделаны приватными
Конкретно для этого класса их можно было сделать публичными
Так как пользователь всё-равно будет иметь доступ без ограничений к этим полям через геттеры и сеттеры
Но они сделаны приватными для образовательных целей
*/
class Point
{
private:
float mx, my;
public:
Point(float x, float y);
Point();
float getX() const;
float getY() const;
void setX(float x);
void setY(float y);
void normalize();
float distance(const Point& p) const;
float norm() const;
Point operator+(const Point& right) const;
Point operator*(float a) const;
friend Point operator*(float a, const Point& p);
friend std::ostream& operator<<(std::ostream& left, const Point& right);
};

@ -0,0 +1,75 @@
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include "number.h"
Number fib(int n)
{
Number a = 0; // F0
Number b = 1; // F1
for (int i = 1; i <= n; ++i) {
if (i % 2) {
a += b;
} else {
b += a;
}
}
if (n % 2) {
return b;
}
return a;
}
Number factorial(int n)
{
Number result {
1};
for (int i = 2; i < n + 1; ++i) {
result = Number(i) * result;
}
return result;
}
void grad(Number n)
{
std::cout << "n = " << n;
Number max = n;
unsigned long long int steps = 0;
while (n != Number(1)) {
if (n > max) {
#ifdef _DEBUG_COMP
std::cout << n << " is greater than " << max << std::endl;
#endif
max = n;
}
if (n.isEven()) {
n.div2();
} else {
n = Number(3) * n + Number(1);
}
#ifdef _DEBUG_GRAD
if (steps > 100) {
std::cout << "break" << std::endl;
break;
}
#endif
++steps;
}
std::cout << " steps = " << steps << " max = " << max << std::endl;
}
int main()
{
std::cout << "===FIB===" << std::endl;
std::cout << "F(1000) = " << fib(1000) << std::endl;
std::cout << "===FAC===" << std::endl;
std::cout << "1000! = " << factorial(1000) << std::endl;
std::cout << "===GRAD===" << std::endl;
grad(Number("7"));
grad(Number("256"));
grad(Number("1117065"));
grad(Number("4761963248413673697"));
grad(Number("90560792656972947582439785608972465789628974587264056284658721771"));
}

@ -0,0 +1,343 @@
#include <iostream>
#include <iomanip>
#include <cstring>
#include "number.h"
Number::Number(int a)
{
#ifdef _DEBUG_CONSTRUCTOR
std::cout << "(Number constructor " << a << " -> ";
#endif
// Находим размер необходимой памяти под это число
int temp = a;
capacity = 0;
while (temp != 0) {
temp /= base;
capacity += 1;
}
// Отдельно обрабатываем случай, когда число равно 0
if (capacity == 0)
capacity = 1;
// Выделяем память и записывем число a в массив data
// Например, число 12345678 представится в виде массива [78, 56, 34, 12]
data = new char[capacity];
for (int i = 0; i < capacity; ++i) {
data[i] = a % base;
a /= base;
}
// В данном случае размер будет равен вместимости
size = capacity;
#ifdef _DEBUG_CONSTRUCTOR
std::cout << *this << ")" << std::endl;
#endif
}
// Конструктор по умолчанию
Number::Number():Number(0){}
// Конструктор копирования
Number::Number(const Number & n)
{
size = n.size;
capacity = n.capacity;
data = new char[capacity];
for (int i = 0; i < size; i++) {
data[i] = n.data[i];
}
}
Number::Number(const char *str)
{
int len = std::strlen(str);
size = (len + len % 2) / 2;
capacity = size;
data = new char[capacity];
char buf[2];
for (int i = 0; i < size; i++) {
buf[1] = str[len - 2 * i - 1];
if (len - 2 * i - 1 > 0) {
buf[0] = str[len - 2 * i - 2];
} else {
buf[0] = '0';
}
data[i] = std::stoi(buf);
}
}
Number::~Number()
{
delete[]data;
}
Number & Number::operator=(const Number & right)
{
capacity = right.capacity;
size = right.size;
data = new char[capacity];
for (int i = 0; i < size; i++) {
data[i] = right.data[i];
}
return *this;
}
Number Number::operator+(Number a)
{
#ifdef _DEBUG_ADD
std::cout << "arg1=" << a << "capacity=" << a.
capacity << ",size=" << a.size << std::endl;
std::cout << "arg2=" << *this << "capacity=" << this->
capacity << ",size=" << this->size << std::endl;
#endif
Number result;
Number temp;
int i;
int carry = 0;
if (size < a.size) {
temp = *this;
*this = a;
a = temp;
}
result.capacity = size + 1;
//result.data = new char[capacity];
result.data = (char *) calloc(result.capacity, sizeof(char));
for (i = 0; i < a.size; ++i) {
result.data[i] = (data[i] + a.data[i] + carry) % base;
carry = (data[i] + a.data[i] + carry) / base;
}
for (; i < size; ++i) {
result.data[i] = (data[i] + carry) % base;
carry = (data[i] + carry) / base;
}
if (carry) {
#ifdef _DEBUG_ADD
std::cout << "applied carry" << std::endl;
#endif
result.data[i] = carry;
result.size = size + 1;
} else {
result.size = size;
}
#ifdef _DEBUG_ADD
std::cout << result << " capacity=" << result.
capacity << ",size=" << result.size << std::endl;
#endif
return result;
}
void Number::operator+=(const Number & a)
{
*this = *this + a;
}
bool Number::isEven() const
{
if (data[0] % 2) {
return false;
}
return true;
}
Number Number::operator*(const Number & right) const
{
#ifdef _DEBUG_MUL
std::
cout << "arg1=" << *this << "(capacity=" << capacity << ",size=" <<
size << ")" << " " << "arg2=" << right << "(capacity=" << right.
capacity << ",size=" << right.size << ")" << std::endl;
#endif
if (*this == Number("0") || right == Number("0"))
return Number("0");
int i, j;
int temp;
Number result;
result.capacity = capacity + right.capacity;
int *carry = (int *) std::calloc(result.capacity, sizeof(int));
result.data = (char *) calloc(result.capacity, sizeof(char));
#ifdef _DEBUG_MUL
std::cout << "carry:[" << carry[0];
for (int k = 1; k < result.capacity; ++k) {
std::cout << "," << carry[k];
}
std::cout << "]" << std::endl;
#endif
for (i = 0; i < size; ++i) {
for (j = 0; j < right.size; ++j) {
#ifdef _DEBUG_MUL
std::cout << i + j << ":" << static_cast <
int >(result.data[i + j]) << " + " << static_cast <
int >(data[i]) << " * " << static_cast <
int >(right.data[j]) << " + " << carry[i + j] << std::endl;
#endif
temp =
(result.data[i + j] + data[i] * right.data[j] +
carry[i + j]);
result.data[i + j] = temp % base;
carry[i + j + 1] += temp / base;
carry[i + j] = 0;
}
}
#ifdef _DEBUG_MUL
std::cout << "result before applying carry:" << result << std::endl;
std::cout << "carry:[" << carry[0];
for (int k = 1; k < result.capacity; ++k) {
std::cout << "," << carry[k];
}
std::cout << "]" << std::endl;
#endif
if (carry[i + j - 1]) {
result.data[i + j - 1] = carry[i + j - 1];
result.size = i + j;
} else {
result.size = i + j - 1;
}
#ifdef _DEBUG_MUL
std::cout << "before correcting capacity, result=" << result << std::
endl;
#endif
// correcting capacity
/*char* temp_data = (char *)calloc(result.size, sizeof(char));
for (i = 0; i < result.size; ++i) {
temp_data[i] = result.data[i];
}
free(result.data);
result.capacity = result.size;
result.data = (char*)calloc(result.size,sizeof(char));
for (i = 0; i < result.size; ++i) {
result.data[i] = temp_data[i];
}
free(temp_data); */
free(carry);
#ifdef _DEBUG_MUL
std::cout << "return value=" << result << "(capacity=" << result.
capacity << ",size=" << result.
size << ")" << std::endl << "======" << std::endl;
#endif
return result;
}
void Number::operator*=(const Number & a)
{
*this = *this * a;
}
bool Number::operator==(const Number & a) const
{
if (size != a.size) {
return false;
}
for (int i = 0; i < size; ++i) {
if (data[i] != a.data[i]) {
return false;
}
}
return true;
}
bool Number::operator!=(const Number & a) const
{
return not(*this == a);
}
bool Number::operator>(const Number & a) const
{
#ifdef _DEBUG_COMP
std::
cout << "comp " << *this << "(size=" << size << ") and " << a <<
"(size=" << a.size << ")" << std::endl;
#endif
if (size > a.size) {
#ifdef _DEBUG_COMP
std::cout << "size > a.size => true" << std::endl;
#endif
return true;
}
if (size < a.size) {
#ifdef _DEBUG_COMP
std::cout << "size < a.size => false" << std::endl;
#endif
return false;
}
for (int i = size - 1; i >= 0; --i) {
if (data[i] > a.data[i]) {
return true;
#ifdef _DEBUG_COMP
std::cout << static_cast <
int >(data[i]) << ">" << static_cast <
int >(a.data[i]) << std::endl;
#endif
}
if (data[i] < a.data[i]) {
#ifdef _DEBUG_COMP
std::cout << static_cast <
int >(data[i]) << "<" << static_cast <
int >(a.data[i]) << std::endl;
#endif
return false;
}
}
#ifdef _DEBUG_COMP
std::cout << "using final false" << std::endl;
#endif
return false;
}
bool Number::operator<(const Number & a) const
{
return not(*this > a) and(*this != a);
}
void Number::div2()
{
#ifdef _DEBUG_DIV2
std::cout << "n = " << *this << std::endl;
#endif
int carry = 0;
int temp;
for (int i = size - 1; i >= 0; --i) {
temp = data[i] + carry * base;
data[i] = temp / 2;
carry = temp % 2;
}
if (data[size - 1] == 0) {
--size;
}
#ifdef _DEBUG_DIV2
std::cout << "unstripped result " << *this << std::endl;
#endif
}
std::ostream & operator<<(std::ostream & stream, const Number & right)
{
#ifdef _DEBUG_COUT
stream << "[";
for (std::size_t i = 0; i < right.size; ++i) {
stream << static_cast <
int >(right.data[right.size - 2 - i]) << ",";
}
stream << "]";
#else
// Печатаем самый большой разряд
stream << (int) right.data[right.size - 1];
// Печатаем остальные разряды с заполнением нулями до 2-х цифр
// setfill и setw это то же самое, что и в языке C спецификатор %02d
for (std::size_t i = 0; i < right.size - 1; ++i)
stream << std::setfill('0') << std::setw(2) << (int) right.
data[right.size - 2 - i];
#endif
return stream;
}

@ -0,0 +1,63 @@
#pragma once
/*
Класс Number -- класс положительных больших чисел
Большое число будет храниться в динамическом массиве data
Каждый элемент этого массива содержит разряд числа в 100-ричной системе счисления
(так как base = 100)
По сути, каждый элемент data хранит две цифры числа в десятичной записи
Значение 100 для системы счисления выбрано как компромис между
эффективностью и удобством написания программы.
Если выбрать значения базы 10 - то программа будет не так эффективна по памяти
Если выбрать значения базы 256 (максимально эффективное использование памяти для типа char),
то алгоритм печати на экран сильно усложнится
В качестве альтернативы, можно было выбрать базу 1e9,
изменив при этом тип элементов c char на int
capacity - размер массива data
size - сколько ячеек занимет число в массиве data
size <= capacity
Для удобства разряды числа хранятся в обратном порядке
Например, число 12345678 соответствует массиву
data = {78, 56, 34, 12}
(это упрощает многие алгоритмы с такими числами)
*/
class Number {
private:
static const int base = 100;
std::size_t size;
std::size_t capacity;
char *data;
public:
Number(int a);
Number();
// Конструктор копирования
Number(const Number & n);
Number(const char *str);
~Number();
Number & operator=(const Number & right);
Number operator+(Number a);
void operator+=(const Number & a);
bool isEven() const;
Number operator*(const Number & right) const;
void operator*=(const Number & a);
bool operator==(const Number & a) const;
bool operator!=(const Number & a) const;
bool operator>(const Number & a) const;
bool operator<(const Number & a) const;
void div2();
friend std::ostream & operator<<(std::ostream & stream,
const Number & right);
};
std::ostream & operator<<(std::ostream & stream, const Number & right);

@ -0,0 +1,22 @@
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
string letter_case_switch(const string & str)
{
string result = str;
if (str.size() == 0)
return result;
result[0] =
isupper(result[0]) ? tolower(result[0]) : toupper(result[0]);
return result;
}
int main()
{
string meow;
cin >> meow;
cout << letter_case_switch(meow) << endl;
}

@ -0,0 +1,19 @@
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
string letter_case_switch(const string& str) {
string result = str;
if (str.size() == 0)
return result;
result[0] = isupper(result[0]) ? tolower(result[0]) : toupper(result[0]);
return result;
}
int main() {
string meow;
cin >> meow;
cout << letter_case_switch(meow) << endl;
}

@ -0,0 +1,48 @@
#include <iostream>
#include <string>
#include <string_view>
using namespace std;
string repeat1(string_view s)
{
return string {
s}
+string {
s};
}
void repeat2(string & s)
{
s += s;
}
void repeat3(string * s)
{
*s += *s;
}
string *repeat4(string_view s)
{
string *result = new string;
*result = string {
s} +string {
s};
return result;
}
int main()
{
string meow;
cin >> meow;
cout << "test of repeat1:" << endl << repeat1(meow) << endl;
repeat2(meow);
cout << "test of repeat2:" << endl << meow << endl;
repeat3(&meow);
cout << "test of repeat3:" << endl << meow << endl;
cout << "test of repeat4:" << endl << *repeat4(meow) << endl;
}

@ -0,0 +1,38 @@
#include <iostream>
#include <string>
#include <string_view>
using namespace std;
string repeat1(string_view s) {
return string{s} + string{s};
}
void repeat2(string& s) {
s += s;
}
void repeat3(string* s) {
*s += *s;
}
string* repeat4(string_view s) {
string* result = new string;
*result = string{s} + string{s};
return result;
}
int main() {
string meow;
cin >> meow;
cout << "test of repeat1:" << endl << repeat1(meow) << endl;
repeat2(meow);
cout << "test of repeat2:" << endl << meow << endl;
repeat3(&meow);
cout << "test of repeat3:" << endl << meow << endl;
cout << "test of repeat4:" << endl << *repeat4(meow) << endl;
}

@ -0,0 +1,24 @@
#include <iostream>
#include <string>
using namespace std;
string operator*(const string str, int n) {
string result;
for (int i = 0; i < n; ++i)
result += str;
return result;
}
string operator*(int n, const string str) {
string result;
for (int i = 0; i < n; ++i)
result += str;
return result;
}
int main() {
string meow;
cin >> meow;
cout << 3 * meow << endl;
}

@ -0,0 +1,22 @@
#include <iostream>
#include <string>
using namespace std;
void truncateToDot(string& s) {
s.resize(s.find('.'));
s.shrink_to_fit();
}
int main() {
std::string a = "cat.dog.mouse.elephant.tiger.lion";
std::string b = "wikipedia.org";
std::string c = ".com";
truncateToDot(a);
truncateToDot(b);
truncateToDot(c);
cout << a << endl
<< b << endl
<< c << endl;
}

@ -0,0 +1,35 @@
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int string_sum(const string& str) {
int res = 0;
int x;
int n = str.size();
int i = 0;
while (i < n) {
switch (str[i]) {
case '[':
case ',' :
sscanf((str.c_str()) + i + 1, "%d", &x);
res += x;
break;
case ']' :
return res;
case ' ':
break;
default:
break;
}
++i;
}
return -1;
}
int main() {
string meow;
getline(cin, meow);
cout << string_sum(meow) << endl;
}

@ -0,0 +1,34 @@
#include <iostream>
#include <string>
#include <string_view>
using namespace std;
int main() {
int *x = new int{123};
cout << *x << endl;
string *str = new string{"Cats and Dogs"};
cout << *str << endl;
int *xs = new int[]{10, 20, 30, 40, 50};
for (int i = 0; i < 5; ++i)
cout << xs[i] << " ";
cout << endl;
string *strs = new string[]{"Cat", "Dog", "Mouse"};
for (int i = 0; i < 3; ++i)
cout << strs[i] << " ";
cout << endl;
string_view *str_views = new string_view[]{strs[0], strs[1], strs[2]};
for (int i = 0; i < 3; ++i)
cout << str_views[i] << " ";
cout << endl;
delete x;
delete str;
delete[] xs;
delete[] strs;
delete[] str_views;
}

@ -0,0 +1,22 @@
#include <iostream>
#include "miptstring.cpp"
using std::cout, std::endl;
int main() {
mipt::String stack{"Cat"};
cout << stack << endl;
mipt::String* heap = new mipt::String{"Dog"};
cout << *heap << endl;
char *x = (char*)malloc(sizeof(mipt::String));
mipt::String* px = new(x) mipt::String{"Elephant"};
cout << *px << endl;
px->~String();
free(px);
delete heap;
}

@ -0,0 +1,215 @@
#pragma once
#include <iostream>
#include <cstring>
namespace mipt{
class String
{
private:
std::size_t mSize {0};
std::size_t mCapacity {0};
char* mpData {nullptr};
public:
String(const char* str)
{
std::size_t strSize = std::strlen(str);
resize(strSize);
std::memcpy(mpData, str, mSize);
std::cout << "mipt::String Constructor (" << mpData << ")" << std::endl;
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
String(std::size_t n, char a)
{
resize(n);
for (std::size_t i = 0; i < mSize; ++i)
mpData[i] = a;
std::cout << "mipt::String Constructor (" << mpData << ")" << std::endl;
}
~String()
{
std::cout << "mipt::String Destructor (" << mpData << ")" << std::endl;
delete [] mpData;
}
void reserve(std::size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = std::max(2 * mCapacity, capacity);
char* newData = new char[mCapacity]; // errorCheckedMalloc(mCapacity);
if (mpData)
std::memcpy(newData, mpData, mSize + 1);
delete [] mpData;
mpData = newData;
}
void resize(std::size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
std::memcpy(mpData, right.mpData, mSize + 1);
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
std::memcpy(result.mpData, mpData, mSize);
std::memcpy(result.mpData + mSize, b.mpData, b.mSize);
result.mpData[result.mSize] = '\0';
return result;
}
String& operator+=(const String& right)
{
*this = *this + right;
return *this;
}
bool operator==(const String& right) const
{
if (mSize != right.mSize)
return false;
std::size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool operator<(const String& right) const
{
std::size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
bool operator<=(const String& right) const
{
std::size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] <= right.mpData[i];
}
bool operator!=(const String& right) const
{
return !(*this == right);
}
bool operator>(const String& right) const
{
return !(*this <= right);
}
bool operator>=(const String& right) const
{
return !(*this < right);
}
char& operator[](std::size_t i)
{
return mpData[i];
}
const char& operator[](std::size_t i) const
{
return mpData[i];
}
char& at(std::size_t i)
{
if (i >= mSize)
throw std::out_of_range{"mipt::String::at: index >= this->size()"};
return mpData[i];
}
const char& at(std::size_t i) const
{
if (i >= mSize)
throw std::out_of_range{"mipt::String::at: index >= this->size()"};
return mpData[i];
}
void clear()
{
delete [] mpData;
mSize = 0;
mCapacity = 1;
mpData = new char[mCapacity];
mpData[0] = '\0';
}
void addCharacter(char c)
{
if (mSize + 1 == mCapacity)
reserve(2 * mCapacity);
mpData[mSize] = c;
resize(mSize + 1);
}
std::size_t getSize() const {return mSize;}
std::size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& out, const String& s)
{
out << s.cStr();
return out;
}
std::istream& operator>>(std::istream& in, String& s)
{
s.clear();
while (true)
{
char x = in.get();
if (std::isspace(x))
break;
s.addCharacter(x);
}
return in;
}
}

@ -0,0 +1,18 @@
#include <iostream>
#include "miptstring.h"
#include "miptstringview.h"
using namespace std;
int main() {
mipt::String a = "abcd";
mipt::String b = "abce";
mipt::StringView av = a;
mipt::StringView bv = b;
//cout << (b < a) << endl;
//cout << (bv < av) << endl;
cout << av.substr(1,10) << endl;
av.remove_suffix(2);
cout << av << endl;
mipt::String meow = av;
cout << "sv to string: " << meow << endl;
}

@ -0,0 +1,218 @@
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include "miptstring.h"
#include "miptstringview.h"
using std::cout, std::cin, std::endl, std::size_t;
namespace mipt{
char* errorCheckedMalloc(size_t newCapacity)
{
char* result = static_cast<char*>(std::malloc(newCapacity * sizeof(char)));
if (result == NULL)
{
cout << "Error! Out of memory" << endl;
std::exit(1);
}
return result;
}
String::String(const char* str)
{
size_t strSize = std::strlen(str);
resize(strSize);
std::memcpy(mpData, str, mSize);
}
String::String() : String("") {}
String::String(const String& s) : String(s.cStr()) {}
String::String(const StringView& sv) {
mSize = sv.size();
(*this).reserve(mSize);
for(int i = 0; i < mSize; ++i)
mpData[i] = sv[i];
mpData[mSize] = '\0';
}
String::String(size_t n, char a)
{
resize(n);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = a;
}
String::~String()
{
std::free(mpData);
}
void String::reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = std::max(2 * mCapacity, capacity);
char* newData = errorCheckedMalloc(mCapacity);
if (mpData)
std::memcpy(newData, mpData, mSize + 1);
std::free(mpData);
mpData = newData;
}
void String::resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& String::operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
std::memcpy(mpData, right.mpData, mSize + 1);
return *this;
}
String String::operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
std::memcpy(result.mpData, mpData, mSize);
std::memcpy(result.mpData + mSize, b.mpData, b.mSize);
result.mpData[result.mSize] = '\0';
return result;
}
String& String::operator+=(const String& right)
{
*this = *this + right;
return *this;
}
bool String::operator==(const String& right) const
{
if (mSize != right.mSize)
return false;
size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool String::operator<(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
bool String::operator<=(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] <= right.mpData[i];
}
bool String::operator!=(const String& right) const
{
return !(*this == right);
}
bool String::operator>(const String& right) const
{
return !(*this <= right);
}
bool String::operator>=(const String& right) const
{
return !(*this < right);
}
char& String::operator[](size_t i)
{
return mpData[i];
}
const char& String::operator[](size_t i) const
{
return mpData[i];
}
char& String::at(size_t i)
{
if (i >= mSize)
{
cout << "Error! Index is out of bounds." << endl;
}
return mpData[i];
}
void String::clear()
{
std::free(mpData);
mSize = 0;
mCapacity = 1;
mpData = errorCheckedMalloc(mCapacity);
mpData[0] = '\0';
}
void String::addCharacter(char c)
{
if (mSize + 1 == mCapacity)
reserve(2 * mCapacity);
mpData[mSize] = c;
resize(mSize + 1);
}
size_t String::getSize() const {return mSize;}
size_t String::getCapacity() const {return mCapacity;}
const char* String::cStr() const {return mpData;}
std::ostream& operator<<(std::ostream& out, const String& s)
{
out << s.cStr();
return out;
}
std::istream& operator>>(std::istream& in, String& s)
{
s.clear();
while (true)
{
char x = in.get();
if (x == ' ' || x == '\n' || x == '\t')
break;
s.addCharacter(x);
}
return in;
}
}

@ -0,0 +1,43 @@
#pragma once
#include <iostream>
namespace mipt {
class StringView;
class String
{
private:
size_t mSize {0};
size_t mCapacity {0};
char* mpData {nullptr};
public:
String(const char* str);
String();
String(const String& s);
String(const mipt::StringView& sv);
String(size_t n, char a);
~String();
void reserve(size_t capacity);
void resize(size_t size);
String& operator=(const String& right);
String operator+(const String& b);
String& operator+=(const String& right);
bool operator==(const String& right) const;
bool operator<(const String& right) const;
bool operator<=(const String& right) const;
bool operator!=(const String& right) const;
bool operator>(const String& right) const;
bool operator>=(const String& right) const;
char& operator[](size_t i);
const char& operator[](size_t i) const;
char& at(size_t i);
void clear();
void addCharacter(char c);
size_t getSize() const;
size_t getCapacity() const;
const char* cStr() const;
};
std::ostream& operator<<(std::ostream& out, const String& s);
std::istream& operator>>(std::istream& in, String& s);
}

@ -0,0 +1,81 @@
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include "miptstring.h"
#include "miptstringview.h"
using std::cout, std::cin, std::endl, std::size_t;
namespace mipt {
StringView::StringView() {;
mSize = 0;
mpData = nullptr;
}
StringView::StringView(const StringView& str) {
mSize = str.mSize;
mpData = str.mpData;
}
StringView::StringView(const mipt::String& s) {
mSize = s.getSize();
mpData = s.cStr();
}
StringView::StringView(const char* s) {
mpData = s;
mSize = strlen(s);
}
const char& StringView::at(size_t i)
{
if (i >= mSize)
{
throw std::out_of_range("Error! Index is out of bounds.");
std::exit(1);
}
return mpData[i];
}
const char& StringView::operator[](size_t i) const
{
return mpData[i];
}
bool StringView::operator<(const StringView& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
size_t StringView::size() const {
return mSize;
}
StringView StringView::substr(size_t pos, size_t count) {
if (pos > mSize)
throw std::out_of_range("Error! Index is out of bounds.");
if (pos + count > mSize)
count = mSize - pos;
StringView result;
result.mpData = mpData + pos;
result.mSize = count;
return result;
}
void StringView::remove_prefix(size_t n) {
mSize -= n;
}
void StringView::remove_suffix(size_t n) {
mSize -= n;
mpData += n;
}
/*std::ostream& StringView::operator<<(std::ostream& out, mipt::StringView sv) {
size_t size = sv.size();
for (int i = 0; i < size; ++i)
out << sv[i];
return out;
}*/
std::ostream& operator<<(std::ostream& out, const mipt::StringView& sv) {
size_t size = sv.size();
for (int i = 0; i < size; ++i)
out << sv[i];
return out;
}
};

@ -0,0 +1,28 @@
#pragma once
#include <iostream>
namespace mipt {
class String;
class StringView
{
private:
const char* mpData;
size_t mSize;
public:
StringView();
StringView(const StringView& str);
StringView(const mipt::String& s);
StringView(const char* s);
const char& at(size_t i);
const char& operator[](size_t i) const;
bool operator<(const StringView& right) const;
size_t size() const;
StringView substr(size_t pos, size_t count);
void remove_prefix(size_t n);
void remove_suffix(size_t n);
};
std::ostream& operator<<(std::ostream& out, const StringView& sv);
}

@ -0,0 +1,18 @@
#include <iostream>
#include <vector>
using std::cout, std::endl;
int sumEven(const std::vector<int>& v) {
int sum = 0;
size_t s = v.size();
for (int i = 0; i < s; ++i)
if (v[i] % 2 == 0)
sum += v[i];
return sum;
}
int main() {
std::vector<int> v {4, 8, 15, 16, 23, 42};
cout << sumEven(v) << endl;
}

@ -0,0 +1,58 @@
#include <iostream>
#include <vector>
#include <span>
using std::cout, std::endl, std::vector, std::span;
vector<int> lastDigits1(const vector<int>& v) {
vector<int> result;
size_t size = v.size();
for(int i = 0; i < size; ++i) {
result.push_back(v[i] % 10);
}
return result;
}
void lastDigits2(vector<int>& v) {
size_t size = v.size();
for(int i = 0; i < size; ++i) {
v[i] %= 10;
}
}
void lastDigits3(vector<int>* pv) {
size_t size = pv->size();
for(int i = 0; i < size; ++i)
(*pv)[i] %= 10;
}
void lastDigits4(span<int> sp) {
size_t size = sp.size();
for(int i = 0; i < size; ++i)
sp[i] %= 10;
}
std::ostream& operator<<(std::ostream& out, const vector<int>& v) {
cout << "[";
size_t size = v.size();
for(int i = 0; i < size; ++i)
cout << v[i] << (i == size - 1 ? "]" : " ");
return out;
}
int main() {
vector<int> meow{1, 2, 3, 12, 45, 32,313123,3245};
vector<int> result1 = lastDigits1(meow);
cout << result1 << endl;
vector<int> result2 = meow;
lastDigits2(result2);
cout << result2 << endl;
vector<int> result3 = meow;
lastDigits3(&result3);
cout << result3 << endl;
span<int> sp = meow;
lastDigits4(sp);
cout << meow << endl;
}

@ -0,0 +1,52 @@
#include <iostream>
#include <utility>
#include <vector>
#include <cmath>
using std::cout, std::endl, std::pair, std::vector;
vector<pair<int, int>> factorization(int n) {
if (n == 1) {
return vector<pair<int,int>>{{1, 1}};
}
int d = 2;
int c;
vector<pair<int, int>> result;
while(n != 1) {
c = 0;
while(n % d == 0) {
c++;
n /= d;
}
if (c)
result.push_back(pair{d, c});
d++;
}
return result;
}
std::ostream& operator<<(std::ostream& out, pair<int,int> p) {
out << "{" << p.first << ", " << p.second << "}";
return out;
}
std::ostream& operator<<(std::ostream& out, vector<pair<int,int>> v) {
out << "{";
size_t size = v.size();
for(int i = 0; i < size; ++i) {
out << v[i] << (i == size - 1 ? "}" : ", ");
}
return out;
}
int main() {
vector<pair<int, int>> res = factorization(60);
cout << res << endl;
res = factorization(626215995);
cout << res << endl;
res = factorization(107);
cout << res << endl;
res = factorization(1);
cout << res << endl;
}

@ -0,0 +1,27 @@
#include <iostream>
#include "time.h"
#include <string_view>
#include <string>
#include <vector>
using std::cout, std::endl, std::string, std::string_view, std::vector;
int main()
{
string t1s = "23:59:59";
string_view t1sv = t1s;
string t2s = "23:59:59";
string_view t2sv = t2s;
Time t1 = t1sv;
Time t2 = t2sv;
cout << t1 + t2 << endl;
string tss = "23:59:59 23:59:59 23:59:59";
string_view tssv = tss;
vector < Time > tsv = getTimesFromString(tss);
for (int i = 0, size = tsv.size(); i < size; ++i) {
cout << tsv[i] << endl;
}
cout << sumTimes(tsv) << endl;
}

@ -0,0 +1,78 @@
#include "time.h"
#include <string>
#include <iomanip>
#include <vector>
using std::cout, std::endl, std::vector, std::string_view, std::string;
Time::Time(int hours, int minutes, int seconds)
{
mHours = hours;
mMinutes = minutes;
mSeconds = seconds;
}
Time::Time(string_view s)
{
string buf;
buf = s.substr(0, 2);
mHours = stoi(buf);
buf = s.substr(3, 2);
mMinutes = stoi(buf);
buf = s.substr(6, 2);
mSeconds = stoi(buf);
}
Time::Time():Time(0, 0, 0)
{
};
Time Time::operator+(Time b) const
{
return Time((mHours + b.mHours + (mMinutes + b.mMinutes) / 60) % 24,
(mMinutes + b.mMinutes +
(mSeconds + b.mSeconds) / 60) % 60,
(mSeconds + b.mSeconds) % 60);
}
int Time::hours() const
{
return mHours;
}
int Time::minutes() const
{
return mMinutes;
}
int Time::seconds() const
{
return mSeconds;
}
vector < Time > getTimesFromString(string_view s)
{
vector < Time > res;
for (int i = 0, size = s.size(); i < size; i += 9) {
res.push_back(Time(s.substr(i, 9)));
}
return res;
}
Time sumTimes(const vector < Time > &v)
{
Time res;
for (int i = 0, size = v.size(); i < size; ++i) {
res = res + v[i];
}
return res;
}
std::ostream & operator<<(std::ostream & out, Time t)
{
out << std::setw(2) << std::setfill('0') << t.mHours
<< ":"
<< std::setw(2) << std::setfill('0') << t.mMinutes
<< ":" << std::setw(2) << std::setfill('0') << t.mSeconds;
return out;
}

@ -0,0 +1,21 @@
#pragma once
#include <string_view>
#include <iostream>
#include <vector>
using std::string_view, std::vector;
class Time {
private:
int mHours = 0, mMinutes = 0, mSeconds = 0;
public:
Time(int hours, int minutes, int seconds);
Time();
Time(string_view s);
Time operator+(Time b) const;
int hours() const; int minutes() const; int seconds() const;
friend std::ostream& operator<<(std::ostream& out, Time t);
};
Time sumTimes(const vector<Time>& v);
vector<Time> getTimesFromString(string_view s);

@ -0,0 +1,34 @@
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::string, std::pair, std::cout, std::endl, std::vector;
template <typename T>
T maximum(const vector<T>& v) {
T max{};
for(int i = 0, size = v.size(); i < size; ++i) {
if (v[i] > max)
max = v[i];
}
return max;
}
int main() {
vector<int> int_v {1,3,5,3,23,113,34,54};
cout << maximum(int_v) << endl;
vector<float> float_v {1.5,5.64,5.67,45.65,113,67.5,98.12};
cout << maximum(float_v) << endl;
vector<string> string_v {"aaaa", "dfg", "dsfdgjb", "meow", "dsfewvcv", "klafdn"};
cout << maximum(string_v) << endl;
vector<pair<int, int>> pair_v {
{113, 1},
{12, 3},
{45, 34},
{113, 113},
{112, 12233}
};
pair<int, int> res = maximum(pair_v);
cout << "(" << res.first << ", " << res.second << ")" << endl;
}

@ -0,0 +1,65 @@
#include <iostream>
#include <vector>
#include <array>
#include <string>
#include <utility>
using std::cout, std::endl, std::vector, std::pair;
template <typename T, typename U>
std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p)
{
out << "(" << p.first << ", " << p.second << ")";
return out;
}
template <typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v)
{
out << "[";
for (size_t i = 0; i < v.size() - 1; ++i)
out << v[i] << ", ";
if (!v.empty())
{
out << v.back();
}
out << "]";
return out;
}
template <typename T>
vector<pair<typename T::value_type,typename T::value_type>> pairing(T& xs) {
typedef typename T::value_type U;
vector<pair<U, U>> res;
size_t size = xs.size();
for (int i = 0, n = (size % 2 ? size - 1: size); i < n; i += 2)
res.push_back(pair(xs[i], xs[i+1]));
if (size % 2)
res.push_back(pair(xs[size - 1], U()));
return res;
}
int main()
{
std::vector v {10, 20, 30, 40, 50, 60};
cout << pairing(v) << endl;
std::array<std::string, 7> a {"cat", "dog", "mouse", "elephant", "tiget", "axolotl", "wolf"};
cout << pairing(a) << endl;
std::string s {"Cats and dogs!"};
cout << pairing(s) << endl;
}
/*
Программа должна напечатать:
[(10, 20), (30, 40), (50, 60)]
[(cat, dog), (mouse, elephant), (tiget, axolotl), (wolf, )]
[(C, a), (t, s), ( , a), (n, d), ( , d), (o, g), (s, !)]
*/

@ -0,0 +1,42 @@
#include <iostream>
#include <string>
template <typename T>
class Manager {
private:
T* mPtr;
public:
Manager() {
mPtr = nullptr;
}
void allocate() {
mPtr = (T*)malloc(sizeof(T));
}
void construct(const T& t) {
new(mPtr) T{t};
}
T& get() {
return *mPtr;
}
void destruct() {
mPtr->~T();
}
void deallocate() {
free(mPtr);
}
};
int main() {
Manager<std::string> a;
a.allocate();
a.construct("Cats and dogs");
a.get() += " and elephants";
std::cout << a.get() << std::endl;
a.destruct();
a.construct("Sapere aude");
std::cout << a.get() << std::endl;
a.destruct();
a.deallocate();
}

@ -0,0 +1,74 @@
#include <iostream>
#include <string>
#include <vector>
using std::cout, std::endl, std::string, std::vector;
template <typename T>
class Ref {
private:
T* mPtr;
public:
Ref(T& t) {
mPtr = &t;
}
Ref(Ref& t) {
mPtr = t.mPtr;
}
Ref() {
mPtr = nullptr;
}
T& get() {
return *mPtr;
}
T operator=(const T& t) {
new(mPtr) T{t};
return *mPtr;
}
T operator+(const T& t) {
return *mPtr + t;
}
T operator+=(const T& t) {
*mPtr = *mPtr + t;
return *mPtr;
}
T* operator->() {
return mPtr;
}
template <typename U>
friend std::ostream& operator<<(std::ostream& out, Ref<U> r);
};
template <typename T>
std::ostream& operator<<(std::ostream& out, Ref<T> r) {
out << *(r.mPtr);
return out;
}
void toUpper(Ref<string> r) {
for(size_t i = 0; i < r->size(); ++i)
r.get()[i] = toupper(r.get()[i]);
}
int main() {
int a = 10;
Ref<int> ra = a;
cout << ra << endl;
string s = "Cat";
Ref<string> rs = s;
rs = "Mouse";
rs += "Elephant";
cout << rs << endl;
cout << s << endl;
toUpper(s);
cout << s << endl;
vector<string> animals {"Cat", "Dogs", "Elephants", "Worms"};
vector<Ref<string>> refs {animals.begin(), animals.end()};
for (int i = 0; i < refs.size(); ++i)
cout << animals[i] << " ";
cout << endl;
}

@ -0,0 +1,22 @@
#include <vector>
#include <iostream>
#include <algorithm>
using std::cout, std::endl, std::vector, std::cin;
int main() {
size_t n;
cin >> n;
vector<int> v(n);
for (int i = 0; i < n; ++i)
cin >> v[i];
vector<int>::iterator max = std::max_element(v.begin(), v.end());
std::sort(v.begin(), max);
std::sort(max, v.end());
std::reverse(max, v.end());
for (int i = 0; i < v.size(); ++i)
cout << v[i] << (i == v.size() - 1 ? "": " ");
cout << endl;
}

@ -0,0 +1,27 @@
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using std::cout, std::endl, std::string, std::vector;
void string_vector_reverse(vector<string>& sv) {
std::for_each(sv.begin(), sv.end(), [](string& s){ std::reverse(s.begin(), s.end()); });
std::reverse(sv.begin(), sv.end());
}
int main() {
vector<string> sv1 {"cat", "dog", "mouse", "elephant"};
vector<string> sv2 {"a", "bc"};
string_vector_reverse(sv1);
string_vector_reverse(sv2);
for (int i = 0; i < sv1.size(); ++i)
cout << sv1[i] << (i == sv1.size() - 1 ? "" : " ");
cout << endl;
for (int i = 0; i < sv2.size(); ++i)
cout << sv2[i] << (i == sv2.size() - 1 ? "" : " ");
cout << endl;
}

@ -0,0 +1,18 @@
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <string>
#include <numeric>
#include <cctype>
using std::string, std::cin, std::cout, std::endl;
bool strIsUpper(const string& s) {
return std::accumulate(s.begin(), s.end(), true, [](bool res, char c) {return res && (!isalpha(c) || isupper(c)); });
}
int main() {
string s;
getline(cin, s);
cout << strIsUpper(s) << endl;
}

@ -0,0 +1,22 @@
#include <iostream>
#include <algorithm>
#include <string>
#include <string_view>
#include <cctype>
using std::cout, std::endl, std::string, std::string_view;
bool isIdentifier(string_view sv) {
bool is = true;
if (!(std::isalpha(sv[0]) || sv[0] == '_'))
return false;
if (std::all_of(sv.begin(), sv.end(), [](const char c){ return isalpha(c) || isdigit(c) || c == '_' ;}))
return true;
return false;
}
int main() {
string s;
getline(std::cin, s);
cout << isIdentifier(s) << endl;
}

@ -0,0 +1,18 @@
#include <iostream>
#include <string>
#include <algorithm>
using std::cout, std::string, std::endl;
void move_spaces(string& s) {
std::stable_sort(s.begin(), s.end(), [](const char& a, const char& b){ return (b == ' '); });
}
int main() {
string s;
std::getline(std::cin, s);
move_spaces(s);
// So we can see spaces
cout << s << "###" << endl;
}

@ -0,0 +1,2 @@
balls:
g++ ./balls.cpp -std=c++11 -o balls.exe -I../../../3rdparty/SFML-2.5.1/include -L ../../../3rdparty/SFML-2.5.1/lib/ -lsfml-graphics -lsfml-window -lsfml-system

@ -0,0 +1,94 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Ball
{
float radius;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
const int n_balls = 100;
// Шаг по времени
const float delta_t = 0.1;
// Создаём экземпляр класса окно
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
// Задаём максимальное количество кадров в секунду
window.setFramerateLimit(60);
// Так как sf::CircleShape занимает много памяти, создаём всего 1 экземпляр
sf::CircleShape circle(50.0f);
circle.setFillColor({200, 216, 200});
std::vector<Ball> balls;
balls.resize(n_balls);
for (int i = 0; i < n_balls; i++)
{
balls[i].radius = 4 + rand() % 8;
balls[i].position = {(float)(rand() % width), (float)(rand() % height)};
balls[i].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
// В данном примере проверяем окно на закрытие
if (event.type == sf::Event::Closed)
window.close();
}
// очистить скрытый холст черным цветом
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
/*
if (balls[i].position.x < 0)
balls[i].position.x += width;
if (balls[i].position.x > width)
balls[i].position.x -= width;
if (balls[i].position.y < 0)
balls[i].position.y += height;
if (balls[i].position.y > height)
balls[i].position.y -= height;
*/
// Используем 1 sf::CircleShape, чтобы нарисовать все шары
circle.setRadius(balls[i].radius);
// setOrigin - задаёт центр объекта
// По умолчанию центр - в левом верхнем угле объекта
// Строка ниже устанавливает центр в центре шарика
// В дальнейшем функция, setPosition устанавливает положение шарика так,
// чтобы его центр был в точке balls[i].position
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
window.draw(circle);
}
// отображаем содержимое скрытого холста на экран
window.display();
}
return 0;
}

@ -0,0 +1,2 @@
balls:
g++ ./balls.cpp -std=c++11 -o balls.exe -I../../../3rdparty/SFML-2.5.1/include -L ../../../3rdparty/SFML-2.5.1/lib/ -lsfml-graphics -lsfml-window -lsfml-system

@ -0,0 +1,93 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Ball
{
float radius;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
const int n_balls = 100;
// Шаг по времени
const float delta_t = 0.1;
// Создаём экземпляр класса окно
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
// Задаём максимальное количество кадров в секунду
window.setFramerateLimit(60);
// Так как sf::CircleShape занимает много памяти, создаём всего 1 экземпляр
sf::CircleShape circle(50.0f);
circle.setFillColor({200, 216, 200});
std::vector<Ball> balls;
balls.resize(n_balls);
for (int i = 0; i < n_balls; i++)
{
balls[i].radius = 4 + rand() % 8;
balls[i].position = {(float)(rand() % width), (float)(rand() % height)};
balls[i].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
// В данном примере проверяем окно на закрытие
if (event.type == sf::Event::Closed)
window.close();
}
// очистить скрытый холст черным цветом
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
if (balls[i].position.x < 0)
balls[i].position.x += width;
if (balls[i].position.x > width)
balls[i].position.x -= width;
if (balls[i].position.y < 0)
balls[i].position.y += height;
if (balls[i].position.y > height)
balls[i].position.y -= height;
// Используем 1 sf::CircleShape, чтобы нарисовать все шары
circle.setRadius(balls[i].radius);
// setOrigin - задаёт центр объекта
// По умолчанию центр - в левом верхнем угле объекта
// Строка ниже устанавливает центр в центре шарика
// В дальнейшем функция, setPosition устанавливает положение шарика так,
// чтобы его центр был в точке balls[i].position
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
window.draw(circle);
}
// отображаем содержимое скрытого холста на экран
window.display();
}
return 0;
}

@ -0,0 +1,90 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Ball
{
float radius;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
const int n_balls = 100;
// Шаг по времени
const float delta_t = 0.1; ///
// Создаём экземпляр класса окно
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
// Задаём максимальное количество кадров в секунду
window.setFramerateLimit(60);
// Так как sf::CircleShape занимает много памяти, создаём всего 1 экземпляр
sf::CircleShape circle(50.0f);
circle.setFillColor({200, 216, 200});
std::vector<Ball> balls;
balls.resize(n_balls);
for (int i = 0; i < n_balls; i++)
{
balls[i].radius = 4 + rand() % 8;
balls[i].position = {(float)(rand() % width), (float)(rand() % height)};
balls[i].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
// В данном примере проверяем окно на закрытие
if (event.type == sf::Event::Closed)
window.close();
}
// очистить скрытый холст черным цветом
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
if ((balls[i].position.x < 0) || (balls[i].position.x > width))
balls[i].velocity.x = -balls[i].velocity.x;
if ((balls[i].position.y < 0) || (balls[i].position.y > height))
balls[i].velocity.y = -balls[i].velocity.y;
// Используем 1 sf::CircleShape, чтобы нарисовать все шары
circle.setRadius(balls[i].radius);
// setOrigin - задаёт центр объекта
// По умолчанию центр - в левом верхнем угле объекта
// Строка ниже устанавливает центр в центре шарика
// В дальнейшем функция, setPosition устанавливает положение шарика так,
// чтобы его центр был в точке balls[i].position
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
window.draw(circle);
}
// отображаем содержимое скрытого холста на экран
window.display();
}
return 0;
}

@ -0,0 +1,89 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
const int min_distance = 5;
const float G = 500;
struct Ball
{
float radius;
float mass = 1;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
const int n_balls = 15;
// Шаг по времени
const float delta_t = 0.1;
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
window.setFramerateLimit(60);
sf::CircleShape circle(50.0f);
circle.setFillColor({200, 216, 200});
std::vector<Ball> balls;
balls.resize(n_balls);
for (int i = 0; i < n_balls; i++)
{
balls[i].radius = 4 + rand() % 8;
balls[i].position = {(float)(rand() % width), (float)(rand() % height)};
balls[i].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
for (int j = 0; j < n_balls; ++j) {
if (i == j)
continue;
float distance = std::sqrt((balls[j].position.x - balls[i].position.x) * (balls[j].position.x - balls[i].position.x) + (balls[j].position.y - balls[i].position.y) * (balls[j].position.y - balls[i].position.y));
if (distance < min_distance)
continue;
auto direction = balls[j].position - balls[i].position;
balls[i].velocity += (direction * G * delta_t * balls[j].mass) / (distance * distance);
}
if (((balls[i].position.x - balls[i].radius) < 0) || (balls[i].position.x + balls[i].radius> width)) {
balls[i].velocity.x = -balls[i].velocity.x;
balls[i].position.x = (balls[i].position.x - balls[i].radius < 0 ? balls[i].radius : width - balls[i].radius);
}
if ((balls[i].position.y - balls[i].radius < 0) || (balls[i].position.y + balls[i].radius > height)) {
balls[i].velocity.y = -balls[i].velocity.y;
balls[i].position.y = (balls[i].position.y - balls[i].radius < 0 ? balls[i].radius : height - balls[i].radius);
}
circle.setRadius(balls[i].radius);
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
window.draw(circle);
}
window.display();
}
return 0;
}

@ -0,0 +1,95 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
const int min_distance = 5;
const float G = 500;
struct Ball
{
float radius;
float mass;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
const int n_balls = 15;
// Шаг по времени
const float delta_t = 0.1;
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
window.setFramerateLimit(60);
sf::CircleShape circle(50.0f);
circle.setFillColor({200, 216, 200});
std::vector<Ball> balls;
balls.resize(n_balls);
for (int i = 0; i < n_balls; i++)
{
balls[i].radius = 4 + rand() % 8;
balls[i].mass = balls[i].radius * balls[i].radius / 100;
balls[i].position = {(float)(rand() % width), (float)(rand() % height)};
balls[i].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
}
/* balls[0].radius = 15;
balls[0].mass = 1000;
balls[0].position = {(float)(rand() % width), (float)(rand() % height)};
balls[0].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
*/
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
for (int j = 0; j < n_balls; ++j) {
if (i == j)
continue;
float distance = std::sqrt((balls[j].position.x - balls[i].position.x) * (balls[j].position.x - balls[i].position.x) + (balls[j].position.y - balls[i].position.y) * (balls[j].position.y - balls[i].position.y));
if (distance < min_distance)
continue;
auto direction = balls[j].position - balls[i].position;
balls[i].velocity += (direction * G * delta_t * balls[j].mass) / (distance * distance);
}
if (((balls[i].position.x - balls[i].radius) < 0) || (balls[i].position.x + balls[i].radius> width)) {
balls[i].velocity.x = -balls[i].velocity.x;
balls[i].position.x = (balls[i].position.x - balls[i].radius < 0 ? balls[i].radius : width - balls[i].radius);
}
if ((balls[i].position.y - balls[i].radius < 0) || (balls[i].position.y + balls[i].radius > height)) {
balls[i].velocity.y = -balls[i].velocity.y;
balls[i].position.y = (balls[i].position.y - balls[i].radius < 0 ? balls[i].radius : height - balls[i].radius);
}
circle.setRadius(balls[i].radius);
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
window.draw(circle);
}
window.display();
}
return 0;
}

@ -0,0 +1,99 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
const int min_distance = 5;
const float K = 25;
struct Ball
{
float radius;
float charge;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
int n_balls = 4;
const float delta_t = 0.1;
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
window.setFramerateLimit(60);
sf::CircleShape circle(50.0f);
std::vector<Ball> balls;
balls.resize(n_balls);
for (int i = 0; i < n_balls; i++)
{
balls[i].radius = 4 + rand() % 8;
balls[i].charge = (rand() % 8 - rand() % 8) * balls[i].radius * balls[i].radius;
while (!balls[i].charge) {
balls[i].charge = (rand() % 8 - rand() % 8) * balls[i].radius * balls[i].radius;
}
balls[i].position = {(float)(rand() % width), (float)(rand() % height)};
balls[i].velocity = {(float)(rand() % 100 - 50), (float)(rand() % 100 - 50)};
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
for (int j = 0; j < n_balls; ++j) {
if (i == j)
continue;
float distance = std::sqrt((balls[j].position.x - balls[i].position.x) * (balls[j].position.x - balls[i].position.x) + (balls[j].position.y - balls[i].position.y) * (balls[j].position.y - balls[i].position.y));
if (distance < min_distance)
continue;
auto direction = balls[j].position - balls[i].position;
if (balls[i].charge * balls[j].charge > 0)
balls[i].velocity -= (direction * K * delta_t * std::abs(balls[j].charge)) / (distance * distance);
else
balls[i].velocity += (direction * K * delta_t * std::abs(balls[j].charge)) / (distance * distance);
}
if (((balls[i].position.x - balls[i].radius) < 0) || (balls[i].position.x + balls[i].radius> width)) {
balls[i].velocity.x = -balls[i].velocity.x;
balls[i].position.x = (balls[i].position.x - balls[i].radius < 0 ? balls[i].radius : width - balls[i].radius);
}
if ((balls[i].position.y - balls[i].radius < 0) || (balls[i].position.y + balls[i].radius > height)) {
balls[i].velocity.y = -balls[i].velocity.y;
balls[i].position.y = (balls[i].position.y - balls[i].radius < 0 ? balls[i].radius : height - balls[i].radius);
}
circle.setRadius(balls[i].radius);
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
if (balls[i].charge > 0)
circle.setFillColor({static_cast<unsigned char>(balls[i].charge/1152 * 255 + 100), 0, 0});
else
circle.setFillColor({0, 0, static_cast<unsigned char>(std::abs(balls[i].charge)/1152 * 255 + 100)});
window.draw(circle);
}
window.display();
}
return 0;
}

@ -0,0 +1,114 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
const int min_distance = 5;
const float K = 5;
struct Ball
{
float radius;
float charge;
sf::Vector2f position;
sf::Vector2f velocity;
};
int main()
{
srand(time(0));
const int width = 1000;
const int height = 800;
int n_balls = 0;
char sign = 1;
// Шаг по времени
const float delta_t = 0.1;
sf::RenderWindow window(sf::VideoMode(width, height), "My window");
window.setFramerateLimit(60);
sf::CircleShape circle(50.0f);
std::vector<Ball> balls;
balls.resize(n_balls);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::LShift) {
sign = -1;
}
}
if (event.type == sf::Event::KeyReleased) {
if (event.key.code == sf::Keyboard::LShift) {
sign = 1;
}
}
if(event.type == sf::Event::MouseButtonPressed) {
Ball b;
if(event.mouseButton.button == sf::Mouse::Right)
b.radius = 15;
else if(event.mouseButton.button == sf::Mouse::Left)
b.radius = 5;
b.charge = sign * b.radius * b.radius;
b.position = {(float)(event.mouseButton.x), (float)(event.mouseButton.y)};
b.velocity = {(float)(0), (float)(0)};
balls.push_back(b);
n_balls++;
}
}
window.clear(sf::Color::Black);
for (int i = 0; i < n_balls; i++)
{
balls[i].position += balls[i].velocity * delta_t;
for (int j = 0; j < n_balls; ++j) {
if (i == j)
continue;
float distance = std::sqrt((balls[j].position.x - balls[i].position.x) * (balls[j].position.x - balls[i].position.x) + (balls[j].position.y - balls[i].position.y) * (balls[j].position.y - balls[i].position.y));
if (distance < min_distance)
continue;
auto direction = balls[j].position - balls[i].position;
if (balls[i].charge * balls[j].charge > 0)
balls[i].velocity -= (direction * K * delta_t * std::abs(balls[j].charge)) / (distance * distance);
else
balls[i].velocity += (direction * K * delta_t * std::abs(balls[j].charge)) / (distance * distance);
}
if (((balls[i].position.x - balls[i].radius) < 0) || (balls[i].position.x + balls[i].radius> width)) {
balls[i].velocity.x = -balls[i].velocity.x;
balls[i].position.x = (balls[i].position.x - balls[i].radius < 0 ? balls[i].radius : width - balls[i].radius);
}
if ((balls[i].position.y - balls[i].radius < 0) || (balls[i].position.y + balls[i].radius > height)) {
balls[i].velocity.y = -balls[i].velocity.y;
balls[i].position.y = (balls[i].position.y - balls[i].radius < 0 ? balls[i].radius : height - balls[i].radius);
}
circle.setRadius(balls[i].radius);
circle.setOrigin(balls[i].radius, balls[i].radius);
circle.setPosition(balls[i].position);
if (balls[i].charge > 0)
circle.setFillColor({200, 0, 0});
else
circle.setFillColor({0, 0, 200});
window.draw(circle);
}
window.display();
}
return 0;
}

@ -0,0 +1 @@
07_n_bodies_charges_mouse

@ -0,0 +1,9 @@
#path = ../../../3rdparty/SFML-2.5.1
#select_move_delete:
# g++ ./select_move_delete.cpp -std=c++11 -o select_move_delete.exe -I $(path)/include -L $(path)/lib/ -lsfml-graphics -lsfml-window -lsfml-system
#select_move_delete:
# g++ ./select_move_delete.cpp -std=c++11 -o select_move_delete.exe -I $(path)/include -L $(path)/lib/ -lsfml-graphics -lsfml-window -lsfml-system
build:
g++ ./select_move_delete.cpp -std=c++11 -o select_move_delete -lsfml-graphics -lsfml-window -lsfml-system
build_debug:
g++ ./select_move_delete.cpp -std=c++11 -o select_move_delete -lsfml-graphics -lsfml-window -lsfml-system -D_DEBUG

@ -0,0 +1,143 @@
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
/*
Класс ContextMenu - контекстное меню
При нажатии правой кнопки мыши на экране появляется контекстное меню
Публичные методы:
ContextMenu(sf::RenderWindow&, const sf::Font&)
Конструктор принимает окно для отрисовки и шрифт
void addButton(const sf::String& name)
Добавить новый элемент в контекстное меню по имени name
void draw()
Нарисовать контекстное меню в окне, которое было передано в конструктор
int handleEvent(const sf::Event& event)
Обрабатывает событие event и возвращает целое число
Если это событие MousePressed и был выбран один из вариантов
контекстного меню, то вернёт номер этого варианта
Нумерация начинается с нуля
В ином случае вернёт -1
*/
class ContextMenu
{
private:
inline static const sf::Color kDefaultColor {sf::Color(190, 210, 190)};
inline static const sf::Color kHoverColor {sf::Color(150, 170, 150)};
inline static const sf::Color kTextColor {sf::Color::Black};
inline static const int kButtonHeight = 20;
inline static const int kCharacterSize = 16;
inline static const float kMenuWidthMultiplier = 1.2;
sf::RenderWindow& mRenderWindow;
sf::RectangleShape mShape;
sf::RectangleShape mHoverShape;
sf::Text mText;
std::vector<sf::String> mButtons;
bool mIsOpened = false;
bool mIsUpdated = false;
int mHoverPosition = -1;
int onMousePressed(const sf::Event& event)
{
if (event.mouseButton.button == sf::Mouse::Right) {
mIsOpened = true;
sf::Vector2f mousePosition = mRenderWindow.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
mShape.setPosition(mousePosition);
}
if (event.mouseButton.button == sf::Mouse::Left && mIsOpened) {
mIsOpened = false;
return mHoverPosition;
}
return -1;
}
void onMouseMove(const sf::Event& event)
{
if (!mIsOpened) {
return;
}
sf::Vector2f mousePosition = mRenderWindow.mapPixelToCoords({event.mouseMove.x, event.mouseMove.y});
if (mShape.getGlobalBounds().contains(mousePosition)) {
mHoverPosition = (mousePosition.y - mShape.getPosition().y) / kButtonHeight;
}
else {
mHoverPosition = -1;
}
}
public:
ContextMenu(sf::RenderWindow& window, const sf::Font& font) : mRenderWindow(window)
{
mText.setFont(font);
mText.setCharacterSize(kCharacterSize);
mText.setFillColor(kTextColor);
mShape.setFillColor(kDefaultColor);
mHoverShape.setFillColor(kHoverColor);
mIsOpened = false;
mIsUpdated = false;
mHoverPosition = -1;
}
void addButton(const sf::String& name)
{
mButtons.push_back(name);
mIsUpdated = false;
}
void draw()
{
if (!mIsOpened) {
return;
}
// Если добавили новый вариант, то её текст может быть длиннее
// чем у других. Нужно расширить прямоугольники.
if (!mIsUpdated) {
int maxSizeX = 0;
for (int i = 0; i < mButtons.size(); i++) {
mText.setString(mButtons[i]);
if (mText.getLocalBounds().width > maxSizeX) {
maxSizeX = mText.getLocalBounds().width;
}
}
maxSizeX *= kMenuWidthMultiplier;
mShape.setSize({(float)maxSizeX, (float)(kButtonHeight * mButtons.size())});
mHoverShape.setSize({(float)maxSizeX, (float)(kButtonHeight)});
mIsUpdated = true;
}
mRenderWindow.draw(mShape);
if (mHoverPosition >= 0){
mHoverShape.setPosition(mShape.getPosition().x, mShape.getPosition().y + mHoverPosition * kButtonHeight);
mRenderWindow.draw(mHoverShape);
}
for (int i = 0; i < mButtons.size(); i++) {
mText.setString(mButtons[i]);
mText.setPosition(mShape.getPosition().x, mShape.getPosition().y + i * kButtonHeight);
mRenderWindow.draw(mText);
}
}
int handleEvent(const sf::Event& event) {
if (event.type == sf::Event::MouseMoved) {
onMouseMove(event);
}
else if (event.type == sf::Event::MouseButtonPressed) {
return onMousePressed(event);
}
return -1;
}
};

@ -0,0 +1,287 @@
#include <iostream>
#include <cmath>
#include <list>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "context_menu.hpp"
using namespace std;
float distance(sf::Vector2f start, sf::Vector2f finish)
{
return sqrtf((start.x - finish.x)*(start.x - finish.x) + (start.y - finish.y)*(start.y - finish.y));
}
void drawLine(sf::RenderWindow& window, sf::Vector2f start, sf::Vector2f finish, sf::Color color = sf::Color::White)
{
sf::Vertex line_vertices[2] = {sf::Vertex(start, color), sf::Vertex(finish, color)};
window.draw(line_vertices, 2, sf::Lines);
}
struct Ball
{
sf::Vector2f position;
float radius;
bool isChoosen;
sf::Color color;
Ball(sf::Vector2f position, float radius, sf::Color color = sf::Color::White) : position(position), radius(radius), color(color)
{
isChoosen = false;
}
void draw(sf::RenderWindow& window) const
{
sf::CircleShape circle(radius);
circle.setFillColor(color);
circle.setOrigin({radius, radius});
circle.setPosition(position);
window.draw(circle);
if (isChoosen) {
const float fraction = 0.7;
drawLine(window, {position.x - radius, position.y + radius}, {position.x - radius, position.y + radius*fraction});
drawLine(window, {position.x - radius, position.y + radius}, {position.x - fraction * radius, position.y + radius});
drawLine(window, {position.x + radius, position.y + radius}, {position.x + radius, position.y + radius*fraction});
drawLine(window, {position.x + radius, position.y + radius}, {position.x + radius*fraction, position.y + radius});
drawLine(window, {position.x + radius, position.y - radius}, {position.x + radius*fraction, position.y - radius});
drawLine(window, {position.x + radius, position.y - radius}, {position.x + radius, position.y - radius*fraction});
drawLine(window, {position.x - radius, position.y - radius}, {position.x - radius*fraction, position.y - radius});
drawLine(window, {position.x - radius, position.y - radius}, {position.x - radius, position.y - radius*fraction});
}
}
void setColor(sf::Uint8 r, sf::Uint8 g, sf::Uint8 b, sf::Uint8 a = 255) {
color.r = r;
color.g = g;
color.b = b;
color.a = a;
}
};
void deleteChoosen(list<Ball>& balls) {
for (list<Ball>::const_iterator it = balls.begin(); it != balls.end();) {
if (it->isChoosen)
it = balls.erase(it);
else
++it;
}
}
void copyBalls(list<Ball>& balls, list<Ball>& buffer) {
buffer.clear();
for (list<Ball>::iterator it = balls.begin(); it != balls.end(); ++it)
if (it->isChoosen)
buffer.push_back(*it);
}
void pasteBalls(list<Ball>& balls, list<Ball>& buffer) {
for (list<Ball>::iterator it = buffer.begin(); it != buffer.end(); ++it)
balls.push_back(*it);
}
void recolorChoosen(list<Ball>& balls) {
for (Ball& b : balls)
if (b.isChoosen)
b.setColor(rand() % 255, rand() % 255, rand() % 255);
}
void resizeChoosen(list<Ball>& balls, double scaling) {
for (list<Ball>::iterator it = balls.begin(); it != balls.end(); ++it) {
if (it->isChoosen)
it->radius += it->radius * scaling;
}
}
int main()
{
sf::ContextSettings settings;
settings.antialiasingLevel = 8;
sf::RenderWindow window(sf::VideoMode(800, 600), "Select, Move, Delete!", sf::Style::Default, settings);
window.setFramerateLimit(60);
std::list<Ball> balls;
balls.push_back(Ball({200, 200}, 26));
balls.push_back(Ball({400, 300}, 20));
balls.push_back(Ball({500, 100}, 16));
balls.push_back(Ball({200, 400}, 18));
balls.push_back(Ball({350, 150}, 22));
balls.push_back(Ball({750, 400}, 21));
list<Ball> buffer{};
sf::RectangleShape selectionRect;
selectionRect.setFillColor(sf::Color(150, 150, 240, 50));
selectionRect.setOutlineColor(sf::Color(200, 200, 255));
selectionRect.setOutlineThickness(1);
bool isSelecting = false;
/* "Режим выделения" */
bool isMovingMode = false;
/* Необходимо, чтоб в режиме выделения считать смещение */
Ball* selected_ball = nullptr;
bool isContextMenu = false;
sf::Vector2f mousePosition{};
sf::Font font;
if (!font.loadFromFile("consolas.ttf")) {
std::cout << "Can't load button font" << std::endl;
}
std::vector<sf::String> contextMenuStrings {"Delete", "Create", "Random Color", "Increase", "Decrease", "Copy", "Cut", "Paste"};
ContextMenu contextMenu(window, font);
for (const auto& el : contextMenuStrings) {
contextMenu.addButton(el);
}
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
int result = contextMenu.handleEvent(event);
switch(result) {
case 0:
deleteChoosen(balls);
break;
case 1:
mousePosition = window.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
balls.push_back(Ball(mousePosition, 5 + rand() % 40));
break;
case 2:
recolorChoosen(balls);
break;
case 3:
resizeChoosen(balls, 0.25);
break;
case 4:
resizeChoosen(balls, -0.25);
break;
case 5:
copyBalls(balls, buffer);
break;
case 6:
copyBalls(balls, buffer);
deleteChoosen(balls);
break;
case 7:
pasteBalls(balls, buffer);
break;
}
if (event.type == sf::Event::MouseMoved) {
mousePosition = window.mapPixelToCoords({event.mouseMove.x, event.mouseMove.y});
// Если мы находимся в режиме выделения и не попали в уже выделенный шарик, то меняем прямоугольник выделения
if (isSelecting & !isMovingMode) {
selectionRect.setSize(mousePosition - selectionRect.getPosition());
}
// Если в режиме перемещения, то двигаем все выделенные шарики
if (isMovingMode) {
sf::Vector2f direction = selected_ball->position - mousePosition;
for (Ball& b : balls) {
if (b.isChoosen) {
b.position -= direction;
}
}
}
}
if (event.type == sf::Event::MouseButtonPressed) {
mousePosition = window.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
if (event.mouseButton.button == sf::Mouse::Left) {
for (Ball& b : balls) {
/* Если попали в какой-то шарик */
if (distance(mousePosition, b.position) < b.radius) {
selected_ball = &b;
// Если попали в еще не выбранный шарик и не зажат левый Ctrl, то снимаем выделение со всех остальных
if(!b.isChoosen && !sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) {
for (Ball& ball : balls) {
ball.isChoosen = false;
}
}
b.isChoosen = true; //
isMovingMode = true;
break;
}
}
// ЛКМ + левый Alt - добавляем новый случайный шарик
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt)) {
balls.push_back(Ball(mousePosition, 5 + rand() % 40));
}
// Задаём новое положения прямоугольника выделения
if (!isMovingMode) {
isSelecting = true;
selectionRect.setPosition(mousePosition);
selectionRect.setSize({0, 0});
}
}
if (event.mouseButton.button == sf::Mouse::Right) {
isContextMenu = true;
}
}
// При отпускании кнопки мыши выходим из режима выделения
if (event.type == sf::Event::MouseButtonReleased) {
// Если не зажат левый Ctrl и не в режиме перемещения шариков, то все выделения снимаются
if (!sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) && !isMovingMode && !isContextMenu) {
for (Ball& b : balls) {
b.isChoosen = false;
}
}
if (isSelecting) {
sf::Vector2f size = selectionRect.getSize();
sf::Vector2f position = selectionRect.getPosition();
for (Ball& b : balls) {
if ( ((b.position.x - b.radius > position.x) && (b.position.x + b.radius < position.x + size.x)) ||
((b.position.x + b.radius < position.x) && (b.position.x - b.radius > position.x + size.x))
)
if (((b.position.y - b.radius > position.y) && (b.position.y + b.radius < position.y + size.y)) ||
((b.position.y + b.radius < position.y) && (b.position.y - b.radius > position.y + size.y))
)
b.isChoosen = true;
}
}
isSelecting = false;
isMovingMode = false;
isContextMenu = false;
}
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::C)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
copyBalls(balls, buffer);
if (event.key.code == sf::Keyboard::V)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
pasteBalls(balls, buffer);
if (event.key.code == sf::Keyboard::X)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) {
copyBalls(balls, buffer);
deleteChoosen(balls);
}
if (event.key.code == sf::Keyboard::Space)
recolorChoosen(balls);
if (event.key.code == sf::Keyboard::Delete) {
deleteChoosen(balls);
}
}
}
window.clear(sf::Color::Black);
// Рисуем все шарики
for (Ball& b : balls) {
b.draw(window);
}
// Рисуем прямоугольник выделения
if (isSelecting) {
window.draw(selectionRect);
}
contextMenu.draw();
window.display();
}
return 0;
}

@ -0,0 +1,11 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/
!_TAG_PROC_CWD /home/nihonium/projects/mipt_cpp/seminar11_events/01_select_move_delete/ //
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 5.9.0 /p5.9.20220828.0/

@ -0,0 +1,6 @@
build:
g++ ./slider.cpp -std=c++11 -o slider -lsfml-graphics -lsfml-window -lsfml-system
build_debug:
g++ ./slider.cpp -std=c++11 -o slider -lsfml-graphics -lsfml-window -lsfml-system -D_DEBUG
build_circle:
g++ ./circle.cpp -std=c++11 -o circle -lsfml-graphics -lsfml-window -lsfml-system

@ -0,0 +1,57 @@
#include <iostream>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "slider.hpp"
int main()
{
int result;
unsigned char r, g, b;
sf::RenderWindow window(sf::VideoMode(800, 600), "Slider");
window.setFramerateLimit(60);
sf::Font font;
if (!font.loadFromFile("consolas.ttf")) {
std::cout << "Can't load button font" << std::endl;
}
Slider slider(window, font, sf::Vector2f{200, 100}, 10, 250);
Slider slider_r(window, font, sf::Vector2f{800, 200}, 0, 255);
Slider slider_g(window, font, sf::Vector2f{800, 300}, 0, 255);
Slider slider_b(window, font, sf::Vector2f{800, 400}, 0, 255);
sf::CircleShape circle(10);
circle.setPosition(sf::Vector2f{400, 400});
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
result = slider.handleEvent(event);
/* Centering of the circle */
circle.setPosition(circle.getPosition() + sf::Vector2f{circle.getRadius() - result, circle.getRadius() - result});
circle.setRadius(result);
r = slider_r.handleEvent(event);
g = slider_g.handleEvent(event);
b = slider_b.handleEvent(event);
circle.setFillColor(sf::Color{r, g, b});
}
window.clear(sf::Color::Black);
slider.draw();
slider_r.draw();
slider_g.draw();
slider_b.draw();
window.draw(circle);
window.display();
}
return 0;
}

@ -0,0 +1,36 @@
#include <iostream>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "slider.hpp"
int main()
{
int result;
sf::RenderWindow window(sf::VideoMode(800, 600), "Slider");
window.setFramerateLimit(60);
sf::Font font;
if (!font.loadFromFile("consolas.ttf")) {
std::cout << "Can't load button font" << std::endl;
}
Slider slider(window, font);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
result = slider.handleEvent(event);
std::cout << result << std::endl;
}
window.clear(sf::Color::Black);
slider.draw();
window.display();
}
return 0;
}

@ -0,0 +1,113 @@
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <sstream>
class Slider
{
private:
const int kCharacterSize = 14;
int mMinValue;
int mMaxValue;
float mSliderPosition = 0;
sf::RenderWindow& mRenderWindow;
sf::RectangleShape mSlider;
sf::RectangleShape mAxis;
sf::Text mText;
bool mIsPressed = false;
void onMousePressed(const sf::Event& event)
{
if (event.mouseButton.button == sf::Mouse::Left) {
sf::Vector2f mousePosition = mRenderWindow.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
if (mSlider.getGlobalBounds().contains(mousePosition))
mIsPressed = true;
else if (mAxis.getGlobalBounds().contains(mousePosition))
{
mIsPressed = true;
if (mousePosition.x + mSlider.getSize().x <= mAxis.getPosition().x + mAxis.getSize().x) {
mSlider.setPosition({mousePosition.x, mSlider.getPosition().y});
mSliderPosition = (mSlider.getPosition().x - mAxis.getPosition().x) / (mAxis.getSize().x - mSlider.getSize().x);
}
else {
mSlider.setPosition({mAxis.getPosition().x + mAxis.getSize().x - mSlider.getSize().x, mSlider.getPosition().y});
mSliderPosition = 1;
}
}
}
}
void onMouseMove(const sf::Event& event)
{
if (!mIsPressed) {
return;
}
sf::Vector2f mousePosition = mRenderWindow.mapPixelToCoords({event.mouseMove.x, event.mouseMove.y});
if ((mousePosition.x >= mAxis.getPosition().x) && (mousePosition.x + mSlider.getSize().x <= mAxis.getPosition().x + mAxis.getSize().x)) {
mSlider.setPosition({mousePosition.x, mSlider.getPosition().y});
}
else if (mousePosition.x < mAxis.getPosition().x) {
mSlider.setPosition({mAxis.getPosition().x, mSlider.getPosition().y});
}
else if (mousePosition.x + mSlider.getSize().x > mAxis.getPosition().x + mAxis.getSize().x) {
mSlider.setPosition({mAxis.getPosition().x + mAxis.getSize().x - mSlider.getSize().x, mSlider.getPosition().y});
}
mSliderPosition = (mSlider.getPosition().x - mAxis.getPosition().x) / (mAxis.getSize().x - mSlider.getSize().x);
}
public:
Slider(sf::RenderWindow& window, const sf::Font& font, sf::Vector2f position = {100,200},int min = 0, int max = 100) : mRenderWindow(window)
{
mSlider.setFillColor(sf::Color::Red);
mSlider.setSize({10,30});
mSlider.setPosition(position - sf::Vector2f{0, 10});
mSlider.setOutlineColor(sf::Color::Black);
mSlider.setOutlineThickness(2);
mAxis.setFillColor(sf::Color::White);
mAxis.setSize({500,10});
mAxis.setPosition(position);
std::stringstream ss;
ss << mMinValue;
mText.setString(ss.str());
mText.setFont(font);
mText.setCharacterSize(kCharacterSize);
mText.setFillColor(sf::Color::White);
mText.setPosition(position + sf::Vector2f{mAxis.getSize().x + 10, -4});
mMinValue = min;
mMaxValue = max;
mIsPressed = false;
}
void draw()
{
std::stringstream ss;
ss << mMinValue + (mMaxValue - mMinValue) * mSliderPosition;
mText.setString(ss.str());
mRenderWindow.draw(mAxis);
mRenderWindow.draw(mSlider);
mRenderWindow.draw(mText);
}
int handleEvent(const sf::Event& event) {
if (event.type == sf::Event::MouseMoved) {
onMouseMove(event);
}
else if (event.type == sf::Event::MouseButtonPressed) {
onMousePressed(event);
}
else if (event.type == sf::Event::MouseButtonReleased) {
mIsPressed = false;
}
return mMinValue + (mMaxValue - mMinValue) * mSliderPosition;
}
};

@ -0,0 +1,11 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/
!_TAG_PROC_CWD /home/nihonium/projects/mipt_cpp/seminar11_events/02_slider/ //
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 5.9.0 /p5.9.20220828.0/

@ -0,0 +1,3 @@
path = ../../../../3rdparty/SFML-2.5.1
arkanoid:
g++ -Wall -Wextra arkanoid.cpp bonus.cpp main.cpp ball.cpp brick_grid.cpp paddle.cpp -std=c++17 -o arkanoid -lsfml-graphics -lsfml-window -lsfml-system

@ -0,0 +1,258 @@
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <list>
#include <cmath>
#include <iostream>
#include "arkanoid.hpp"
#include "bonus.hpp"
const double pi = 3.14159265358979323846;
void Arkanoid::addRandomBonus(sf::Vector2f position)
{
if (m_bonuses.size() > kMaxNumBonuses)
return;
int max_rand = 10000;
if ((rand() % max_rand) * 1.0f / max_rand < m_bonusProbability)
{
int max = 4; int min = 1;
int range = max - min + 1;
int num = rand() % range + min;
switch (num) {
case 1:
m_bonuses.push_back(new TripleBallBonus(position));
break;
case 2:
m_bonuses.push_back(new EnlargePaddleBonus(position));
break;
case 3:
m_bonuses.push_back(new ShrinkPaddleBonus(position));
break;
case 4:
m_bonuses.push_back(new SlowingBonus(position));
break;
}
}
}
// Функция, которая обрабатывает все столкновения шарика
void Arkanoid::handleBallCollisions(Ball& ball)
{
ball.handleWallsCollision(m_border);
ball.handlePaddleCollision(m_paddle);
auto indexes = ball.handleBrickGridCollision(m_brickGrid);
if (indexes.first == -1)
return;
m_brickGrid.deactivateBrick(indexes);
addRandomBonus(ball.position);
}
Arkanoid::Arkanoid(sf::FloatRect border, sf::Font& font) :
m_time{0.0},
m_border{border},
m_paddle{{m_border.left + m_border.width / 2, m_border.top + m_border.height - 100}, {120, 20}},
m_gameState{GameState::stuck},
m_numLives{7}
{
float gap = border.width / 10;
m_brickGrid = BrickGrid({border.left + gap, border.top + gap, border.width - 2 * gap, border.height / 2}, 50, 30);
m_bonusProbability = 0.1;
m_endText.setFont(font);
m_endText.setString("You Win!");
m_endText.setCharacterSize(100);
m_endText.setFillColor(sf::Color::White);
sf::FloatRect textRect = m_endText.getLocalBounds();
m_endText.setOrigin(textRect.left + textRect.width / 2.0f, textRect.top + textRect.height / 2.0f);
m_endText.setPosition({border.left + border.width / 2, border.top + border.height / 2});
}
sf::FloatRect Arkanoid::getBorder() const
{
return m_border;
}
const Paddle& Arkanoid::getPaddle() const
{
return m_paddle;
}
const BrickGrid& Arkanoid::getBrickGrid() const
{
return m_brickGrid;
}
void Arkanoid::addBall(const Ball& ball)
{
if (m_balls.size() < kMaxNumBalls)
m_balls.push_back(ball);
}
bool Arkanoid::isMaxBalls()
{
return m_balls.size() == kMaxNumBalls - 1;
}
// Эта функция вызывается каждый кадр
void Arkanoid::update(const sf::RenderWindow& window, float dt)
{
m_time += dt;
// Устанавливаем положение ракетки
sf::Vector2f mousePosition = window.mapPixelToCoords(sf::Mouse::getPosition(window));
m_paddle.position.x = mousePosition.x;
// Обрабатываем шарики
for (std::list<Ball>::iterator it = m_balls.begin(); it != m_balls.end();)
{
(*it).update(dt);
handleBallCollisions(*it);
if ((*it).position.y > m_border.top + m_border.height)
{
it = m_balls.erase(it);
}
else
{
it++;
}
}
// Если шариков нет, то переходи в режим начала игры и уменьшаем кол-во жизней
if (m_gameState == GameState::running && m_balls.size() == 0)
{
m_effects.clear();
m_gameState = GameState::stuck;
m_numLives--;
}
// Если жизни кончились, то переходим в состояние конца игры (проигрыш)
if (m_numLives < 0)
{
m_gameState = GameState::endLose;
}
// Если блоки кончились, то переходим в состояние конца игры (победа)
if (m_brickGrid.getNumActiveBricks() == 0)
{
m_gameState = GameState::endWin;
}
// Обрабатываем бонусы
for (auto it = m_bonuses.begin(); it != m_bonuses.end();)
{
(*it)->update(dt);
if ((*it)->isColiding(m_paddle))
{
(*it)->activate(*this);
delete *it;
it = m_bonuses.erase(it);
}
else if ((*it)->m_position.y > m_border.top + m_border.height)
{
delete (*it);
it = m_bonuses.erase(it);
}
else
{
it++;
}
}
/* Обработка эффектов */
for (auto it = m_effects.begin(); it != m_effects.end();)
{
if ((*it)->isExpired(m_time))
{
(*it)->deactivate(*this);
delete *it;
it = m_effects.erase(it);
}
else {
it++;
}
}
}
void Arkanoid::draw(sf::RenderWindow& window)
{
// Рисуем задний прямоугольник
static sf::RectangleShape background {{m_border.width, m_border.height}};
background.setPosition({m_border.left, m_border.top});
background.setFillColor(kBackgroundColor);
window.draw(background);
// Рисуем блоки
m_brickGrid.draw(window);
// Рисуем шарики
for (Ball& ball : m_balls)
{
ball.draw(window);
}
// Рисуем ракетку
m_paddle.draw(window);
// Если мы в режиме начала игры, то рисуем шарик на ракетке
if (m_gameState == GameState::stuck)
{
m_initialBall.position = {m_paddle.position.x, m_paddle.position.y - m_paddle.size.y / 2 - m_initialBall.radius};
m_initialBall.position = {m_paddle.position.x, m_paddle.position.y - m_paddle.size.y / 2 - m_initialBall.radius};
m_initialBall.draw(window);
}
// Рисуем кол-во жизней вверху слева
for (int i = 0; i < m_numLives; i++)
{
m_initialBall.position = {m_initialBall.radius * (3 * i + 2), 2 * m_initialBall.radius};
m_initialBall.draw(window);
}
// Рисуем бонусы
for (Bonus* pbonus : m_bonuses)
{
pbonus->draw(window);
}
// При завершении игры рисуем надпись
if (m_gameState == GameState::endWin)
{
m_endText.setString("You Win!");
window.draw(m_endText);
}
// При завершении игры рисуем надпись
if (m_gameState == GameState::endLose)
{
m_endText.setString("You Lose!");
window.draw(m_endText);
}
}
void Arkanoid::onMousePressed(sf::Event& event)
{
switch (m_gameState)
{
case GameState::stuck:
if (event.mouseButton.button == sf::Mouse::Left)
{
m_gameState = GameState::running;
float velocityAngle = (rand() % 100 + 40) * pi / 180;
float velocityNorm = Ball::initialVelocity;
sf::Vector2f newPosition = {m_paddle.position.x, m_paddle.position.y - m_paddle.size.y / 2.0f - m_initialBall.radius};
sf::Vector2f newVelocity = {-velocityNorm * cosf(velocityAngle), -velocityNorm * sinf(velocityAngle)};
addBall({m_initialBall.radius, newPosition, newVelocity});
}
break;
case GameState::running:
break;
case GameState::endLose:
break;
case GameState::endWin:
break;
}
}

@ -0,0 +1,85 @@
#pragma once
#include <list>
#include "ball.hpp"
#include "brick_grid.hpp"
#include "paddle.hpp"
class Bonus;
class Effect;
class Arkanoid
{
private:
// Константы:
// Цвет задника
const sf::Color kBackgroundColor {12, 31, 47};
// Максимально возможное количество шариков в один момент времени
const unsigned kMaxNumBalls {250};
// Максимально возможное количество бонусов в один момент времени
const unsigned kMaxNumBonuses {10};
// Время, которое прошло с начала игры в секундах
double m_time;
// Границы игрового поля
sf::FloatRect m_border;
// Связный список всех шариков
std::list<Ball> m_balls;
// Объект, задающий состояние сетки блоков
BrickGrid m_brickGrid;
// Ракетка
Paddle m_paddle;
// Состояние игры
enum class GameState {stuck, running, endLose, endWin};
GameState m_gameState;
// Текущее число жизней
int m_numLives;
// Связный список указателей на бонусы
// Почему указатели - для реализации полиформизма
// Так как в будущем мы хотим сделать несколько вариантов бонусов
std::list<Bonus*> m_bonuses;
std::list<Effect*> m_effects;
// Вероятность того, что при разрушении блока выпадет бонус
float m_bonusProbability;
// Макет шарика, используемый для рисова
Ball m_initialBall {6, {0, 0}, {0, 0}};
// Текст, который рисуется в конце игры
sf::Text m_endText;
void addRandomBonus(sf::Vector2f position);
// Функция, которая обрабатывает все столкновения шарика
void handleBallCollisions(Ball& ball);
public:
Arkanoid(sf::FloatRect border, sf::Font& font);
sf::FloatRect getBorder() const;
const Paddle& getPaddle() const;
const BrickGrid& getBrickGrid() const;
void addBall(const Ball& ball);
// Эта функция вызывается каждый кадр
void update(const sf::RenderWindow& window, float dt);
void draw(sf::RenderWindow& window);
void onMousePressed(sf::Event& event);
bool isMaxBalls();
// Класс бонус должен быть дружественным, так как он может менять внутреннее состояние игры
friend class Bonus;
friend class TripleBallBonus;
friend class EnlargePaddleBonus;
friend class ShrinkPaddleBonus;
friend class SlowingBonus;
friend class SlowingEffect;
};

@ -0,0 +1,183 @@
#include <cmath>
#include "ball.hpp"
#include "brick_grid.hpp"
#include "paddle.hpp"
// Вспомагательные функции для работы с векторами типа sf::Vector2f
float operator*(const sf::Vector2f& first, const sf::Vector2f& second)
{
return first.x * second.x + first.y * second.y;
}
float norm(sf::Vector2f a)
{
return std::sqrt(a.x * a.x + a.y * a.y);
}
float sqnorm(sf::Vector2f a)
{
return a.x * a.x + a.y * a.y;
}
Ball::Ball(float radius, sf::Vector2f position, sf::Vector2f velocity) :
radius(radius), position(position), velocity(velocity) {}
void Ball::update(float dt)
{
position += velocity * dt;
}
void Ball::draw(sf::RenderWindow& window)
{
static sf::CircleShape shape {};
shape.setRadius(radius);
shape.setOrigin(radius, radius);
shape.setFillColor(color);
shape.setPosition(position);
window.draw(shape);
}
std::pair<sf::Vector2f, bool> Ball::findClosestPoint(const sf::FloatRect& rect) const
{
float left = rect.left;
float right = rect.left + rect.width;
float bottom = rect.top + rect.height;
float top = rect.top;
sf::Vector2f d;
if (position.x < left)
d.x = left;
else if (position.x > right)
d.x = right;
else
d.x = position.x;
if (position.y > bottom)
d.y = bottom;
else if (position.y < top)
d.y = top;
else
d.y = position.y;
d -= position;
bool isColiding = sqnorm(d) < radius * radius;
return {d, isColiding};
}
bool Ball::handleRectCollision(const sf::FloatRect& rect)
{
auto [d, isColiding] = findClosestPoint(rect);
if (!isColiding)
return false;
float closestPointNorm = norm(d);
// Если расстояние == 0, то это значит, что шарик за 1 фрейм зашёл центром внутрь блока
// Отражаем шарик от блока
if (closestPointNorm < 1e-4)
{
if (std::fabs(velocity.x) > std::fabs(velocity.y))
velocity.x *= -1;
else
velocity.y *= -1;
}
// Если расстояние != 0, но шарик касается блока, то мы можем просчитать отражение более точно
// Отражение от углов и по касательной.
else if (closestPointNorm < radius)
{
position -= d * ((radius - closestPointNorm) / closestPointNorm);
velocity -= 2.0f * d * (d * velocity) / (closestPointNorm * closestPointNorm);
}
return true;
}
void Ball::handleWallsCollision(sf::FloatRect boundary)
{
if (position.x < boundary.left + radius)
{
position.x = boundary.left + radius;
velocity.x *= -1;
}
if (position.x > boundary.left + boundary.width - radius)
{
position.x = boundary.left + boundary.width - radius;
velocity.x *= -1;
}
if (position.y < boundary.top + radius)
{
position.y = boundary.top + radius;
velocity.y *= -1;
}
}
std::pair<int, int> Ball::handleBrickGridCollision(const BrickGrid& brickGrid)
{
auto [gridColumns, gridRows] = brickGrid.getGridSizes();
auto [brickWidth, brickHeight] = brickGrid.getBrickSizes();
auto [left, top, width, height] = brickGrid.getBorder();
// Определяем координаты блоков с которыми шарик может пересечься
int brickColumnStart = std::clamp(static_cast<int>((position.x - left - radius) / brickWidth), 0, gridColumns);
int brickColumnFinish = std::clamp(static_cast<int>((position.x - left + radius) / brickWidth) + 1, 0, gridColumns);
int brickRowStart = std::clamp(static_cast<int>((position.y - top - radius) / brickHeight), 0, gridRows);
int brickRowFinish = std::clamp(static_cast<int>((position.y - top + radius) / brickHeight) + 1, 0, gridRows);
// Если шарик находится вне сетки блоков, то выходим
if (brickColumnStart == brickColumnFinish || brickRowStart == brickRowFinish)
return {-1, -1};
// Находим ближайший к центру шарика активный пересекаемый шариком блок
float closestSqNorm = width * width + height * height;
std::pair<int, int> closestBrickIndexes = {-1, -1};
for (int i = brickColumnStart; i < brickColumnFinish; ++i)
{
for (int j = brickRowStart; j < brickRowFinish; ++j)
{
if (!brickGrid.isBrickActive({i, j}))
continue;
sf::FloatRect rect {left + i * brickWidth, top + j * brickHeight, brickWidth, brickHeight};
auto [d, isColiding] = findClosestPoint(rect);
if (!isColiding)
continue;
if (sqnorm(d) < closestSqNorm)
{
closestSqNorm = sqnorm(d);
closestBrickIndexes = {i, j};
}
}
}
// Если такого не нашли, то возвращаем {-1, -1}
if (closestBrickIndexes.first == -1)
return closestBrickIndexes;
// Упруго сталкиваем шарик с найденым блоком
sf::FloatRect rect {left + closestBrickIndexes.first * brickWidth, top + closestBrickIndexes.second * brickHeight, brickWidth, brickHeight};
handleRectCollision(rect);
// Возвращаем координаты блока в сетки блоков
return closestBrickIndexes;
}
// Обрабатываем столкновения шарика с ракеткой
void Ball::handlePaddleCollision(const Paddle& paddle)
{
auto [d, isColiding] = findClosestPoint(paddle.getBorder());
if (!isColiding)
return;
// Столкновение не упругое
// Угол отражения зависит от места на ракетке, куда стукнулся шарик
// Если шарик стукнулся в левую часть ракетки, то он должен полететь влево.
// Если в правую часть ракетки, то вправо.
const float pi = 3.14159265;
float velocityAngle = (position.x - paddle.position.x) / (paddle.size.x + 2 * radius) * (0.8 * pi) + pi / 2;
float velocityNorm = norm(velocity);
velocity.x = - velocityNorm * std::cos(velocityAngle);
velocity.y = - velocityNorm * std::sin(velocityAngle);
}

@ -0,0 +1,31 @@
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
class BrickGrid;
class Paddle;
struct Ball
{
inline static const float initialVelocity = 700;
inline static const sf::Color color {246, 213, 92};
float radius;
sf::Vector2f position;
sf::Vector2f velocity;
Ball(float radius, sf::Vector2f position, sf::Vector2f velocity);
void update(float dt);
void draw(sf::RenderWindow& window);
std::pair<sf::Vector2f, bool> findClosestPoint(const sf::FloatRect& rect) const;
bool handleRectCollision(const sf::FloatRect& rect);
void handleWallsCollision(sf::FloatRect boundary);
std::pair<int, int> handleBrickGridCollision(const BrickGrid& brickGrid);
void handlePaddleCollision(const Paddle& paddle);
};

@ -0,0 +1,221 @@
#include <cmath>
#include <iostream>
#include "bonus.hpp"
#include "arkanoid.hpp"
#include "ball.hpp"
#include "paddle.hpp"
/* =============
* ===Bonuses===
* =============
* */
Bonus::Bonus(sf::Vector2f position): m_position(position)
{
m_time = 0;
}
void Bonus::update(float dt)
{
m_time += dt;
m_position.y += speed * dt;
}
bool Bonus::isColiding(const Paddle& paddle) const
{
bool result = paddle.getBorder().intersects({m_position.x - radius, m_position.y - radius, 2 * radius, 2 * radius});
return result;
}
/*
* TripleBallBonus
* */
void TripleBallBonus::draw(sf::RenderWindow& window) const
{
static sf::CircleShape shape(radius);
shape.setOrigin(radius, radius);
shape.setFillColor(sf::Color{100, 200, 100});
shape.setPosition(m_position);
window.draw(shape);
float angle = 0;
static Ball ball {5, {0, 0}, {0, 0}};
float ballRotationRadius = 7;
ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
ball.draw(window);
angle += 2.0 * M_PI / 3.0;
ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
ball.draw(window);
angle += 2.0 * M_PI / 3.0;
ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
ball.draw(window);
}
void TripleBallBonus::activate(Arkanoid& game)
{
int numBalls = game.m_balls.size();
std::list<Ball>::iterator it = game.m_balls.begin();
bool isSlowed = false;
bool toApply = true;
Effect* slowing_effect = nullptr;
for (auto it = game.m_effects.begin(); it != game.m_effects.end();) {
if ((*it)->effectId == _EFFECT_SLOWING_ID) {
isSlowed = true;
slowing_effect = *it;
break;
}
it++;
}
for (int i = 0; i < numBalls; i++)
{
float angle, vx, vy;
if (game.isMaxBalls()) {
toApply = false;
}
if (toApply) {
angle = rand() % 1000 * (2 * M_PI / 1000);
vx = Ball::initialVelocity * sin(angle);
vy = Ball::initialVelocity * cos(angle);
game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}});
if (isSlowed) {
slowing_effect->activate(game.m_balls.back());
}
}
if (game.isMaxBalls()) {
toApply = false;
}
if (toApply) {
angle = rand() % 1000 * (2 * M_PI / 1000);
vx = Ball::initialVelocity * sin(angle);
vy = Ball::initialVelocity * cos(angle);
game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}});
if (isSlowed) {
slowing_effect->activate(game.m_balls.back());
}
}
it++;
}
}
/*
* EnlargePaddleBonus
* */
void EnlargePaddleBonus::draw(sf::RenderWindow& window) const
{
static sf::CircleShape shape(radius);
shape.setOrigin(radius, radius);
shape.setFillColor(sf::Color{100, 200, 100});
shape.setPosition(m_position);
window.draw(shape);
static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2});
rect.setFillColor(sf::Color::Green);
rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4});
window.draw(rect);
}
void EnlargePaddleBonus::activate(Arkanoid& game)
{
if (game.m_paddle.size.x < 300) {
game.m_paddle.size.x *= 1.5;
}
}
/*
* ShrinkPaddleBonus
* */
void ShrinkPaddleBonus::draw(sf::RenderWindow& window) const
{
static sf::CircleShape shape(radius);
shape.setOrigin(radius, radius);
shape.setFillColor(sf::Color{100, 200, 100});
shape.setPosition(m_position);
window.draw(shape);
static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2});
rect.setFillColor(sf::Color::Red);
rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4});
window.draw(rect);
}
void ShrinkPaddleBonus::activate(Arkanoid& game)
{
if (game.m_paddle.size.x > 40) {
game.m_paddle.size.x *= 0.8;
}
}
/*
* SlowingBonus
* */
void SlowingBonus::draw(sf::RenderWindow& window) const
{
static sf::CircleShape shape(radius);
shape.setOrigin(radius, radius);
shape.setFillColor(sf::Color{100, 200, 100});
shape.setPosition(m_position);
window.draw(shape);
static sf::CircleShape clock(radius / 2);
clock.setOutlineColor(sf::Color::Red);
clock.setOutlineThickness(3);
clock.setPosition(m_position - sf::Vector2f{radius /2, radius / 2});
window.draw(clock);
}
void SlowingBonus::activate(Arkanoid& game)
{
bool isAlreadySlowed = false;
for (auto it = game.m_effects.begin(); it != game.m_effects.end();) {
if ((*it)->effectId == _EFFECT_SLOWING_ID) {
(*it)->mDuration += mDuration;
isAlreadySlowed = true;
break;
}
it++;
}
if (!isAlreadySlowed) {
game.m_effects.push_back(new SlowingEffect(game.m_time, mDuration));
game.m_effects.back()->activate(game);
}
}
/* =============
* ===Effects===
* =============
* */
Effect::Effect(char id, double start_time, double duration) : effectId(id), mStartTime(start_time), mDuration(duration) {};
bool Effect::isExpired(double time) {
if (mStartTime + mDuration > time)
return false;
return true;
}
SlowingEffect::SlowingEffect(double start_time, double duration) : Effect(_EFFECT_SLOWING_ID, start_time, duration) {};
void SlowingEffect::activate(Arkanoid& game) {
for (Ball& ball : game.m_balls) {
ball.velocity = sf::Vector2f{ball.velocity.x * mSlowingFactor, ball.velocity.y * mSlowingFactor};
}
}
void SlowingEffect::activate(Ball& ball) {
ball.velocity = sf::Vector2f{ball.velocity.x * mSlowingFactor, ball.velocity.y * mSlowingFactor};
}
void SlowingEffect::deactivate(Arkanoid& game) {
for (Ball& ball : game.m_balls) {
ball.velocity = sf::Vector2f{ball.velocity.x / mSlowingFactor, ball.velocity.y / mSlowingFactor};
}
}

@ -0,0 +1,92 @@
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
class Paddle;
class Ball;
class Arkanoid;
class Bonus
{
protected:
inline static const float speed = 120;
inline static const float radius = 15;
sf::Vector2f m_position;
float m_time;
public:
Bonus(sf::Vector2f position);
void update(float dt);
virtual void draw(sf::RenderWindow& window) const = 0;
virtual void activate(Arkanoid& game) = 0;
virtual ~Bonus() = default;
bool isColiding(const Paddle& paddle) const;
// Класс Arkanoid должен быть дружественным, так как он может менять внутреннее объекта-бонуса
friend class Arkanoid;
};
class TripleBallBonus : public Bonus {
public:
TripleBallBonus(sf::Vector2f position): Bonus(position) {};
void draw(sf::RenderWindow& window) const;
void activate(Arkanoid& game);
};
class EnlargePaddleBonus : public Bonus {
public:
EnlargePaddleBonus(sf::Vector2f position): Bonus(position) {};
void draw(sf::RenderWindow& window) const;
void activate(Arkanoid& game);
};
class ShrinkPaddleBonus : public Bonus {
public:
ShrinkPaddleBonus(sf::Vector2f position): Bonus(position) {};
void draw(sf::RenderWindow& window) const;
void activate(Arkanoid& game);
};
class SlowingBonus : public Bonus {
private:
double mDuration = 10;
public:
SlowingBonus(sf::Vector2f position): Bonus(position) {};
void draw(sf::RenderWindow& window) const;
void activate(Arkanoid& game);
};
/*
* Effects
* */
#define _EFFECT_SLOWING_ID 0
class Effect {
protected:
char effectId;
double mStartTime;
double mDuration;
public:
Effect(char id, double start_time, double duration);
virtual ~Effect() = default;
virtual void activate(Arkanoid& game) = 0;
virtual void activate(Ball& ball) = 0;
virtual void deactivate(Arkanoid& game) = 0;
bool isExpired(double time);
friend class SlowingBonus;
friend class TripleBallBonus;
friend class Arkanoid;
};
class SlowingEffect : public Effect {
private:
float mSlowingFactor = 0.1;
char id = _EFFECT_SLOWING_ID;
public:
SlowingEffect(double start_time, double duration);
void activate(Arkanoid& game);
void activate(Ball& ball);
void deactivate(Arkanoid& game);
};

@ -0,0 +1,5 @@
#pragma once
struct Brick
{
bool isActive;
};

@ -0,0 +1,63 @@
#include <vector>
#include "brick_grid.hpp"
BrickGrid::BrickGrid() {}
BrickGrid::BrickGrid(sf::FloatRect borders, int numBrickColumns, int numBrickRows) :
m_border(borders),
m_numBrickColumns(numBrickColumns),
m_numBrickRows(numBrickRows),
m_numActiveBricks(numBrickColumns * numBrickRows)
{
m_bricks.resize(m_numBrickColumns * m_numBrickRows, Brick{true});
m_brickShape.setSize(getBrickSizes());
m_brickShape.setOutlineColor(sf::Color::Black);
m_brickShape.setOutlineThickness(0.5);
m_brickShape.setFillColor(color);
}
sf::FloatRect BrickGrid::getBorder() const
{
return m_border;
}
sf::Vector2i BrickGrid::getGridSizes() const
{
return {m_numBrickColumns, m_numBrickRows};
}
sf::Vector2f BrickGrid::getBrickSizes() const
{
return {m_border.width / m_numBrickColumns, m_border.height / m_numBrickRows};
}
bool BrickGrid::isBrickActive(std::pair<int, int> indexes) const
{
return m_bricks[indexes.first + indexes.second * m_numBrickColumns].isActive;
}
void BrickGrid::deactivateBrick(std::pair<int, int> indexes)
{
m_bricks[indexes.first + indexes.second * m_numBrickColumns].isActive = false;
m_numActiveBricks--;
}
int BrickGrid::getNumActiveBricks() const
{
return m_numActiveBricks;
}
void BrickGrid::draw(sf::RenderWindow& window)
{
auto [brickWidth, brickHeight] = getBrickSizes();
for (int j = 0; j < m_numBrickRows; ++j)
{
for (int i = 0; i < m_numBrickColumns; ++i)
{
if (!isBrickActive({i, j}))
continue;
m_brickShape.setPosition({m_border.left + i * brickWidth, m_border.top + j * brickHeight});
window.draw(m_brickShape);
}
}
}

@ -0,0 +1,37 @@
#pragma once
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "brick.hpp"
class BrickGrid
{
private:
inline static const sf::Color color {100, 200, 250};
sf::FloatRect m_border;
int m_numBrickColumns;
int m_numBrickRows;
std::vector<Brick> m_bricks;
sf::RectangleShape m_brickShape;
int m_numActiveBricks;
public:
BrickGrid();
BrickGrid(sf::FloatRect borders, int numBrickColumns, int numBrickRows);
sf::FloatRect getBorder() const;
sf::Vector2i getGridSizes() const;
sf::Vector2f getBrickSizes() const;
bool isBrickActive(std::pair<int, int> indexes) const;
void deactivateBrick(std::pair<int, int> indexes);
int getNumActiveBricks() const;
void draw(sf::RenderWindow& window);
};

Some files were not shown because too many files have changed in this diff Show More