基于OpenCV的飞行棋小游戏

· · 个人记录

利用了opencv的一些函数写的飞行棋,花了一个晚上写出来的东西,目前还很满意。

运行示例在博客末尾。

工程除了opencv还需要两个文件,一个背景图片,一个点参数文档。

背景图片下载:

点坐标参数文档,要是觉得点不好,可以用这个工程重描点,点的顺序一言难尽,自己琢磨。

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <opencv.hpp>
#define DEBUG 0

using namespace std;
using namespace cv;

const char* map_file = "2019091013500077.png";//背景图片
const char* win_name = "摸鱼飞行棋";
ifstream point_in("point.txt");//点坐标参数
vector<Point> map_deque;

enum class TEAM_COLOR { blue, green, red, yellow };
void init();
int dice();
void show(Mat, int, TEAM_COLOR);
void draw_piece(Mat&, Point, TEAM_COLOR, int);
void win(Mat, TEAM_COLOR);
Scalar team_color(TEAM_COLOR);

class MP {
private:
    int x, y;
    bool flag;
public:
    MP() :flag(0) { x = y = 0; }
    void flash_position(int x, int y) {
        this->x = x;
        this->y = y;
        flag = 1;
    }
    bool empty() { return !flag; }
    Point get_position() {
        if (flag) {
            flag = 0;
            return Point(x, y);
        }
    }
} mouse_position;

class team {
private:
    TEAM_COLOR color;
    Point home[4];
    Point start, end;
    int first, last;
    int fly_point, fly_dist;
    int planes_inv[4];
    Point planes[4];
    bool tail_pg[4];
    Point tail[6];
public:
    team(TEAM_COLOR c) :color(c) {
        for (int i = 0; i < 4; ++i) {
            planes_inv[i] = -2;
            tail_pg[i] = 0;
        }
    }
    void init(vector<Point>&, int, int, int, int);
    bool all_home();
    bool run(int, Point);
    void draw(Mat&);
    bool win();
    void turn_home(int inv);
};

team blue(TEAM_COLOR::blue), 
    green(TEAM_COLOR::green),
    red(TEAM_COLOR::red),
    yellow(TEAM_COLOR::yellow);

int main() {
    int dn;
    Mat map_org = imread(map_file);
#if DEBUG & 1
    Mat cp = map_org.clone();
    while (!point_in.eof()) {
        int x, y;
        point_in >> x >> y;
        circle(cp, Point(x, y), 5, Scalar(255, 0, 255), FILLED);
    } imshow("map", cp);
#endif
    init();
    while (1) {
        do {
            dn = dice();
            show(map_org.clone(), dn, TEAM_COLOR::green);
            do {
                while (mouse_position.empty()) waitKey(100);
            } while (!green.run(dn, mouse_position.get_position()));
            if(green.win()) win(map_org.clone(), TEAM_COLOR::green);
        } while (dn == 6);

        do {
            dn = dice();
            show(map_org.clone(), dn, TEAM_COLOR::red);
            do {
                while (mouse_position.empty()) waitKey(100);
            } while (!red.run(dn, mouse_position.get_position()));
            if (red.win()) win(map_org.clone(), TEAM_COLOR::red);
        } while (dn == 6);

        do {
            dn = dice();
            show(map_org.clone(), dn, TEAM_COLOR::yellow);
            do {
                while (mouse_position.empty()) waitKey(100);
            } while (!yellow.run(dn, mouse_position.get_position()));
            if (yellow.win()) win(map_org.clone(), TEAM_COLOR::yellow);
        } while (dn == 6);

        do {
            dn = dice();
            show(map_org.clone(), dn, TEAM_COLOR::blue);
            do {
                while (mouse_position.empty()) waitKey(100);
            } while (!blue.run(dn, mouse_position.get_position()));
            if (blue.win()) win(map_org.clone(), TEAM_COLOR::blue);
        } while (dn == 6);
    }
    return 0;
}

void show(Mat img, int dn, TEAM_COLOR tc) {
    green.draw(img);
    blue.draw(img);
    red.draw(img);
    yellow.draw(img);
    putText(img, (string)"Moving forward " + to_string(dn) + " steps", Point(0, img.rows - 20), 1, 3, team_color(tc), 5);
    imshow(win_name, img);
}

void OnMouse(int e, int x, int y, int flag, void* data) {
    if (e == EVENT_LBUTTONDOWN) {
        mouse_position.flash_position(x, y);
    }
}

Point get_point() {
    int x, y;
    point_in >> x >> y;
    return Point(x, y);
}

void init() {
    namedWindow(win_name);
    setMouseCallback(win_name, OnMouse);

    vector<Point> blue_p, green_p, red_p, yellow_p;
    for (int i = 0; i < 5; ++i)
        green_p.push_back(get_point());
    for (int i = 0; i < 5; ++i)
        red_p.push_back(get_point());
    for (int i = 0; i < 5; ++i)
        yellow_p.push_back(get_point());
    for (int i = 0; i < 5; ++i)
        blue_p.push_back(get_point());

    for (int i = 0; i < 52; ++i)
        map_deque.push_back(get_point());

    for (int i = 0; i < 6; ++i)
        red_p.push_back(get_point());
    for (int i = 0; i < 6; ++i)
        yellow_p.push_back(get_point());
    for (int i = 0; i < 6; ++i)
        blue_p.push_back(get_point());
    for (int i = 0; i < 6; ++i)
        green_p.push_back(get_point());
    Point tmp = get_point();
    red_p.push_back(tmp);
    yellow_p.push_back(tmp);
    blue_p.push_back(tmp);
    green_p.push_back(tmp);

    red.init(red_p, 3, 0, 20, 32);
    yellow.init(yellow_p, 16, 13, 33, 45);
    blue.init(blue_p, 29, 26, 46, 6);
    green.init(green_p, 42, 39, 7, 19);
}

