开幕雷击:本文非常非常非常长,请做好心理准备再阅读!推荐跳过小球游戏,直接阅读分数类的实现!可以直接点击右侧列表实现跳转。
实验结论
小球移动游戏
代码极其垃圾,写法极其鬼畜,阅读前请做好准备。正确的写法应该是再写一个类控制小球的移动,但是我当时一时脑抽,写出了如下产物。切勿模仿!!!!!!!!!
源码
main.cpp
#include <iostream>
#include <random>
#include <conio.h>
#include "canvas.h"
#include <ctime>
using namespace std;
mt19937 gen(static_cast<unsigned int>(time(nullptr)));
int main() {
int score=0;
cout << "Press any key to start,'Q' to quit." << endl;
if (getch() == 'q' || getch() == 'Q')
return 0;
Canvas canvas1("0", "A", 25, 25);
uniform_int_distribution<> enemyX(1, canvas1.getX());
uniform_int_distribution<> enemyY(1, canvas1.getY());
canvas1.generateBalls(1, 1);
canvas1.generateBalls(enemyX(gen), enemyY(gen),'$');
while (true) {
switch (getch()) {
case 'W':
case 'w':
canvas1.getBalls()[0].up();
canvas1.refreshBalls();
break;
case 'A':
case 'a':
canvas1.getBalls()[0].left();
canvas1.refreshBalls();
break;
case 'S':
case 's':
canvas1.getBalls()[0].down();
canvas1.refreshBalls();
break;
case 'D':
case 'd':
canvas1.getBalls()[0].right();
canvas1.refreshBalls();
break;
case 'Q':
case 'q':
return 0;
}
if (canvas1.getBalls()[0].getx() == canvas1.getBalls()[1].getx() &&
canvas1.getBalls()[0].gety() == canvas1.getBalls()[1].gety()) {
score++;
canvas1.deleteLastBall();
canvas1.generateBalls(enemyX(gen), enemyY(gen),'$');
canvas1.refreshBalls();
}
cout<<"Score:"<<score<<endl;
}
}
canvas.h
#ifndef CANVAS_H
#define CANVAS_H
#include <vector>
#include <string>
#include "ball.h"
using std::string;
using std::vector;
class Canvas {
public:
Canvas(string bg0 = "0", string fg0 = "A", int x = 50, int y = 50);
void changeCanvasBg(string &bg0);
void changeCanvasFg(string &fg0);
void changeCanvasColor(string &bg0, string &fg0);
void refreshG();
void refreshBalls();
void generateBalls(int x0, int y0, char ch0='o');
void deleteLastBall();
vector<Ball>& getBalls();
int getX() const;
int getY() const;
private:
int X;
int Y;
char **blocks;
string bg;
string fg;
vector<Ball> balls;
};
#endif
canvas.cpp
#include <utility>
#include "canvas.h"
#include <cstdlib>
#include <iostream>
Ball ball(1, 1, 1, 1);
Canvas::Canvas(string bg0, string fg0, int x, int y) : bg(std::move(bg0)), fg(std::move(fg0)), X(x), Y(y) {
blocks = new char *[Y];
for (int i = 0; i < Y; ++i) {
blocks[i] = new char[X]{' '};
}
refreshG();
}
void Canvas::changeCanvasBg(string &bg0) {
bg = bg0; // 更新画布背景色
refreshG();
}
void Canvas::changeCanvasFg(string &fg0) {
fg = fg0; // 更新画布前景色
refreshG();
}
void Canvas::changeCanvasColor(string &bg0, string &fg0) {
bg = bg0; // 更新画布背景色
fg = fg0; // 更新画布前景色
refreshG();
}
void Canvas::refreshG() {
string color = "color ";
color += bg;
color += fg;
system(color.c_str());
}
void Canvas::refreshBalls() {
system("cls");
for (int j = 0; j < Y; ++j) {
for (int i = 0; i < X; ++i) {
blocks[j][i]=' ';
}
}
for (int i = 0; i < balls.size(); ++i) {
blocks[balls[i].gety()-1][balls[i].getx()-1]=balls[i].getCh();
}
for (int j = 0; j < Y; ++j) {
for (int i = 0; i < X; ++i) {
std::cout<<blocks[j][i];
}
std::cout<<std::endl;
}
}
void Canvas::generateBalls(int x0, int y0,char ch0) {
balls.push_back(ball);
balls.back().setX(X);
balls.back().setY(Y);
balls.back().setx(x0);
balls.back().sety(y0);
balls.back().setCh(ch0);
}
vector<Ball>& Canvas::getBalls() {
return balls;
}
int Canvas::getX() const {
return X;
}
int Canvas::getY() const {
return Y;
}
void Canvas::deleteLastBall() {
balls.pop_back();
}
ball.h
#ifndef BALL_H
#define BALL_H
class Ball {
public:
Ball(int x0, int y0, int X0, int Y0); // 在坐标(X,Y)处构造一个小球(小球用字符O表示)
void left(int step = 1); // 左移step
void right(int step = 1); // 右移step
void up(int step = 1); // 上移step
void down(int step = 1); // 下移step
void setx(int x0);
void sety(int y0);
void setX(int X0);
void setY(int Y0);
int getX() const;
int getY() const;
int gety() const;
int getx() const;
char getCh() const;
void setCh(char ch='o');
private:
char ch;
int x;
int y;
int X;
int Y;
};
#endif
ball.cpp
#include "ball.h"
#include "canvas.h"
#include <iostream>
using std::cout;
using std::endl;
Ball::Ball(int x0, int y0, int X0, int Y0) : x(x0), y(y0), X(X0), Y(Y0) {
}
void Ball::left(int step) {
x = x - step;
if (x <= 1)
x = 1;
}
void Ball::right(int step) {
x = x + step;
if (x >= X)
x = X;
}
void Ball::up(int step) {
y = y - step;
if (y <= 1)
y = 1;
}
void Ball::down(int step) {
y = y + step;
if (y >= Y)
y = Y;
}
void Ball::setY(int Y0) {
Y = Y0;
}
void Ball::setx(int x0) {
x = x0;
}
void Ball::sety(int y0) {
y = y0;
}
void Ball::setX(int X0) {
X = X0;
}
int Ball::getx() const {
return x;
}
int Ball::gety() const {
return y;
}
int Ball::getX() const {
return X;
}
int Ball::getY() const {
return Y;
}
void Ball::setCh(char ch0) {
ch = ch0;
}
char Ball::getCh() const {
return ch;
}
运行截图
画三角形
因为上一part里已经做过控制小球移动的内容了,本part的实现基本一样,所以咕咕咕了也没什么问题吧。(笑
源码
main.cpp
#include <iostream>
#include "graph.h"
using namespace std;
int main() {
Graph graph1('*', 5);
graph1.draw();
Graph graph2('$', 7);
graph2.draw();
cin.get();
return 0;
}
graph.h
#ifndef GRAPH_H
#define GRAPH_H
// 类Graph的声明
class Graph {
public:
Graph(char ch, int n); // 带有参数的构造函数
void draw(); // 绘制图形
private:
char symbol;
int size;
};
#endif
graph.cpp
// 类graph的实现
#include "graph.h"
#include <iostream>
using namespace std;
// 带参数的构造函数的实现
Graph::Graph(char ch, int n) : symbol(ch), size(n) {
}
// 成员函数draw()的实现
// 功能:绘制size行,显示字符为symbol的指定图形样式
void Graph::draw() {
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size - i - 1; ++j) {
cout << ' ';
}
for (int k = 0; k < 2 * (i + 1) - 1; k++) {
cout << symbol;
}
cout << endl;
}
}
运行截图
Fraction类的实现
源码
main.cpp
#include <iostream>
#include "Fraction.h"
using namespace std;
int main() {
Fraction a(-1, 2);
Fraction b(4, -3);
Fraction c(-5, -20);
Fraction d(5, 1);
Fraction e(1, -5);
a.show();
cout << a << endl;
cout << a.add(b) << endl;
cout << a + b << endl;
cout << b.minus(c) << endl;
cout << b - c << endl;
cout << c.multiply(d) << endl;
cout << c * d << endl;
cout << d.division(e) << endl;
cout << d / e << endl;
cout << d.compare(e) << endl;
cout << d.compare(d) << endl;
cout << e.compare(d) << endl;
return 0;
}
Fraction.h
//
// Created by KOKODA on 2019/4/21.
//
#ifndef FRACTION_H
#define FRACTION_H
#include<iostream>
class Fraction {
private:
int top;
int bottom;
public:
Fraction(int top = 0, int bottom = 1);
Fraction add(Fraction &a);
Fraction minus(Fraction &a);
Fraction multiply(Fraction &a);
Fraction division(Fraction &a);
Fraction operator*(Fraction &a);
Fraction operator+(Fraction &a);
Fraction operator-(Fraction &a);
Fraction operator/(Fraction &a);
int compare(Fraction &a);
friend std::ostream& operator << (std::ostream&,Fraction);
void show();
double Decimal();
};
#endif //FRACTION_H
Fraction.cpp
//
// Created by KOKODA on 2019/4/21.
//
#include "Fraction.h"
#include <iostream>
int gcd(int a0, int b0) {
int a = std::abs(a0);
int b = std::abs(b0);
if (a < b) {
std::swap(a, b);
}
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}
}
int lcm(int a, int b) {
return std::abs(a * b) / gcd(a, b);
}
Fraction::Fraction(int top0, int bottom0) : top(top0 / gcd(top0, bottom0)), bottom(bottom0 / gcd(top0, bottom0)) {
if (top * bottom > 0) {
top = abs(top);
bottom = abs(bottom);
} else if (bottom < 0) {
top = -top;
bottom = -bottom;
}
}
Fraction Fraction::operator+(Fraction &a) {
return {top * (lcm(bottom, a.bottom) / bottom) + a.top * (lcm(bottom, a.bottom) / a.bottom), lcm(bottom, a.bottom)};
}
Fraction Fraction::add(Fraction &a) {
return {top * (lcm(bottom, a.bottom) / bottom) + a.top * (lcm(bottom, a.bottom) / a.bottom), lcm(bottom, a.bottom)};
}
Fraction Fraction::operator-(Fraction &a) {
return {top * (lcm(bottom, a.bottom) / bottom) - a.top * (lcm(bottom, a.bottom) / a.bottom), lcm(bottom, a.bottom)};
}
Fraction Fraction::minus(Fraction &a) {
return {top * (lcm(bottom, a.bottom) / bottom) - a.top * (lcm(bottom, a.bottom) / a.bottom), lcm(bottom, a.bottom)};
}
Fraction Fraction::operator*(Fraction &a) {
return {top * a.top, bottom * a.bottom};
}
Fraction Fraction::multiply(Fraction &a) {
return {top * a.top, bottom * a.bottom};
}
Fraction Fraction::operator/(Fraction &a) {
return {top * a.bottom, bottom * a.top};
}
Fraction Fraction::division(Fraction &a) {
return {top * a.bottom, bottom * a.top};
}
void Fraction::show() {
if (top / bottom == (double) top / (double) bottom)
std::cout << top / bottom << std::endl;
else
std::cout << top << '/' << bottom << std::endl;
}
std::ostream &operator<<(std::ostream &output, Fraction a) {
if (a.top / a.bottom == (double) a.top / (double) a.bottom)
output << a.top / a.bottom;
else
output << a.top << '/' << a.bottom;
return output;
}
double Fraction::Decimal() {
return (double) top / (double) bottom;
}
int Fraction::compare(Fraction &a) {
if(((*this)-a).bottom*((*this)-a).top<0)
return -1;
else if(((*this)-a).bottom*((*this)-a).top==0)
return 0;
else
return 1;
}
运行截图
实验总结与体会
part1
这一part的话,正确的做法是使用一个新的类来控制小球的移动,但是因为我当时没想到而且我就想用给的两个类来着,于是写了这么个不伦不类的东西,总之大家不要学我。但还是基本写出了个框架可以实现多个小球同台竞技了,加球也还算简单吧(心虚。
part2
找出公式就好了,没什么说的。
part3
最最最重要的部分来了,分数类的设计用到了运算符重载,不过这不关键,主要是在构造函数的设计上我采用了将输入直接约分的形式,保证所有分数类对象在创建的时候是以最简形式出现的,然后在进行 +-*/
的运算时,返回值时会调用构造函数,也就保证了所有运算得出的值都是最简形式,计划通!完美,这样做得话不但完美解决了最简形式的问题,而且代码简洁又工整,看起来很舒服。那么说完了最关键的部分,我来提一手分数类实现的功能。
- 实现了
add()minus()multiply()division()
函数用以进行加减乘除运算。 - 运用运算符重载实现分数类对象使用
+-*/
运算符进行运算。 - 实现了返回分数对应的小数值的函数
- 实现了两个分数的比较 例:
a.compare(b)
若a > b则返回1,a = b则返回0,a < b则返回-1
值得一提的是 compare()
的实现我使用了this
指针这样就可以利用之前实现的-
运算符重载直接比较两者的大小
ps:也可以直接重载> <
号来实现直接比较,但我就没有去做了,有兴趣的同学可以试着写写看。