一开始我们所用代码选用了我们之中较好的我的搭档的代码,就是代码量稍微大了些 但是实现的功能更全。
这次php版的四则运算出炉了
由于c++代码转php代码有个BUG调不出来,首先,环境:
WampServer 3.0 64bit
netbeans 8.1
然后,数据库设计,
三个表:用户表user,管理员表admin,答题记录表ansrecord
表结构在这里
/*Navicat MySQL Data TransferSource Server : tpSource Server Version : 50709Source Host : localhost:3306Source Database : 2zhuziTarget Server Type : MYSQLTarget Server Version : 50709File Encoding : 65001Date: 2016-03-31 16:22:23*/SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `admin`-- ----------------------------DROP TABLE IF EXISTS `admin`;CREATE TABLE `admin` ( `adminid` int(11) NOT NULL AUTO_INCREMENT, `adminname` varchar(255) NOT NULL, `pwd` varchar(255) NOT NULL, PRIMARY KEY (`adminid`)) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;-- ------------------------------ Records of admin-- ----------------------------INSERT INTO `admin` VALUES ('1', 'admin', '123456');INSERT INTO `admin` VALUES ('2', 'root', '123456');-- ------------------------------ Table structure for `ansrecord`-- ----------------------------DROP TABLE IF EXISTS `ansrecord`;CREATE TABLE `ansrecord` ( `ansrecordid` int(11) NOT NULL AUTO_INCREMENT, `userid` int(11) NOT NULL, `question` varchar(255) NOT NULL, `rightans` double NOT NULL, `lastans` varchar(255) NOT NULL, PRIMARY KEY (`ansrecordid`), KEY `userid` (`userid`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;-- ------------------------------ Records of ansrecord-- ------------------------------ ------------------------------ Table structure for `user`-- ----------------------------DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `userid` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `pwd` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, PRIMARY KEY (`userid`)) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
再然后,用户部分:
包括用户登录,用户注册,用户首页三个页面,可实现用户注册,登陆,注销,跳转到在线答题,访问隔离(好像叫这么个名字)等功能,
接下来是管理员部分:
包括 管理员登录,管理员首页,用户列表,答题记录列表四个页面,可实现管理员的登录,注销,查看用户列表,删除特定用户,查看答题记录,删除指定答题记录等功能。
最后,在线答题部分:
这部分就是核心包括OJ首页,设置题目各种属性,题目列表页面,旧题浏览页面,可实现题目属性设定,服务器端生成题目,旧题浏览,保存答题结果等功能。
题目生成是questionGenerator这个类完成的。
由于xdebug+netbeans/phpstrom/sublime/zendstudio 什么什么的环境弄不起来,所以在线判断这部分功能就阉了。。 其实写好了调了好久调不对。。
下面是我们的核心代码
1 itemNum = $itemNum; 14 $this->isMulandDiv = $isMulandDiv; 15 $this->isParentheses = $isParentheses; 16 $this->isNeg = $isNeg; 17 $this->isRem = $isRem; 18 $this->start = $start; 19 $this->end = $end; 20 } 21 22 function isTrueFraction($numerator,$denominator){ //判断产生的分数是否是真分数 23 if($numerator >= $denominator){ 24 return false; 25 } 26 for($i = 2; $i <= $numerator;$i++){ //判断分数是否能够约分 27 if(($numerator % $i == 0)&&($denominator % $i == 0)){ 28 return false; 29 } 30 } 31 return true; 32 } 33 34 function getNum($start = 0, $end = 100,$isParentheses = false,$depth = 0){ // 若带括号 则为 a op ( b op c ) 的形式 op为运算符 35 if($isParentheses){ 36 $num1 = mt_rand($start,$end); 37 if($depth < 2){ //控制递归层数,带括号的式子少于10个 38 $num2 = "( " . $this->getNum($start,$end,mt_rand() % 2 == 0,$depth + 1) . " )"; 39 return strval($num1) . " , " . $num2; 40 }else{ 41 $num2 = "( " . $this->getNum($start,$end,false,$depth + 1) . " )"; 42 return strval($num1) . " , " . $num2; 43 } 44 }else{ 45 if(mt_rand() % 7 == 0){ //若随机数n是7的倍数,产生一个真分数和一个整数,否则为两个整数 46 $num1 = mt_rand($start,$end); 47 $num2 = mt_rand($start,$end); 48 $num3 = mt_rand($start,$end); 49 if($this->isTrueFraction($num1,$num2)){ 50 return strval($num1) . "/" . strval($num2) . " , " . strval($num3); 51 }else{ 52 return $this->getNum($start,$end); 53 } 54 }else{ 55 $num1 = mt_rand($start,$end); 56 $num2 = mt_rand($start,$end); 57 return strval($num1) . " , " . strval($num2); 58 } 59 } 60 } 61 62 function getOperator($num2 = '1',$isMulandDiv = true){ // 默认第二个参数不为0,默认包括乘除法 63 $op = array('+','-','*','/'); 64 if($isMulandDiv){ 65 if($num2 == '0'){ //避免除数为0 66 return $op[mt_rand() % 3]; 67 }else{ 68 return $op[mt_rand() % 4]; 69 } 70 }else{ 71 return $op[mt_rand() % 2]; 72 } 73 } 74 75 function isNegative($num1, $num2, $op){ 76 if($op == '-'){ 77 if(intval($num1) < intval($num2)){ 78 return true; 79 }else{ 80 return false; 81 } 82 }else{ 83 if(intval($num1) + intval($num2) < 0){ 84 return true; 85 }else{ 86 return false; 87 } 88 } 89 } 90 91 function isRemainder($num1, $num2){ 92 if(intval($num1) % intval($num2) == 0){ 93 return false; 94 }else{ 95 return true; 96 } 97 } 98 99 function generateQuest(){100 $addFlag = false;101 $one = 1;102 while (count($this->items) < $this->itemNum){103 $num = $this->getNum($this->start,$this->end,$this->isParentheses);104 while (strpos($num,",")){105 $addFlag = true;106 if(substr($num,intval(strpos($num,",")) + 2,1) == '('){ //运算符后紧跟括号,运算符选取只和isMulandDiv有关107 $op = $this->getOperator('1',$this->isMulandDiv);108 $num = str_replace(",",$op,$num,$one);109 }else{ //运算符后是数字,运算符选取和num2和isMulandDiv有关,此时是不带括号或最右边的算式110 $num2 = substr($num, intval(strrpos($num,",")) + 2, intval(strpos($num,")")) - intval(strrpos($num,",")) - 3);111 $op = $this->getOperator($num2,$this->isMulandDiv);112 $num = str_replace(",", $op, $num, $one);113 $begin = 0; //找到形如 a op b 的式子114 if(strpos($num, "(")){ //如果式子里有()的话115 $begin = intval(strrpos($num, "(")) + 2;116 }117 $num1 = substr($num, $begin, intval(strrpos($num, $op)) - $begin - 1);118 if( $op == '-' || $op == '+')119 {120 if(!$this->isNeg && $this->isNegative($num1, $num2, $op))121 {122 $addFlag = FALSE;123 break;124 }125 }elseif ($op == '/') {126 if(!$this->isRem && $this->isRemainder($num1, $num2)){127 $addFlag = FALSE;128 break;129 }130 }131 }132 }133 if(!$addFlag){ //满足要求,可以添加134 continue;135 }136 if(!in_array($num, $this->items)){ //判断是否重复,不重复则添加137 array_push($this->items, $num);138 }139 }140 }141 142 function calculate($num1,$num2,$op){143 switch ($op){144 case "+":145 return $num1 + $num2;146 break;147 case "-":148 return $num1 - $num2;149 break;150 case "*":151 return $num1 * $num2;152 break;153 case "/":154 return $num1 / $num2;155 break;156 default :157 echo "";158 }159 }160 161 function getResult(){162 $pri = array(163 '+' => array('+' => '>', '-' => '>', '*' => '<', '/' => '<', '(' => '<', ')' => '>', '#' => '>'),164 '-' => array('+' => '>', '-' => '>', '*' => '<', '/' => '<', '(' => '<', ')' => '>', '#' => '>'),165 '*' => array('+' => '>', '-' => '>', '*' => '>', '/' => '>', '(' => '<', ')' => '>', '#' => '>'),166 '/' => array('+' => '>', '-' => '>', '*' => '>', '/' => '>', '(' => '<', ')' => '>', '#' => '>'),167 '(' => array('+' => '<', '-' => '<', '*' => '<', '/' => '<', '(' => '<', ')' => '=', '#' => ''),168 ')' => array('+' => '>', '-' => '>', '*' => '>', '/' => '>', '(' => '', ')' => '>', '#' => '>'),169 '#' => array('+' => '<', '-' => '<', '*' => '<', '/' => '<', '(' => '<', ')' => '', '#' => '=')170 );171 $ansL = array();172 foreach ($this->items as $exp){173 $stackOps = array();174 $stackNums = array();175 array_push($stackOps,"#");176 $exp = $exp . " #";177 $flag = -1;178 while (!(substr($exp,$flag + 1,1) == "#" && end($stackOps) == "#")){179 $str = substr($exp, $flag + 1, strpos($exp, " ", $flag + 1) - $flag -1);180 if(!in_array($str,array("+","-","*","/","(",")","#"))){181 if(strpos($str,"/")){182 $numerator = substr($str,0,strpos($str,"/"));183 $denominator = substr($str,strpos($str,"/") + 1);184 array_push($stackNums,floatval($numerator)/floatval($denominator));185 $flag = strpos($exp," ",$flag + 1);186 } else {187 array_push($stackNums,floatval($str));188 $flag = strpos($exp," ",$flag + 1);189 }190 } else {191 if($pri[end($stackOps)][$str] == "<"){192 array_push($stackOps,$str);193 $flag = strpos($exp," ",$flag + 1);194 }elseif ($pri[end($stackOps)][$str] == ">") {195 $op = end($stackOps);196 array_pop($stackOps);197 $num2 = end($stackNums);198 array_pop($stackNums);199 $num1 = end($stackNums);200 array_pop($stackNums);201 array_push($stackNums, $this->calculate($num1, $num2, $op));202 }elseif ($pri[end($stackOps)][$str] == "=") {203 array_pop($stackOps);204 $flag = strpos($exp," ",$flag + 1);205 } else {206 echo "";207 }208 }209 }210 array_push($ansL, end($stackNums));211 }212 return $ansL;213 }214 215 function getQuestionList(){216 return $this->items;217 }218 219 220 }复制代码基本思路和c++版的相同,不过php 数组的特性,还有字符串处理的优势,还是更方便一些,代码少了一半。数据库连接用的是PDO,虽然比直接用mysql_* 的函数麻烦一点,但是安全性更高,访问隔离(貌似是这么叫的)在每一部分都有,通过session_start();if(!isset($_SESSION['adminid']) && !isset($_SESSION['adminname']) ){ echo "";}或者session_start();if (!isset($_SESSION['adminid']) && !isset($_SESSION['adminname'])) { echo "";}实现,简单。管理员部分对特定数据操作是在遍历中加入GET请求实现的例如:复制代码 prepare("select * from ansrecord");$stmt->execute();$res = $stmt->fetchAll(PDO::FETCH_ASSOC);?>
序号 | 用户ID | 题目 | 最后答案 | 操作 |
---|---|---|---|---|
" . $key . " | " . $value['userid'] . " | " . $value['question'] . " | ".$value['lastans']." | 删除记录 |
从用户界面->OJ首页->OJ->题目属性设置->题目列表->提交题目和答案到数据库
题目属性设置页面提交一个POST表单,通过PHP输入过滤器对表单内容过滤,然后将属性做参数传入questionGenerator构造函数
$qG = new questionGenerator($itemNum, $isMulandDiv, $isParentheses, $isNeg, $isRem, $start, $end);$qG->generateQuest();$qL = $qG->getQuestionList();$numofqL = count($qL);
将题目通过只读的input框 显示,答案也用表单收集,题目数量通过一个隐藏域传入表单
我的队友信1301-2班 肖兴堂