• 四则运算完结篇


    一开始我们所用代码选用了我们之中较好的我的搭档的代码,就是代码量稍微大了些 但是实现的功能更全。

    这次php版的四则运算出炉了

    由于c++代码转php代码有个BUG调不出来,首先,环境:

    WampServer 3.0 64bit   

    netbeans 8.1 

    然后,数据库设计,

    三个表:用户表user,管理员表admin,答题记录表ansrecord

    表结构在这里

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : tp
    Source Server Version : 50709
    Source Host           : localhost:3306
    Source Database       : 2zhuzi
    
    Target Server Type    : MYSQL
    Target Server Version : 50709
    File Encoding         : 65001
    
    Date: 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 <?php
      2 class questionGenerator
      3 {
      4     private $itemNum = 5;
      5     private $isMulandDiv = true;
      6     private $isParentheses = true;
      7     private $isNeg = true;
      8     private $isRem = true;
      9     private $start = 0;
     10     private $end = 100;
     11     public $items = array();
     12     function __construct($itemNum, $isMulandDiv, $isParentheses, $isNeg, $isRem, $start, $end) {
     13         $this->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 "<script>alert('Calculate Error !!!');location='setattr.php';</script>";
    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 "<script>alert('Push&Pop Error !!!');location='setattr.php';</script>";
    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 "<script>alert('请登录!');location='adminlogin.html';</script>";
    }
    
    或者
    
    session_start();
    if (!isset($_SESSION['adminid']) && !isset($_SESSION['adminname'])) {
        echo "<script>alert('请登录!');location='adminlogin.html';</script>";
    }
    
    实现,简单。
    
    管理员部分对特定数据操作是在遍历中加入GET请求实现的
    
    例如:
    
    
    复制代码
    <?php
    $stmt = $pdo->prepare("select * from ansrecord");
    $stmt->execute();
    $res = $stmt->fetchAll(PDO::FETCH_ASSOC);
    ?>
    <table border="1" align="center" width="40%" >
                <tr><th>序号</th><th>用户ID</th><th>题目</th><th>最后答案</th><th>操作</th></tr>
                <tr><td></td><td></td></tr>
                <?php
                foreach ($res as $key => $value) {
                    echo "<tr><td>" . $key . "</td><td>" . $value['userid'] . "</td><td>" . $value['question'] . "</td><td>".$value['lastans']."</td><td><a href="ansrecordmangagement.php?action=DELETE&ansrecordid=".$value['ansrecordid']."" >删除记录</a></td></tr>";
                }
                $stmt = null;
                $pdo = null;
                ?>
            </table>

    从用户界面->OJ首页->OJ->题目属性设置->题目列表->提交题目和答案到数据库

    题目属性设置页面提交一个POST表单,通过PHP输入过滤器对表单内容过滤,然后将属性做参数传入questionGenerator构造函数

    $qG = new questionGenerator($itemNum, $isMulandDiv, $isParentheses, $isNeg, $isRem, $start, $end);
    $qG->generateQuest();
    $qL = $qG->getQuestionList();
    $numofqL = count($qL);

    将题目通过只读的input框 显示,答案也用表单收集,题目数量通过一个隐藏域传入表单

    <form method="post" action="submitquestandans.php"> 
            <table>
                <tr><th>题目</th><th>答案</th></tr>
                
                <?php
                echo "<tr><td colspan="2"><input type="hidden" value="".$numofqL."" name="numofqL" > </td></tr>";
                foreach ($qL as $key => $value) {
                    echo "<tr><td><input type="text" name="question".$key."" value="".$value."" readonly="true" ></td><td><input type="text" name="answer".$key."" required size="10" ></td></tr>";
                }
                ?>
                <tr><td colspan="2"><input type="submit" name="qL_submit" value="提交" ></td></tr>
            </table>
           </form>

    我的队友信1301-2班 肖兴堂

  • 相关阅读:
    Swift入门篇-Hello World
    Swift入门篇-swift简介
    Minecraft 插件 world edit 的cs 命令
    搭建本地MAVEN NEXUS 服务
    MC java 远程调试 plugin 开发
    企业内部从零开始安装docker hadoop 提纲
    javascript 命令方式 测试例子
    ca des key crt scr
    JSF 抽象和实现例子 (函数和属性)
    form 上传 html 代码
  • 原文地址:https://www.cnblogs.com/liuwei8882/p/5350128.html
Copyright © 2020-2023  润新知