0016 Othello UVA - 220 算法竞赛入门经典系列源码解析

Othello UVA - 220

问题

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码

// 算法竞赛入门经典习题与解答 P28
// 算法竞赛入门经典第2版 P96
/*
    Dreams never shine!
    It's you that shine while chasing your dreams :)
    JAYO!!
*/
#include <iostream>
#include <vector>
#include <cassert>
#include <cstring>
#include <iomanip>
using namespace std;

bool inRange(int x, int left, int right) {
    if(left > right) return inRange(x, right, left);
    return left <= x && x <= right;
}

struct Point {
    int x, y;
    Point(int x = 0, int y = 0) : x(x), y(y) {}
};

ostream & operator << (ostream &os, const Point &p) { return os << "(" << p.x << "," << p.y << ")"; }
template<typename T>
ostream & operator << (ostream &os, const vector<T> &v) {
    for(int i = 0; i < v.size(); i++) {
        if(i) os << ' ';
        os << v[i];
    }
    return os;
}

typedef Point Vector;

Vector operator + (const Vector &A, const Vector &B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (const Vector &A, const Vector &B) { return Vector(A.x - B.x, A.y - B.y); }
Vector operator * (const Vector &A, int p) { return Vector(A.x * p, A.y * p); }
bool operator == (const Vector &A, const Vector &B) { return A.x == B.x && A.y == B.y; }
bool operator < (const Vector &A, const Vector &B) { return A.x < B.x || (A.x == B.x && A.y < B.y); }
const int N = 8, White = 'W', Black = 'B', Empty = '-';

Vector DIRS[N];

inline bool valid(const Point &p) { return inRange(p.x, 1, N) && inRange(p.y, 1, N); }
char Board[N + 1][N + 1], Player;
char playerChange(char c) {
    if(c == White) return Black;
    assert(c == Black);
    return White;
}

void print_board() {
    for(int i = 1; i <= N; i++) {
        for(int j = 1; j <= N; j++) 
            cout << Board[i][j];
        cout << endl;
    }
}

bool canMove(const Point &p, const Vector &dir) { // 先判断这一条线上有么有可以杀掉的棋子
    Point pn = p + dir;
    char c, pc = playerChange(Player);
    int sz = 0;
    while(valid(pn)) {
        c = Board[pn.x][pn.y];
        if(c == pc) {
            sz++;
            pn = pn + dir;
        }
        else break;
    }
    if(!sz) return false;
    if(!valid(pn)) return false;
    return c == Player;
}

void move(const Point &p, const Vector & dv) { // 执行杀棋操作(要先判断canMove)
    Board[p.x][p.y] = Player;
    Point pn = p + dv;
    char pc = playerChange(Player);
    assert(Board[pn.x][pn.y] == pc);
    while(Board[pn.x][pn.y] == pc) {
        Board[pn.x][pn.y] = Player;
        pn = pn + dv;
    }
    assert(Board[pn.x][pn.y] == Player);
}

void move(int r, int c) { // 放棋子的点
    Point p(r, c);
    bool m = false;
    for(int d = 0; d < N; d++) {
        const Vector &dv = DIRS[d];
        if(canMove(p, dv)) { // 杀棋的判断操作(能杀的都杀)(检测落子处的杀棋范围)
            m = true;
            move(p, dv); // 判断后进行杀棋
        }
    }

    Player = playerChange(Player); // (提前交换棋手)
    if(m) return; // 如果杀不了对方的,就只能被杀(交换棋手)

    for(int d = 0; d < N; d++) {
        const Vector &dv = DIRS[d];
        if(canMove(p, dv)) move(p, dv);
    }
    Player = playerChange(Player);
}

void listAllMoves() {
    vector<Point> moves;
    for(int i = 1; i <= N; i++) {
        for(int j = 1; j <= N; j++) {
            Point p(i, j);
            if(Board[i][j] != Empty) continue; // 找出合法的空格‘-’(并且可以至少夹住一个对方棋子), 计算legal moves
            for(int d = 0; d < N; d++)
                if(canMove(p, DIRS[d])) {
                    moves.push_back(p);
                    break;
                }
        }
    }

    if(moves.empty()) cout << "No legal move." << endl;
    else cout << moves << endl;
}

int main() {
    int T;
    cin >> T;
    DIRS[0].x = 1; DIRS[0].y = 0;
    DIRS[1].x = 1; DIRS[1].y = 1;
    DIRS[2].x = 0; DIRS[2].y = 1;
    DIRS[3].x = -1; DIRS[3].y = 1;
    DIRS[4].x = -1; DIRS[4].y = 0;
    DIRS[5].x = -1; DIRS[5].y = -1;
    DIRS[6].x = 0; DIRS[6].y = -1;
    DIRS[7].x = 1; DIRS[7].y = -1;

    bool first = true;
    while(T--) {
        if(first) first = false; else cout << endl;
        string line;
        memset(Board, 0, sizeof(Board));
        for(int i = 1; i <= N; i++) {
            cin >> line;
            for(int j = 1; j <= N; j++) 
                Board[i][j] = line[j - 1];
        }
        cin >> Player;
        while(true) {
            cin >> line;
            if(line == "Q") {
                print_board();
                break;
            }
            if(line == "L") {
                listAllMoves();
            } else {
                assert(line.size() == 3 && line[0] == 'M');
                move(line[1] - '0', line[2] - '0');
                int w = 0, b = 0;
                for(int i = 1; i <= N; i++) {
                    for(int j = 1; j <= N; j++) {
                        char c = Board[i][j];
                        if(c == White) w++;
                        else if(c == Black) b++;
                    }
                }
                cout << "Black - " << setw(2) << b << " White - " << setw(2) << w << endl;
            }
        }
    }
 	return 0;
}


知识点

setw(n)

C++ setw() 函数用于设置字段的宽度,语法格式如下:
setw(n)

n 表示宽度,用数字表示。
setw() 函数只对紧接着的输出产生作用。
当后面紧跟着的输出字段长度小于 n 的时候,
在该字段前面用空格补齐,当输出字段长度大于 n 时,全部整体输出。

总结

耐心,解析。带动自己的大脑积极思考。
读懂题目,读懂要求,知道代码实在干嘛?
就是按照题目要求执行一系列被指定的操作!!!
注意自己的心态!你遇到的困难别人也遇到了,但是那些志在登顶的人,绝不会半途而废,绝不放弃,前进,朝着目标前进!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值