一起來做一個 c++ 單項選擇題標準化考試系統

題目要求

1、問題描述 :

設計一個單項選擇題標準化考試系統,該系統要求能自動組卷和評分。

2、功能要求

(1)用文件保存試題庫。(每個試題包括題幹、4 個備選答案、標準答案)。
(2)試題錄入:可隨時增加試題到試題庫中。
(3)試題抽取:每次從試題庫中可以隨機抽出 N 道題(N 由鍵盤輸入)。
(4)答題:用戶可實現輸入自己的答案。
(5)自動判卷:系統可根據用戶答案與標準答案的對比實現判卷並給出成績。
(6)退出。

思路分析

考試系統,得有題目,先做一個題目類,就定義這些變量吧
在這裏插入圖片描述
然後對這個題進行分析歸納,通過功能要求初步確定要有這些模塊~
在這裏插入圖片描述
有登錄模塊當然也應該有包含用戶名和密碼的用戶類啦
在這裏插入圖片描述
簡簡單單~

接下來分別實現各個模塊

各個模塊的實現

題目類的創建

創建Timu.h頭文件,然後隨便寫上變量就完事了~上代碼:

class Timu {
public:
    Timu() {}
    ~Timu() {}
    string tigan;
    string A, B, C, D;
    char answer;
    void show() {
        cout << tigan << endl;
        cout << "A." << A << endl;
        cout << "B." << B << endl;
        cout << "C." << C << endl;
        cout << "D." << D << endl;
    }
};

管理題庫模塊的實現

整個題庫用一個 Timu 類型的 vector 實現。
管理題庫這事哪能是什麼人都能幹的?當然要設置權限了

bool quanxian()
{
    cout << "請輸入密碼來證明您的權限" << endl;
    string c;
    cin >> c;
    return c == "73748156";
}

7 3 7 4 8 1 5 6
今生今世伴你左右 ~ 挺好挺好

出題功能的實現

因爲是用 vector 實現的題庫,所以直接輸入相關信息後插入 vector 就行,簡簡單單,看代碼:

void addTimu(vector<Timu>& a) {
    Timu temp;
    string s, A, B, C, D, ans;
    cout << "請輸入題幹" << endl;
    cin >> temp.tigan;
    cout << "請輸入A選項" << endl;
    cin >> temp.A;
    cout << "請輸入B選項" << endl;
    cin >> temp.B;
    cout << "請輸入C選項" << endl;
    cin >> temp.C;
    cout << "請輸入D選項" << endl;
    cin >> temp.D;
    cout << "請輸入正確選項" << endl;
    cin >> temp.answer;
    if (temp.answer >= 'a' && temp.answer <= 'z')temp.answer = temp.answer - 32;
    a.push_back(temp);
    cout << "添加完成" << endl;
}

突然覺得這個三級項目寫的沒有激情。。。。有點簡單。。
在這裏插入圖片描述

題目的存儲與讀取

大概不能每次考試都重新打一遍題。。。太不人性化了
就把題庫存到本地文件裏吧
這裏要用到c++文件流來實現,上代碼
存儲:

void save(vector<Timu>& a)
{
    ofstream ofs;
    ofs.open(FILENAME, ios::out);
    for (auto& i : a) {//錄入每道題信息
        ofs << i.tigan << "\n" << i.A << "\n" << i.B << "\n"
            << i.C << "\n" << i.D << "\n" << i.answer << endl;
        //將所有信息存儲
    }
    cout << "保存成功" << endl;
    ofs.close();//關閉文件
}

讀取也差不多

void fetch(vector<Timu>& a)
{
    ifstream ifs;
    ifs.open(FILENAME, ios::in);//讀文件
    if (!ifs.is_open())//判斷是否存在
    {
        cout << "題庫文件不存在" << endl;
        ifs.close();
        return;
    }

    Timu i;
    while (ifs >> i.tigan >> i.A >> i.B >> i.C >> i.D >> i.answer)//信息讀取到temp中
    {
        a.push_back(i);
    }
    ifs.close();
    if (a.empty())
    {
        cout << "題庫爲空" << endl;
    }
    else
        cout << "當前題目數目爲" << a.size() << "道" << endl;
}

把讀取加在主函數裏,保存放到出題同級菜單下就好

封裝題庫管理模塊

加一個滿足理科生審美的菜單

void showMenu2()
{
    cout << "*********************************" << endl;
    cout << "*******     學習使我快樂     ******" << endl;
    cout << "*******      出題請按 1      ******" << endl;
    cout << "*******    保存題庫請按 2     ******" << endl;
    cout << "*******      退出請按 0     ******" << endl;
    cout << "*********************************" << endl;
}

我愛學習,學習使我快樂!
在這裏插入圖片描述

用switch實現整理題庫的封裝函數

void arrangeTiku(vector<Timu>& a) {

    char c;
    while (true)
    {
        showMenu2();
        cin >> c;
        switch (c) {
        case '0'://退出
            return;
        case '1'://出題
            addTimu(a);
            break;
        case '2'://保存
            save(a);
            break;
        }
        system("pause");
        system("cls");
    }
}

完美 ~ ~ 此處應該有掌聲鼓勵!

考試模塊的實現

抽題功能的實現

c++沒有封裝隨機數的方法,查了好多才知道該怎麼在一定範圍內取隨機數,先加個這個#define random(x) (rand()%x)
然後在函數中這樣調用就可以在指定範圍內出隨機數啦 ~
肯定要讀入 N(抽取題目數量),把 N 傳進函數裏

void chouTimu(vector<Timu>a, vector<Timu>& b, int N)
{
    int x;
    for (int i = 0; i < N; ++i) {
        x = random(a.size());
        b.push_back(a[x]);
        a.erase(a.begin() + x);
    }
}

