1. 程式人生 > 其它 >湖南大學結隊程式設計專案隊友程式碼互評

湖南大學結隊程式設計專案隊友程式碼互評

一.簡介

本篇部落格為對結對程式設計搭檔李津鬆的個人專案(中小學數學卷子自動生成程式)的評價。該程式碼使用語言為c++。本次點評僅為個人觀點,如有錯誤,請多指正!

二.程式碼評析

/*
  copyright jinsong li 2021/9/26
*/
#include <direct.h>
#include <time.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include 
<fstream> #include <vector> using std::cin; using std::cout; using std::endl; using std::string; using std::to_string; using std::vector; using std::ifstream; using std::ofstream; void getFiles(string path, vector<string> &files) { // 檔案句 int16_t hFile = 0; // 檔案資訊 struct _finddata_t fileinfo;
string pathName; if ((hFile = _findfirst(pathName.assign(path).c_str(), &fileinfo)) != -1) { do { if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) files.push_back(pathName.assign(path). append("/").append(fileinfo.name)); }
while (_findnext(hFile, &fileinfo) == 0); _findclose(hFile); } } // 查重函式:將先前的文件進行遍歷, // 然後在提取出每一行的字串, // 比較每一行的字串, // 若沒有重複則返回1,重複了就返回-1 int find(string test, int ty) { string FindType = ""; switch (ty) { case 1: { FindType = "./張三1/"; break; } case 2: { FindType = "./張三2/"; break; } case 3: { FindType = "./張三3/"; break; } case 4: { FindType = "./李四1/"; break; } case 5: { FindType = "./李四2/"; break; } case 6: { FindType = "./李四3/"; break; } case 7: { FindType = "./王五1/"; break; } case 8: { FindType = "./王五2/"; break; } case 9: { FindType = "./王五3/"; break; } } vector<string> files; getFiles(FindType, files); int size = files.size(); for (int i = 0; i < size; i++) { ifstream fin(files[i]); string past; while (fin >> past) { if (past == test) return (-1); } } return 1; } // 試卷生成函式:通過隨機數生成不同運算元, // 根據引用的不同型別的試卷, // 生成不同的試卷並儲存在相應的位置。 void get(int NUM, int USER, int TYPE) { time_t t = time(NULL); ofstream File; char ttime[33]; // 確定使用者 switch (USER) { case 1: { strftime(ttime, 33, "./張三1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 2: { strftime(ttime, 33, "./張三2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 3: { strftime(ttime, 33, "./張三3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 4: { strftime(ttime, 33, "./李四1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 5: { strftime(ttime, 33, "./李四2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 6: { strftime(ttime, 33, "./李四3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 7: { strftime(ttime, 33, "./王五1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 8: { strftime(ttime, 33, "./王五2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } case 9: { strftime(ttime, 33, "./王五3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t)); break; } } File.open(ttime); int randNum = 0; int diff = 0; // 確定型別 switch (TYPE) { case 1: { diff = 0; break; } case 2: { diff = 2; break; } case 3: { diff = 5; break; } } int syn = 0, spin = 0; // 生成題目 for (int i = 1; i <= NUM; i++) { File << i << ". " << endl; if (diff == 0) { randNum = rand() % 4 + 2; } else { randNum = rand() % 5 + 1; } int Number[randNum] = {0, 0, 0, 0, 0}; string sNumber[randNum] = {"", "", "", "", ""}; for (int j = 0; j < randNum; j++) { Number[j] = rand() % 100 + 1; sNumber[j] = to_string(Number[j]); } string FileWrite = ""; if (diff == 0) { spin = 0; } else if (diff == 2) { spin = rand() % 2 + 1; } else if (diff == 5) { spin = rand() % 3 + 3; } string spis = ""; switch (spin) { case 0: { FileWrite = FileWrite + sNumber[0]; break; } case 1: { spis = spis + "^2"; FileWrite = FileWrite + sNumber[0]; FileWrite = FileWrite + spis; break; } case 2: { spis = spis + ""; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 3: { spis = spis + "sin"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 4: { spis = spis + "cos"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } case 5: { spis = spis + "tan"; FileWrite = FileWrite + spis; FileWrite = FileWrite + sNumber[0]; break; } } if (randNum != 1) { int flag = 0; int dir = 0; for (int j = 1; j < randNum; j++) { syn = rand() % 4; string symbol = ""; switch (syn) { case 0: { symbol = symbol + '+'; break; } case 1: { symbol = symbol + '-'; break; } case 2: { symbol = symbol + '*'; break; } case 3: { symbol = symbol + '/'; break; } } FileWrite = FileWrite + symbol; if ((rand() % 3 == 1) && (flag == 0) && (j != randNum - 1)) { FileWrite = FileWrite + "("; flag = 1; dir = j; } FileWrite = FileWrite + sNumber[j]; if ((dir != j) && (flag == 1) && (rand() % 3 == 2)) { FileWrite = FileWrite + ")"; flag = 2; } } if (flag == 1) { FileWrite = FileWrite + ")"; flag = 2; } } if (find(FileWrite, USER) == 1) { File << FileWrite; File << endl << endl; } else { i = i - 1; } } File.close(); } int user = 0; int type = 0; // 主函式 int main() { cout << "試卷生成系統" << endl; cout << "請輸入使用者名稱和密碼" << endl; while (1) { // user等於0時表示登入初始介面,不同的user的值表示不同的賬戶 if (user == 0) { char username[20] = ""; char password[20] = ""; cin >> username >> password; if ((strcmp(username, "張三1") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為小學出題" << endl; user = 1; type = 1; } else if ((strcmp(username, "張三2") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為小學出題" << endl; user = 2; type = 1; } else if ((strcmp(username, "張三3") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為小學出題" << endl; user = 3; type = 1; } else if ((strcmp(username, "李四1") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為初中出題" << endl; user = 4; type = 2; } else if ((strcmp(username, "李四2") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為初中出題" << endl; user = 5; type = 2; } else if ((strcmp(username, "李四3") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為初中出題" << endl; user = 6; type = 2; } else if ((strcmp(username, "王五1") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為高中出題" << endl; user = 7; type = 3; } else if ((strcmp(username, "王五2") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為高中出題" << endl; user = 8; type = 3; } else if ((strcmp(username, "王五3") == 0) && (strcmp(password, "123") == 0)) { cout << "登入成功" << endl; cout << "當前選擇為高中出題" << endl; user = 9; type = 3; } else { cout << "請輸入正確的使用者名稱、密碼:" << endl; } } // user大於等於1時進入生成試卷系統 if (user >= 1) { char choosetype[20] = ""; cout << "是否更換當前出題型別" << endl; cin >> choosetype; // 切換出題型別 if (strcmp(choosetype, "切換為小學") == 0) { type = 1; } else if (strcmp(choosetype, "切換為初中") == 0) { type = 2; } else if (strcmp(choosetype, "切換為高中") == 0) { type = 3; } else { cout << "請輸入小學、初中和高中三個選項中的一個" << endl; continue; } switch (type) { case 1: { cout << "準備生成小學數學題目,請輸入生成題目數量"; cout << "(輸入-1將退出當前使用者,重新登入):" << endl; break; } case 2: { cout << "準備生成初中數學題目,請輸入生成題目數量"; cout << "(輸入-1將退出當前使用者,重新登入):" << endl; break; } case 3: { cout << "準備生成高中數學題目,請輸入生成題目數量"; cout << "(輸入-1將退出當前使用者,重新登入):" << endl; break; } } int number = 0; cin >> number; // 選擇出題數量 if (number == -1) { user = 0; } else if ((number <= 30) && (number >= 10)) { // 呼叫生成試卷函式:將試題數量、使用者、型別傳入 get(number, user, type); cout << "卷子生成成功!已退出" << endl; cout << "試卷生成系統" << endl; cout << "請輸入使用者名稱和密碼" << endl; user = 0; } } } }
View Code

