前言
文章灵感源自于好兄弟的求助。好兄弟让我写一个 ATM 模拟程序来和他的对比一下。
从 OI 层面来看,这不就是纯纯的中等模拟吗?直接启洞!
设计
分析
我们先来看看要求:
ATM模拟程序能够完成ATM的主要功能,包括:
①显示欢迎词及提示信息;
②用户插卡,ATM验证用户账号及密码有效性,输入错误3次即被锁卡;
③余额查询:初始余额为10000元;
④取款功能:每次取款余额为100的整数倍,有单笔和单日金额限制;
⑤转账功能:可将本账户中的存款转入其它账户,转入账户账号需两次输入确认;
⑥修改密码:密码为6位数字,新密码需要两次输入确认;
⑦退卡。
设计实现命令行界面,界面应友好、方便操作。
不着急分析要求,我们再看看 ATM 机的工作流程:
插卡(进入系统)-> 登录 -> 用户操作(存取款等) ->退卡
通过分析了工作流程,我们可以发现一个简单的 ATM 机可以分为三个子系统:主界面系统、登录系统、用户端操作系统。
再回头看看设计要求,我们可以发现要求 ① 是贯穿 3 个子系统的,要求 ② 则是对于登陆系统来说的,剩下的要求都是对用户操作系统的要求,知道了这些,我们就可以开始设计程序了。
总体设计思路:使用类来实现 ATM 机的模拟。
代码
账户
首先先建立账户信息。一个账户所包含的信息有:用户名、卡号、密码、身份证号、余额、银行卡状态以及银行卡限额(和现实相似,I 类卡和 II 类卡)
使用结构体来定义这些内容,代码如下:
struct Account{
string cardid;
string user_name;
string idcard;
string password;
double money;
bool lock;
int limit;
};
卡号,身份证号,用户名可能长达十几位,因此使用 string 来存储。
密码固定六位,方便判断也用了 string 。(用 int 其实也可以)
钱可能会出现小数,所以我们使用 double 类型。
lock 表示银行卡状态。0为未锁卡,1为锁卡。
limit 表示限额。
主界面
我们首先使用 类 来定义 ATM 系统
class ATMsystem {
public:
vector<Account> accountlist; //银行账户存储,方便查找
const int once_limit = 1e9+7; //一次的限额,为了方便就这样定义了
}atm;
接下来是写主界面系统,我们命名为 sys (防止和system函数重名)
主界面比较容易,就是一个按钮对应一个操作,一个操作对应一个函数。
void sys(){
while(1) {
clear();
cout<<"=============== ATM 系统 ==============="<<endl;
cout<<"欢迎使用 ATM 机!请选择你要操作的类型"<<endl;
cout<<"1、银行开户\n2、用户登录\n3、退出系统"<<endl;
cout<<"按5可获取帮助"<<endl;
int op;
while( 1 ) {
cin >> op;
if( op == 0 ) op = 3;
if(op == 1 || op == 2 || op == 3 || op == 4 || op == 5 ) break;
cout << "操作错误!请重新输入" << endl;
}
if(op==1) {
clear();
add();
}
else if(op==2) {
int record = login();
//if( record != -1 ) { cout<<record<<"\n";system("pause");/*cout<<accountlist[record].money<<'\n';*/}
if( record != -1 ) user_command( accountlist[record] );
}
else if( op == 3 ) {
close();
break;
}
else if( op == 4 ) {clear();checklist();system("pause");}
else if( op == 5 ) {help();}
}
}
创建账户
如果用户选择了1(银行开户),就跳转到创建账户函数(命名为 add 或者 registered 均可),这里命名为 add。
创建账户需要经历以下过程:
输入姓名 -> 输入身份证号 -> 输入密码 -> 二次确认 -> 随机一个银行卡号,完成账户创建。
其中:身份证号、密码需要验证是否合法。身份证号为 18 位,密码为 6 位。
void add() {
Account user;
cout << "请输入姓名:" << endl;
cin>>user.user_name;
cout << "请输入身份证号:" << endl;
while(1) {
cin >> user.idcard;
if( user.idcard == "0" ) return ;
if( user.idcard.size()==18 ) break;
else cout<< "格式错误!请重新输入。"<< endl;
}
cout << "请输入密码" << endl;
while(1) {
cin >> user.password;
while( user.password.size() != 6 ) {cout << "格式错误!请重新输入" << endl; cin >> user.password;}
if ( check_password( user.password ) == 1 ) {
cout << "请再次确认密码!" <<endl;
string temp;
cin >> temp;
while( temp.size() != 6 ) {cout << "格式错误!请重新输入" << endl; cin >> temp;}
if( temp == user.password ) {
user.money = 10000 ; user.lock = 0; user.limit = 1000000;
user.cardid = id_rand();
accountlist.push_back(user);
cout << "创建账户成功!您的账户是: " << user.cardid << endl;
break;
}
}
}
cout<<accountlist.size()<<'\n';
system("pause");//暂停,方便用户记录卡号。
}
登录
如果用户选择了 2 (登录),跳转至登录系统。这里将登录系统命名为 login。
login 函数应为 int 型,以便确认是否能够登录以及返回登录账户在 accountlist 的位置。
登录系统流程:
插卡(输入卡号) -> 输入密码 -> 进入操作系统/返回主界面
这里需要注意以下几点:
- 密码输错三次马上锁卡,告知用户并返回主界面;
- 检查密码位数是否合法,不合法的密码不能算输错密码;
- 如果卡已经被上锁,告知用户并退回主界面;
- 成功登录,返回账户返回登录账户在 accountlist 的位置,否则返回 -1。(因为 vector 数组从 0 开始)
int login() {
clear();
int cnt = 0,flag; Account user;
cout << "请输入账户" << endl;
while(1) {
flag = -1; string str;
cin >> str;
if( str == "0" ) return -1;
for(int i=0;i<(int)accountlist.size();++i) {
if( accountlist[i].cardid == str ) {
user = accountlist[i];
flag = i;
break;
}
}
if( flag != -1 ) break;
else cout << "该账户不存在!请重新输入" << endl;
}
if( user.lock == 1 ) {
cout << "该银行卡以上锁,请联系银行" << endl;
return -1;
}
cout << "请输入密码" << endl;
while( cnt<3 ) {
string str;
cin >> str;
while( check_password(str) != 1 ) {
cout << "密码不合法,请重新输入" << endl;
cin >> str;
}
if( user.password == str ) {
cout << "登录成功!正在进入操作系统" << endl;
return flag;
}
cnt++;
cout << "密码错误!还有" << 3-cnt << "次机会" << endl;
}
if( cnt == 3 ) {
accountlist[flag].lock = 1;
cout << "银行卡已上锁,请联系银行!" << endl;
}
return -1;
}
用户操作系统
成功登录,进入用户操作系统。这里命名为 user_command。
用户操作系统有以下功能:
- 存款(额外开发功能,作业内并未要求);
- 取款:需要注意取出的钱只能是 100 的整数倍;
- 转账:转账可以转到小数点后两位,目标账户必须在本银行中;
- 余额查询:返回账户内余额就可以了;
- 修改密码:这个简单,输入一次旧密码,一次新密码,二次确认即可;
- 退卡:退出 user_command 函数。
需要注意的是,我们需要对 accountlist 内的数据进行修改而不是它的副本(因为最后退出系统保存数据时保存的是 accountlist 内的数据)。这就是为什么 login 函数我们返回的是对应账户在 accountlist 的位置而不是简单的 0-1 的原因。
void user_command(Account &user) {
while(1) {
clear();
cout << "请选择您需要办理的业务" << endl;
cout << "1、存款" << "\n" << "2、取款" << "\n" << "3、转账" << "\n" ;
cout << "4、余额查询" << "\n" << "5、修改密码" << "\n" << "6、退卡" << endl;
int op ;
cin >> op;
while( op<1 || op>6 ) {cout << "操作错误!请重新输入" << endl; cin >> op;}
if( op == 1 ) {
cout << "本机暂不支持存款业务!" << endl;
}
else if( op == 2 ) {
clear();
double number = 0 ;int input ;
cout << "请选择取款金额" << endl;
cout << "1 - 100" << "\n" << "2 - 200" << "\n" << "3 - 500" << "\n" ;
cout << "4 - 1000" << "\n" << "5 - 自定义" << endl;
while( 1 ) {
cin >> input;
if( input < 1 || input > 5 ) continue; //need fix
break;
}
if( input == 1 ) number = 100;
else if( input == 2 ) number = 200;
else if( input == 3 ) number = 500;
else if( input == 4 ) number = 1000;
else if( input == 5 ) {
cout << "请输入金额" << endl;
int temp = 0;
cin >> temp ;
while( temp % 100 != 0 ) {
cout << "金额错误!请重新输入" << endl;
cin >> temp ;
}
number = temp * 1.0 ;
}
/*cout<<number<<" "<<user.limit<<'\n';
system("Pause");*/
if( user.money < number ) { cout << "余额不足!" << endl; system("pause"); continue ;}
else if( number > user.limit ) { cout << "无法取出,因为今日可取款数量仅剩" << user.limit <<"元,如有需要请到柜台办理。" << endl; system("pause"); continue;}
else if( number > once_limit ) { cout << "操作失败!单笔仅可取出 " << once_limit << "元,如有需要请到柜台办理。" << endl; system("pause"); continue;}
user.money-=number; user.limit-=number;
cout << "操作成功!账户余额还剩" << user.money << endl;
}
else if( op == 3 ) {
string id; Account target; double number; int flag = -1;
clear();
cout << "请输入目标账户的卡号" << endl;
while(1) {
cin >> id;
flag = -1;
for(int i=0;i<(int)accountlist.size();++i) {
if( accountlist[i].cardid == id ) {
target = accountlist[i];
flag = i;
break;
}
}
if( flag != -1 ) break;
else cout << "目标账户不存在,请重新输入!" << endl;
}
cout << "请输入转账金额" << endl;
cin >> number;
//cout << number << " " << user.money << endl;
while( number > user.money ) {
if( number == 0 ) break;
cout << "余额不足!" << endl;
Sleep(5000);
cin >> number;
}
if( number == 0 ) continue;
cout << "请再次确认目标账户的卡号" << endl;
cin >> id;
while( id!=target.cardid ) {
clear();
cout << "两次输入账户不一致,请重新输入" << endl;
cin >> id;
}
user.money-=number; accountlist[flag].money+=number;
cout << "操作成功!已向目标账户转账" << number << "元" << endl;
}
else if( op == 4 ) {
clear();
cout << "您的账户目前余额为: " << user.money << "元" << endl;
}
else if( op == 5 ) {
string old_password,new_password,str;
cout << "请输入旧密码" << endl;
while(1) {
cin>>old_password;
if( old_password != user.password ) {
cout << "密码错误,请重新输入!" << endl;
continue;
}
else break;
}
cout << "请输入新密码" << endl;
cin >> new_password;
while( old_password == new_password ) {
cout << "新密码不能与旧密码相同!请重新输入" << endl;
cin >> new_password;
}
cout << "请再次确认新密码:" << endl;
cin >> str;
while( str != new_password ) {
cout << "两次输入不一致!请重新输入" << endl;
cin >> str;
}
user.password = new_password;
cout << "修改成功!" << endl;
}
else if( op == 6 ) {
clear();
cout << "退卡成功!" << endl;
system("pause");
break;
}
system("pause");
}
return ;
}
至此,我们三大子系统已经全部实现。
接下来是一些三大子系统所需的小功能:
- 随机卡号
string id_rand() {
srand(time(0));
string temp="";
for(int i=1;i<=19;++i) {
int num = rand() % 10;
char x = num + '0';
temp.push_back(x);
}
return temp;
}
- 密码合法性检查
bool check_password(string password) {
if( password.size()<6 ) return false;
for(int i=0;i<6;++i) {
if( password[i]<'0' || password[i]>'9' ) return false;
}
return true;
}
- clear函数
清除屏幕内容,保持交互界面干净整洁
- 数据文件读写
略。
总代码
#include<iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<string>
#include<windows.h>
using namespace std;
const int inf = 2147483647;
const double eps = 1e-3;
struct Account{
string cardid;
string user_name;
string idcard;
string password;
double money;
bool lock;
int limit;
};
class ATMsystem {
public:
vector<Account> accountlist; const int once_limit = 1e9+7;
public:
bool check_password(string password) {
if( password.size()<6 ) return false;
for(int i=0;i<6;++i) {
if( password[i]<'0' || password[i]>'9' ) return false;
}
return true;
}
string id_rand() {
srand(time(0));
string temp="";
for(int i=1;i<=19;++i) {
int num = rand() % 10;
char x = num + '0';
temp.push_back(x);
}
return temp;
}
void init() {
ifstream fin;
fin.open("data.txt",ios::in);
if( !fin.is_open() ) {
cout << "读取文件失败!" << endl;
return ;
}
char line1[1024]={0},line2[1024]={0}; Account registered;
while(fin.getline(line1,sizeof(line1))) {
Account temp;
stringstream word(line1);
word >> temp.cardid;
word >> temp.user_name;
word >> temp.idcard;
word >> temp.password;
fin.getline(line2,sizeof(line2));
istringstream string_to_num(line2);
string_to_num >> temp.money >> temp.lock >> temp.limit;
accountlist.push_back(temp);
}
fin.close();
}
void close() {
ofstream fout;
fout.open("data.txt",ios::out);
if( !fout.is_open() ) {
cout << "写入文件失败!" << endl;
return ;
}
for(int i=0;i<(int)accountlist.size();++i) {
fout << accountlist[i].cardid << " " << accountlist[i].user_name << " ";
fout << accountlist[i].idcard << " " << accountlist[i].password << endl ;
fout << accountlist[i].money << " " << accountlist[i].lock << " " << accountlist[i].limit << endl;
}
fout.close();
}
void Administrator() {
Account admin;
admin.cardid="001"; admin.user_name="admin"; admin.idcard="001"; admin.password="123456";
admin.money=10000; admin.lock=0; admin.limit = inf;
accountlist.push_back(admin);
return ;
}
void checklist() {
cout<<accountlist.size()<<"\n";
for(int i=0;i<(int)accountlist.size();++i) {
cout<<accountlist[i].cardid<<" "<<accountlist[i].user_name<<" "<<accountlist[i].password;
cout<<" "<<accountlist[i].money<<'\n';
}
}
void clear() {
system("cls");
return ;
}
void help() {
clear();
cout << "按 0 可以退回上一个界面" << endl;
system("pause");
}
void add() {
Account user;
cout << "请输入姓名:" << endl;
cin>>user.user_name;
cout << "请输入身份证号:" << endl;
while(1) {
cin >> user.idcard;
if( user.idcard == "0" ) return ;
if( user.idcard.size()==18 ) break;
else cout<< "格式错误!请重新输入。"<< endl;
}
cout << "请输入密码" << endl;
while(1) {
cin >> user.password;
while( user.password.size() != 6 ) {cout << "格式错误!请重新输入" << endl; cin >> user.password;}
if ( check_password( user.password ) == 1 ) {
cout << "请再次确认密码!" <<endl;
string temp;
cin >> temp;
while( temp.size() != 6 ) {cout << "格式错误!请重新输入" << endl; cin >> temp;}
if( temp == user.password ) {
user.money = 10000 ; user.lock = 0; user.limit = 1000000;
user.cardid = id_rand();
accountlist.push_back(user);
cout << "创建账户成功!您的账户是: " << user.cardid << endl;
break;
}
}
}
cout<<accountlist.size()<<'\n';
system("pause");
}
int login() {
clear();
int cnt = 0,flag; Account user;
cout << "请输入账户" << endl;
while(1) {
flag = -1; string str;
cin >> str;
if( str == "0" ) return -1;
for(int i=0;i<(int)accountlist.size();++i) {
if( accountlist[i].cardid == str ) {
user = accountlist[i];
flag = i;
break;
}
}
if( flag != -1 ) break;
else cout << "该账户不存在!请重新输入" << endl;
}
if( user.lock == 1 ) {
cout << "该银行卡以上锁,请联系银行" << endl;
return -1;
}
cout << "请输入密码" << endl;
while( cnt<3 ) {
string str;
cin >> str;
while( check_password(str) != 1 ) {
cout << "密码不合法,请重新输入" << endl;
cin >> str;
}
if( user.password == str ) {
cout << "登录成功!正在进入操作系统" << endl;
return flag;
}
cnt++;
cout << "密码错误!还有" << 3-cnt << "次机会" << endl;
}
if( cnt == 3 ) {
accountlist[flag].lock = 1;
cout << "银行卡已上锁,请联系银行!" << endl;
}
return -1;
}
void user_command(Account &user) {
while(1) {
clear();
cout << "请选择您需要办理的业务" << endl;
cout << "1、存款" << "\n" << "2、取款" << "\n" << "3、转账" << "\n" ;
cout << "4、余额查询" << "\n" << "5、修改密码" << "\n" << "6、退卡" << endl;
int op ;
cin >> op;
while( op<1 || op>6 ) {cout << "操作错误!请重新输入" << endl; cin >> op;}
if( op == 1 ) {
cout << "本机暂不支持存款业务!" << endl;
}
else if( op == 2 ) {
clear();
double number = 0 ;int input ;
cout << "请选择取款金额" << endl;
cout << "1 - 100" << "\n" << "2 - 200" << "\n" << "3 - 500" << "\n" ;
cout << "4 - 1000" << "\n" << "5 - 自定义" << endl;
while( 1 ) {
cin >> input;
if( input < 1 || input > 5 ) continue; //need fix
break;
}
if( input == 1 ) number = 100;
else if( input == 2 ) number = 200;
else if( input == 3 ) number = 500;
else if( input == 4 ) number = 1000;
else if( input == 5 ) {
cout << "请输入金额" << endl;
int temp = 0;
cin >> temp ;
while( temp % 100 != 0 ) {
cout << "金额错误!请重新输入" << endl;
cin >> temp ;
}
number = temp * 1.0 ;
}
/*cout<<number<<" "<<user.limit<<'\n';
system("Pause");*/
if( user.money < number ) { cout << "余额不足!" << endl; system("pause"); continue ;}
else if( number > user.limit ) { cout << "无法取出,因为今日可取款数量仅剩" << user.limit <<"元,如有需要请到柜台办理。" << endl; system("pause"); continue;}
else if( number > once_limit ) { cout << "操作失败!单笔仅可取出 " << once_limit << "元,如有需要请到柜台办理。" << endl; system("pause"); continue;}
user.money-=number; user.limit-=number;
cout << "操作成功!账户余额还剩" << user.money << endl;
}
else if( op == 3 ) {
string id; Account target; double number; int flag = -1;
clear();
cout << "请输入目标账户的卡号" << endl;
while(1) {
cin >> id;
flag = -1;
for(int i=0;i<(int)accountlist.size();++i) {
if( accountlist[i].cardid == id ) {
target = accountlist[i];
flag = i;
break;
}
}
if( flag != -1 ) break;
else cout << "目标账户不存在,请重新输入!" << endl;
}
cout << "请输入转账金额" << endl;
cin >> number;
//cout << number << " " << user.money << endl;
while( number > user.money ) {
if( number == 0 ) break;
cout << "余额不足!" << endl;
Sleep(5000);
cin >> number;
}
if( number == 0 ) continue;
cout << "请再次确认目标账户的卡号" << endl;
cin >> id;
while( id!=target.cardid ) {
clear();
cout << "两次输入账户不一致,请重新输入" << endl;
cin >> id;
}
user.money-=number; accountlist[flag].money+=number;
cout << "操作成功!已向目标账户转账" << number << "元" << endl;
}
else if( op == 4 ) {
clear();
cout << "您的账户目前余额为: " << user.money << "元" << endl;
}
else if( op == 5 ) {
string old_password,new_password,str;
cout << "请输入旧密码" << endl;
while(1) {
cin>>old_password;
if( old_password != user.password ) {
cout << "密码错误,请重新输入!" << endl;
continue;
}
else break;
}
cout << "请输入新密码" << endl;
cin >> new_password;
while( old_password == new_password ) {
cout << "新密码不能与旧密码相同!请重新输入" << endl;
cin >> new_password;
}
cout << "请再次确认新密码:" << endl;
cin >> str;
while( str != new_password ) {
cout << "两次输入不一致!请重新输入" << endl;
cin >> str;
}
user.password = new_password;
cout << "修改成功!" << endl;
}
else if( op == 6 ) {
clear();
cout << "退卡成功!" << endl;
system("pause");
break;
}
system("pause");
}
return ;
}
void sys(){
while(1) {
clear();
cout<<"=============== ATM 系统 ==============="<<endl;
cout<<"欢迎使用 ATM 机!请选择你要操作的类型"<<endl;
cout<<"1、银行开户\n2、用户登录\n3、退出系统"<<endl;
cout<<"按5可获取帮助"<<endl;
int op;
while( 1 ) {
cin >> op;
if( op == 0 ) op = 3;
if(op == 1 || op == 2 || op == 3 || op == 4 || op == 5 ) break;
cout << "操作错误!请重新输入" << endl;
}
if(op==1) {
clear();
add();
}
else if(op==2) {
int record = login();
//if( record != -1 ) { cout<<record<<"\n";system("pause");/*cout<<accountlist[record].money<<'\n';*/}
if( record != -1 ) user_command( accountlist[record] );
}
else if( op == 3 ) {
close();
break;
}
else if( op == 4 ) {clear();checklist();system("pause");}
else if( op == 5 ) {help();}
}
}
}atm;
int main() {
atm.init();
//atm.Administrator();
atm.sys();
return 0;
}
代码已经加入防抄袭,请自己独立完成呐~
总结
OIer 毫不畏惧。不需要过多的思维,无脑写就完了!
可以尝试自己开发一下管理员系统和完善存款功能,更加还原现实生活的 ATM 系统。