int dice() {
#if DEBUG == 2
    return waitKey(0) - '0';
#endif
    static bool flag = 1;
    if (flag) srand(time(0)), flag = 0;
    return rand() % 6 + 1;
}

Scalar team_color(TEAM_COLOR color) {
    switch (color) {
    case TEAM_COLOR::blue:
        return Scalar(255, 0, 0);
        break;
    case TEAM_COLOR::green:
        return Scalar(0, 255, 0);
        break;
    case TEAM_COLOR::red:
        return Scalar(0, 0, 255);
        break;
    case TEAM_COLOR::yellow:
        return Scalar(0, 255, 255);
        break;
    default: break;
    }
}

void draw_piece(Mat& img, Point p, TEAM_COLOR c, int n) {
    circle(img, p, 20, team_color(c), FILLED);
    circle(img, p, 20, Scalar(0, 0, 0), 3);
    putText(img, to_string(n), p - Point(10, -10), 1, 2, Scalar(0, 0, 0), 3);
}

void team::init(vector<Point>& init_point, int fir, int las, int ff, int fd) {
    int cnt = 0;
    for (int i = 0; i < 4; ++i)
        home[i] = init_point[cnt++];
    start = init_point[cnt++];
    first = fir;
    last = las;
    fly_point = ff;
    fly_dist = fd;
    for (int i = 0; i < 6; ++i)
        tail[i] = init_point[cnt++];
    end = init_point[cnt++];
    for (int i = 0; i < 4; ++i)
        planes[i] = home[i];
}

bool team::all_home() {
    for (int i = 0; i < 4; ++i) {
        if (planes_inv[i] != -2 && planes_inv[i] != -3)
            return false;
    }
    return true;
}

double p2p_dis(const Point& a, const Point& b) {
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

bool team::run(int p, Point n) {
    if (all_home() && p != 6)
        return true;
    int res = -1;
    for (int i = 0; i < 4; ++i) {
        int dis = p2p_dis(n, planes[i]);
        if (dis < 20) res = i;
    }
    if (!~res) return false;
    if (planes_inv[res] == -2) {
        if (p == 6) {
            planes_inv[res] = -1;
            planes[res] = start;
            return true;
        }
        else return false;
    }
    if (tail_pg[res]) {
        if (p > 6 - planes_inv[res])
            planes_inv[res] += ((6 - planes_inv[res]) << 1) - p;
        else if (p == 6 - planes_inv[res]) {
            planes_inv[res] = -3;
            planes[res] = end;
            return true;
        }
        else planes_inv[res] += p;
    }
    else {
        if (planes_inv[res] + p > 51) {
            p -= 52 - planes_inv[res];
            planes_inv[res] = 0;
        }
        if (planes_inv[res] == -1) {
            planes_inv[res] = first + p;
        }
        else if (planes_inv[res] <= last && planes_inv[res] + p > last) {
            tail_pg[res] = 1;
            planes_inv[res] = p - (last - planes_inv[res] + 1);
        }
        else {
            planes_inv[res] += p;
        }
    }
    if (tail_pg[res]) {
        planes[res] = tail[planes_inv[res]];
    }
    else {
        if (planes_inv[res] == fly_point) planes_inv[res] = fly_dist;
        planes[res] = map_deque[planes_inv[res]];
        if (color != TEAM_COLOR::blue) blue.turn_home(planes_inv[res]);
        if (color != TEAM_COLOR::red) red.turn_home(planes_inv[res]);
        if (color != TEAM_COLOR::green) green.turn_home(planes_inv[res]);
        if (color != TEAM_COLOR::yellow) yellow.turn_home(planes_inv[res]);
    }
    return true;
}

void team::draw(Mat& img) {
    for (int i = 0; i < 4; ++i)
        draw_piece(img, planes[i], color, i);
}

bool team::win() {
    for (int i = 0; i < 4; ++i)
        if (planes[i] != end)
            return false;
    return true;
}

void team::turn_home(int inv) {
    for (int i = 0; i < 4; ++i)
        if (!tail_pg[i] && planes_inv[i] == inv) {
            planes_inv[i] = -2;
            planes[i] = home[i];
        }
}

void win(Mat img, TEAM_COLOR c) {
    putText(img, "WIN!", Point((img.cols >> 1) - 150, (img.rows >> 1) + 50), 1, 10, team_color(c), 20);
    imshow(win_name, img);
    waitKey(0);
    exit(0);
}

因为弄运行示例很麻烦,所以没有QAQ。

(c) saxiy 2021.12.30 保留所有权利,允许自由转载但请注明作者及出处。