本次程式碼使用將近400行程式碼來實現出卷功能。我將以登入,切換出卷模式,出卷,查重這四個功能進行講述。

(1)登入功能

使用while迴圈用if來判斷使用者及密碼是否正確,並設定了使用者型別跟出卷型別為user跟type。

cout << "試卷生成系統" << endl;
  cout << "請輸入使用者名稱和密碼" << endl;
  while (1) {
    // user等於0時表示登入初始介面,不同的user的值表示不同的賬戶
    if (user == 0) {
      char username[20] = "";
      char password[20] = "";
      cin >> username >> password;
      if ((strcmp(username, "張三1") == 0) &&
          (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為小學出題" << endl;
        user = 1;
        type = 1;
      } else if ((strcmp(username, "張三2") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為小學出題" << endl;
        user = 2;
        type = 1;
      } else if ((strcmp(username, "張三3") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為小學出題" << endl;
        user = 3;
        type = 1;
      } else if ((strcmp(username, "李四1") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為初中出題" << endl;
        user = 4;
        type = 2;
      } else if ((strcmp(username, "李四2") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為初中出題" << endl;
        user = 5;
        type = 2;
      } else if ((strcmp(username, "李四3") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為初中出題" << endl;
        user = 6;
        type = 2;
      } else if ((strcmp(username, "王五1") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為高中出題" << endl;
        user = 7;
        type = 3;
      } else if ((strcmp(username, "王五2") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為高中出題" << endl;
        user = 8;
        type = 3;
      } else if ((strcmp(username, "王五3") == 0) &&
                 (strcmp(password, "123") == 0)) {
        cout << "登入成功" << endl;
        cout << "當前選擇為高中出題" << endl;
        user = 9;
        type = 3;
      } else {
        cout << "請輸入正確的使用者名稱、密碼:" << endl;
      }
    }
登入程式碼

(2)切換出卷型別

在每次出卷前都要輸入出卷的型別如”切換為小學“才能進入出卷,並輸出當時為什麼型別的出卷。

 if (user >= 1) {
      char choosetype[20] = "";
      cout << "是否更換當前出題型別" << endl;
      cin >> choosetype;
      // 切換出題型別
      if (strcmp(choosetype, "切換為小學") == 0) {
        type = 1;
      } else if (strcmp(choosetype, "切換為初中") == 0) {
        type = 2;
      } else if (strcmp(choosetype, "切換為高中") == 0) {
        type = 3;
      } else {
        cout << "請輸入小學、初中和高中三個選項中的一個" << endl;
        continue;
      }
      switch (type) {
        case 1: {
          cout << "準備生成小學數學題目,請輸入生成題目數量";
          cout << "(輸入-1將退出當前使用者,重新登入):" << endl;
          break;
        }
        case 2: {
          cout << "準備生成初中數學題目,請輸入生成題目數量";
          cout << "(輸入-1將退出當前使用者,重新登入):" << endl;
          break;
        }
        case 3: {
          cout << "準備生成高中數學題目,請輸入生成題目數量";
          cout << "(輸入-1將退出當前使用者,重新登入):" << endl;
          break;
        }
      }
切換出卷型別程式碼

(3)出卷

使用get(int NUM, int USER, int TYPE)來進行出卷,傳入引數出卷題目數量,出卷人,出卷的型別。

並把出的試卷生成並儲存在該使用者的目錄下,以出卷時間為命名的txt檔案。根據小學加減乘除括號,初中有根號或者平方,高中有三角函式來進行分類編寫,用rand產生隨機數來確定使用什麼運算元,操作符,運算元大小,並用string進行拼接,雖然滿足了加減乘除,但是在特殊符號的處理上只放在第一位來對算術進行特殊化,如sin50+6*5=。

void get(int NUM, int USER, int TYPE) {
  time_t t = time(NULL);
  ofstream File;
  char ttime[33];
  // 確定使用者
  switch (USER) {
    case 1: {
      strftime(ttime, 33, "./張三1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 2: {
      strftime(ttime, 33, "./張三2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 3: {
      strftime(ttime, 33, "./張三3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 4: {
      strftime(ttime, 33, "./李四1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 5: {
      strftime(ttime, 33, "./李四2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 6: {
      strftime(ttime, 33, "./李四3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 7: {
      strftime(ttime, 33, "./王五1/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 8: {
      strftime(ttime, 33, "./王五2/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
    case 9: {
      strftime(ttime, 33, "./王五3/%Y-%m-%d-%H-%M-%S.txt", localtime(&t));
      break;
    }
  }
  File.open(ttime);
  int randNum = 0;
  int diff = 0;
  // 確定型別
  switch (TYPE) {
    case 1: {
      diff = 0;
      break;
    }
    case 2: {
      diff = 2;
      break;
    }
    case 3: {
      diff = 5;
      break;
    }
  }
  int syn = 0, spin = 0;
  // 生成題目
  for (int i = 1; i <= NUM; i++) {
    File << i << ". " << endl;
    if (diff == 0) {
      randNum = rand() % 4 + 2;
    } else {
      randNum = rand() % 5 + 1;
    }
    int Number[randNum] = {0, 0, 0, 0, 0};
    string sNumber[randNum] = {"", "", "", "", ""};
    for (int j = 0; j < randNum; j++) {
      Number[j] = rand() % 100 + 1;
      sNumber[j] = to_string(Number[j]);
    }
    string FileWrite = "";
    if (diff == 0) {
      spin = 0;
    } else if (diff == 2) {
      spin = rand() % 2 + 1;
    } else if (diff == 5) {
      spin = rand() % 3 + 3;
    }
    string spis = "";
    switch (spin) {
      case 0: {
        FileWrite = FileWrite + sNumber[0];
        break;
      }
      case 1: {
        spis = spis + "^2";
        FileWrite = FileWrite + sNumber[0];
        FileWrite = FileWrite + spis;
        break;
      }
      case 2: {
        spis = spis + "";
        FileWrite = FileWrite + spis;
        FileWrite = FileWrite + sNumber[0];
        break;
      }
      case 3: {
        spis = spis + "sin";
        FileWrite = FileWrite + spis;
        FileWrite = FileWrite + sNumber[0];
        break;
      }
      case 4: {
        spis = spis + "cos";
        FileWrite = FileWrite + spis;
        FileWrite = FileWrite + sNumber[0];
        break;
      }
      case 5: {
        spis = spis + "tan";
        FileWrite = FileWrite + spis;
        FileWrite = FileWrite + sNumber[0];
        break;
      }
    }
    if (randNum != 1) {
      int flag = 0;
      int dir = 0;
      for (int j = 1; j < randNum; j++) {
        syn = rand() % 4;
        string symbol = "";
        switch (syn) {
          case 0: {
            symbol = symbol + '+';
            break;
          }
          case 1: {
            symbol = symbol + '-';
            break;
          }
          case 2: {
            symbol = symbol + '*';
            break;
          }
          case 3: {
            symbol = symbol + '/';
            break;
          }
        }
        FileWrite = FileWrite + symbol;
        if ((rand() % 3 == 1) &&
            (flag == 0) &&
            (j != randNum - 1)) {
          FileWrite = FileWrite + "(";
          flag = 1;
          dir = j;
        }
        FileWrite = FileWrite + sNumber[j];
        if ((dir != j) &&
            (flag == 1) &&
            (rand() % 3 == 2)) {
          FileWrite = FileWrite + ")";
          flag = 2;
        }
      }
      if (flag == 1) {
        FileWrite = FileWrite + ")";
        flag = 2;
      }
    }
    if (find(FileWrite, USER) == 1) {
      File << FileWrite;
      File << endl << endl;
    } else {
      i = i - 1;
    }
  }
  File.close();
}
View Code

(4)查重

首先是傳入該使用者的資訊,以此來進入該使用者目錄下的檔案,在遍歷目錄下所有檔案,進入檔案中的txt,提取每一行成string,並於出的題作比較,如果相同返回-1,如果不同返回1.

void getFiles(string path, vector<string> &files) {
  // 檔案句
  int16_t hFile = 0;
  // 檔案資訊
  struct _finddata_t fileinfo;
  string pathName;
  if ((hFile = _findfirst(pathName.assign(path).c_str(), &fileinfo)) != -1) {
    do {
        if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
          files.push_back(pathName.assign(path).
                          append("/").append(fileinfo.name));
    } while (_findnext(hFile, &fileinfo) == 0);
    _findclose(hFile);
  }
}
// 查重函式:將先前的文件進行遍歷,
// 然後在提取出每一行的字串,
// 比較每一行的字串,
// 若沒有重複則返回1,重複了就返回-1
int find(string test, int ty) {
  string FindType = "";
  switch (ty) {
    case 1: {
      FindType = "./張三1/";
      break;
    }
    case 2: {
      FindType = "./張三2/";
      break;
    }
    case 3: {
      FindType = "./張三3/";
      break;
    }
    case 4: {
      FindType = "./李四1/";
      break;
    }
    case 5: {
      FindType = "./李四2/";
      break;
    }
    case 6: {
      FindType = "./李四3/";
      break;
    }
    case 7: {
      FindType = "./王五1/";
      break;
    }
    case 8: {
      FindType = "./王五2/";
      break;
    }
    case 9: {
      FindType = "./王五3/";
      break;
    }
  }
  vector<string> files;
  getFiles(FindType, files);
  int size = files.size();
  for (int i = 0; i < size; i++) {
    ifstream fin(files[i]);
    string past;
    while (fin >> past) {
      if (past == test)
        return (-1);
    }
  }
  return 1;
}
查重

三總結

優點:

本次程式設計基本實現了功能,在每個使用者下正確出小學,初中,高中試卷,出卷題目滿足要求。程式碼使用get函式進行出題,getFile和find函式進行查重,查重通過才寫入txt。

缺點:

註釋太少,運算元,操作符的註釋沒有,讓人剛開始理解起來不是那麼流暢。功能實現有不合理性,因為只在第一位數字才進行特殊化處理,題目就沒有那麼合理性。

評價:

我的也是使用的是C++,大體是一樣的,但是在出題的時候,他是三份型別試卷一起寫,理解起來較為困難。對比起來,總會發現自己與他人的差別,在之後也會學習別人的優點,運用更好的方法。