將抽出來的題目存在一個新的 Timu 類型 vector 中就完事啦 ~ 輕輕鬆鬆 ~ ~ ~

答題功能的實現

傳入剛纔抽出來的題目,讀入答案,判斷並記數,最後返回成績

int answerTi(vector<Timu>a) {
    char c;
    int x = 0;
    for (int i = 0; i < a.size(); ++i) {
        a[i].show();
        cout << "請輸入你的答案" << endl;
        cin >> c;
        if (c >= 'a' && c <= 'z')c = c - 32;
        if (c == a[i].answer)x++;
    }
    return 100 * x / a.size();
}

嘖 ~ 這三級項目就快要完事了

考試模塊的封裝

讀入要答題的數目,注意判斷下題庫裏題目夠不夠就行

簡簡單單,直接上代碼

void takeExam(vector<Timu>& a) {
    cout << "請輸入你想要答題的數目" << endl;
    int N;
    cin >> N;
    if (N > a.size())
    {
        cout << "當前題目數量不足" << endl;
        return;
    }
    vector<Timu>b;
    chouTimu(a, b, N);
    int score = answerTi(b);
    cout << "你的成績是" << score << endl;
}

完事,下一個 ~
在這裏插入圖片描述

用戶類的創建

沒啥可說的,就這倆變量

class User {
public:
    string password;
    string userName;
};

太簡單,感覺他不配二級目錄。。。。。

登錄模塊的創建

無非就是註冊和登錄,記得註冊的時候把他用文件流存到本地文件裏,下次還能登錄就好 ~
先聲明一個判斷用戶名是否存在的函數
代碼如下:

int isUserExist(string name, vector<User>u) {
    for (int i = 0; i < u.size(); ++i) {
        if (u[i].userName == name) return i;
    }
    return -1;
}

接着是註冊的代碼:

void zhuce(vector<User>& u)
{
    string password;
    User tmp;
    string name;
    cout << "請輸入用戶名" << endl;
    cin >> name;
    int a = isUserExist(name, u);
    if (a == -1)
    {
        tmp.userName = name;
        cout << "請輸入密碼" << endl;
        cin >> password;
        tmp.password = password;
        u.push_back(tmp);
        ofstream ofs;
        ofs.open(FILENAME2, ios::out);
        for (auto& i : u) {//錄入用戶信息
            ofs << i.userName << " " << i.password << endl;
        }
        cout << "保存成功" << endl;
        ofs.close();//關閉文件
    }
    else cout << "該用戶名已被使用,註冊失敗" << endl;
}

要記得判斷用戶名是否重複,以免出現問題 ~

然後是登錄的代碼:

bool denglu(vector<User>& u) {
    string name, password;
    cout << "請輸入用戶名" << endl;
    cin >> name;
    int a = isUserExist(name, u);
    if (a == -1) {
        cout << "用戶名不存在,登錄失敗" << endl;
        return false;
    }
    else
    {
        cout << "請輸入密碼" << endl;
        cin >> password;
        if (u[a].password == password) {
            cout << "登錄成功" << endl;
            return true;
        }
        else
        {
            cout << "密碼錯誤,登錄失敗" << endl;
            return false;
        }
    }
}

遍歷判斷密碼對不對就行

然後做一個美麗的菜單

void showMenu3() {
    cout << "*********************************" << endl;
    cout << "*******     學習使我快樂     ******" << endl;
    cout << "*******      登錄請按 1      ******" << endl;
    cout << "*******      註冊請按 2     ******" << endl;
    cout << "*******      退出請按 0     ******" << endl;
    cout << "*********************************" << endl;
}

注意這裏要停一會,好好欣賞下菜單再往下 ~ ~ ~ ~
在這裏插入圖片描述

最後封裝到一起就好啦

主函數的封裝

創建兩個 vector ,然後讀入本地文件到 vector 中,接後邊的主菜單函數,通過主菜單函數封裝所有模塊 ~

int main() {
    vector<Timu>tiku;
    vector<User>yonghu;
    fetch(tiku);
    fetchUser(yonghu);
    select(tiku, yonghu);
    return 0;
}

主菜單選項的封裝

要先做一個主菜單

void showMenu1()
{
    cout << "******************************" << endl;
    cout << "*******   學習使我快樂    ******" << endl;
    cout << "*******    考試請按 1     ******" << endl;
    cout << "*******   整理題庫請按 2   ******" << endl;
    cout << "*******    退出請按 0     ******" << endl;
    cout << "******************************" << endl;
}

樣式還是依舊絕色

void select(vector<Timu>& a, vector<User>& b) {
    char s,choose0;
    int h = 0;
    do {
        showMenu3();
        cin >> choose0;
        switch (choose0)
        {
        case'1'://登錄
            if (denglu(b))
            {
                h = 1;
                break;
            }
            else
                continue;
        case'2'://註冊
            zhuce(b);
            break;
        case'0':
            cout << "歡迎下次使用" << endl;
            return;
        }
        system("pause");
        system("cls");
    } while ((choose0 != '0' && h != 1));
    while (true)
    {
        showMenu1();
        cin >> s;
        switch (s) {
        case '0'://退出
            cout << "歡迎下次使用" << endl;
            return;
        case '1'://考試
            takeExam(a);
            break;
        case '2'://整理題庫
            if (quanxian())
                arrangeTiku(a);
            else cout << "密碼錯誤,您沒有權限" << endl;
            break;
        default:
            cout << "指令錯誤,請重新輸入" << endl;
            break;
        }
        system("pause");
        system("cls");
    }
}

三級項目完成 ~ 是不是還挺簡單的 ?
在這裏插入圖片描述
成品也上傳到這裏啦

燕大的朋友們也可以私信找我要代碼的
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章