您的位置:首页 > 其它

四则运算4(完结)

2016-04-02 12:26 281 查看
终于熬出头了

php版的四则运算出炉了

由于c++代码转php代码有个BUG调不出来,在经历了10+个小时的努力,换了n+个环境了,终于也没把php断点调试环境搭起来,

所以,就当这是个阉割版的四则运算吧。。。。

首先,环境:

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 什么什么的环境弄不起来,所以在线判断这部分功能就阉了。。 其实写好了调了好久调不对。。

贴一下核心代码,嘿嘿嘿

<?php
class questionGenerator
{
private $itemNum = 5;
private $isMulandDiv = true;
private $isParentheses = true;
private $isNeg = true;
private $isRem = true;
private $start = 0;
private $end = 100;
public $items = array();
function __construct($itemNum, $isMulandDiv, $isParentheses, $isNeg, $isRem, $start, $end) {
$this->itemNum = $itemNum;
$this->isMulandDiv = $isMulandDiv;
$this->isParentheses = $isParentheses;
$this->isNeg = $isNeg;
$this->isRem = $isRem;
$this->start = $start;
$this->end = $end;
}

function isTrueFraction($numerator,$denominator){   //判断产生的分数是否是真分数
if($numerator >= $denominator){
return false;
}
for($i = 2; $i <= $numerator;$i++){               //判断分数是否能够约分
if(($numerator % $i == 0)&&($denominator % $i == 0)){
return false;
}
}
return true;
}

function getNum($start = 0, $end = 100,$isParentheses = false,$depth = 0){    // 若带括号 则为 a op ( b op c ) 的形式 op为运算符
if($isParentheses){
$num1 = mt_rand($start,$end);
if($depth < 2){         //控制递归层数,带括号的式子少于10个
$num2 = "( " . $this->getNum($start,$end,mt_rand() % 2 == 0,$depth + 1) . " )";
return strval($num1) . " , " . $num2;
}else{
$num2 = "( " . $this->getNum($start,$end,false,$depth + 1) . " )";
return strval($num1) . " , " . $num2;
}
}else{
if(mt_rand() % 7 == 0){      //若随机数n是7的倍数,产生一个真分数和一个整数,否则为两个整数
$num1 = mt_rand($start,$end);
$num2 = mt_rand($start,$end);
$num3 = mt_rand($start,$end);
if($this->isTrueFraction($num1,$num2)){
return strval($num1) . "/" . strval($num2) . " , " . strval($num3);
}else{
return $this->getNum($start,$end);
}
}else{
$num1 = mt_rand($start,$end);
$num2 = mt_rand($start,$end);
return strval($num1) . " , " . strval($num2);
}
}
}

function getOperator($num2 = '1',$isMulandDiv = true){     // 默认第二个参数不为0,默认包括乘除法
$op = array('+','-','*','/');
if($isMulandDiv){
if($num2 == '0'){    //避免除数为0
return $op[mt_rand() % 3];
}else{
return $op[mt_rand() % 4];
}
}else{
return $op[mt_rand() % 2];
}
}

function isNegative($num1, $num2, $op){
if($op == '-'){
if(intval($num1) < intval($num2)){
return true;
}else{
return false;
}
}else{
if(intval($num1) + intval($num2) < 0){
return true;
}else{
return false;
}
}
}

function isRemainder($num1, $num2){
if(intval($num1) % intval($num2) == 0){
return false;
}else{
return true;
}
}

function generateQuest(){
$addFlag = false;
$one = 1;
while (count($this->items) < $this->itemNum){
$num = $this->getNum($this->start,$this->end,$this->isParentheses);
while (strpos($num,",")){
$addFlag = true;
if(substr($num,intval(strpos($num,",")) + 2,1) == '('){   //运算符后紧跟括号,运算符选取只和isMulandDiv有关
$op = $this->getOperator('1',$this->isMulandDiv);
$num = str_replace(",",$op,$num,$one);
}else{           //运算符后是数字,运算符选取和num2和isMulandDiv有关,此时是不带括号或最右边的算式
$num2 = substr($num, intval(strrpos($num,",")) + 2, intval(strpos($num,")")) - intval(strrpos($num,",")) - 3);
$op = $this->getOperator($num2,$this->isMulandDiv);
$num = str_replace(",", $op, $num, $one);
$begin = 0;        //找到形如 a op b 的式子
if(strpos($num, "(")){     //如果式子里有()的话
$begin = intval(strrpos($num, "(")) + 2;
}
$num1 = substr($num, $begin, intval(strrpos($num, $op)) - $begin - 1);
if( $op == '-' || $op == '+')
{
if(!$this->isNeg && $this->isNegative($num1, $num2, $op))
{
$addFlag = FALSE;
break;
}
}elseif ($op == '/') {
if(!$this->isRem && $this->isRemainder($num1, $num2)){
$addFlag = FALSE;
break;
}
}
}
}
if(!$addFlag){    //满足要求,可以添加
continue;
}
if(!in_array($num, $this->items)){   //判断是否重复,不重复则添加
array_push($this->items, $num);
}
}
}

function calculate($num1,$num2,$op){
switch ($op){
case "+":
return $num1 + $num2;
break;
case "-":
return $num1 - $num2;
break;
case  "*":
return $num1 * $num2;
break;
case "/":
return $num1 / $num2;
break;
default :
echo "<script>alert('Calculate Error !!!');location='setattr.php';</script>";
}
}

function getResult(){
$pri = array(
'+' => array('+' => '>', '-' => '>', '*' => '<', '/' => '<', '(' => '<', ')' => '>', '#' => '>'),
'-' => array('+' => '>', '-' => '>', '*' => '<', '/' => '<', '(' => '<', ')' => '>', '#' => '>'),
'*' => array('+' => '>', '-' => '>', '*' => '>', '/' => '>', '(' => '<', ')' => '>', '#' => '>'),
'/' => array('+' => '>', '-' => '>', '*' => '>', '/' => '>', '(' => '<', ')' => '>', '#' => '>'),
'(' => array('+' => '<', '-' => '<', '*' => '<', '/' => '<', '(' => '<', ')' => '=', '#' => ''),
')' => array('+' => '>', '-' => '>', '*' => '>', '/' => '>', '(' => '', ')' => '>', '#' => '>'),
'#' => array('+' => '<', '-' => '<', '*' => '<', '/' => '<', '(' => '<', ')' => '', '#' => '=')
);
$ansL = array();
foreach ($this->items as $exp){
$stackOps = array();
$stackNums = array();
array_push($stackOps,"#");
$exp = $exp . " #";
$flag = -1;
while (!(substr($exp,$flag + 1,1) == "#" && end($stackOps) == "#")){
$str = substr($exp, $flag + 1, strpos($exp, " ", $flag + 1) - $flag -1);
if(!in_array($str,array("+","-","*","/","(",")","#"))){
if(strpos($str,"/")){
$numerator = substr($str,0,strpos($str,"/"));
$denominator = substr($str,strpos($str,"/") + 1);
array_push($stackNums,floatval($numerator)/floatval($denominator));
$flag = strpos($exp," ",$flag + 1);
}  else {
array_push($stackNums,floatval($str));
$flag = strpos($exp," ",$flag + 1);
}
}  else {
if($pri[end($stackOps)][$str] == "<"){
array_push($stackOps,$str);
$flag = strpos($exp," ",$flag + 1);
}elseif ($pri[end($stackOps)][$str] == ">") {
$op = end($stackOps);
array_pop($stackOps);
$num2 = end($stackNums);
array_pop($stackNums);
$num1 = end($stackNums);
array_pop($stackNums);
array_push($stackNums, $this->calculate($num1, $num2, $op));
}elseif ($pri[end($stackOps)][$str] == "=") {
array_pop($stackOps);
$flag = strpos($exp," ",$flag + 1);
}  else {
echo "<script>alert('Push&Pop Error !!!');location='setattr.php';</script>";
}
}
}
array_push($ansL, end($stackNums));
}
return $ansL;
}

function getQuestionList(){
return $this->items;
}

}


基本思路和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>


第一次用php做,边做边学,如有错误,感谢指出。

我的队友 信1301-1 刘伟

1.系统首页



2.用户登录



3.用户首页



4.答题设置页面



5.开始答题



6.浏览答题记录



7.管理员登陆界面



8.管理员首页



9.用户管理列表



10.用户答题记录:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: