get(array('type_id' => $type_id,'bonus_status' => 0,'bonus_value' => array('gt',$min_amount))); if(!empty($items)) { $total_num = $this->weight_num($strength,count($items)); $total_amount = 0; $index = 0; $selitems = array(); foreach ($items as $bonus) { $total_amount += intval($bonus['bonus_value'] * 100 + 0.5); array_push($selitems,$bonus); if(++$index >= $total_num) { break; } } $total_amount = doubleval($total_amount / 100); $ret = $this->separate($bonus_val,$total_amount,$total_num,$direction,$strength); if($ret == true) { $type = type::create_by_id($type_id); $type_max_value = $type->max_amount(); $alloc = new allocator(); $moneys = $alloc->separate_money(self::min_amount,$total_amount,$total_num,$min_val,$max_val); $ret = $mod_bonus->where(array('type_id' => $type_id,'bonus_id' => $bonus_id))->update(array('bonus_value' => $bonus_val)); if($ret == false || $mod_bonus->affected_rows() <= 0) { throw new Exception(); } $index = 0; $max_value = 0.00; foreach ($selitems as &$item) { $item['bonus_value'] = $moneys[$index]; $item['remain_amount'] = $moneys[$index]; $max_value = $this->max($max_val,$item['bonus_value']); ++$index; } $max_value = $this->max($type_max_value,$max_value); $remain_change = $bonus_val - $bonus_valin; if($bonus_status === 2) { $data[] = array('max_amount' => $max_value,'remain_amount' => array('exp', "remain_amount-{$remain_change}")); Model('bonus_type')->edit(array('type_id' => $type_id),$data); } else { if($this->equal($type_max_value,$max_value) == false) { Model('bonus_type')->edit(array('type_id' => $type_id),array('max_amount' => $max_value)); } } $ret = $mod_bonus->insertAll($selitems,array(),true); if($ret == false && $mod_bonus->affected_rows() <= 0) { throw new Exception(); } } } $trans->commit(); $bonus_valin = $bonus_val; return true; } catch (Exception $ex) { $trans->rollback(); return false; } } private function equal($left,$right) { $left = intval($left * 100 + 0.5); $right = intval($right * 100 + 0.5); return ($left == $right); } private function max($left,$right) { $left = intval($left * 100 + 0.5); $right = intval($right * 100 + 0.5); return $left > $right ? $left / 100 : $right / 100; } private function delta_asc($total,$num,$strength) { if($strength == 5) { $mul = 2; } elseif ($strength == 4) { $mul = 1.6; } elseif ($strength == 3) { $mul = 1.2; } elseif ($strength == 2) { $mul = 0.8; } elseif ($strength == 1) { $mul = 0.4; } else { return 0; } $avg = doubleval($total / $num); $avg = intval($avg * $mul + 0.5); return mt_rand(0,$avg); } private function delta_dec($total,$strength) { if($strength == 5) { $mul = 1; } elseif ($strength == 4) { $mul = 0.8; } elseif ($strength == 3) { $mul = 0.6; } elseif ($strength == 2) { $mul = 0.4; } elseif ($strength == 1) { $mul = 0.2; } else { return 0; } $avg = intval($total * $mul + 0.5); return mt_rand(0,$avg); } private function weight_num($strength,$total_num) { if($strength == 0) { $strength = 1; } $weight = intval(doubleval($total_num / self::max_strength) * $strength + 0.5); return ($weight > $total_num) ? $total_num : $weight; } private function separate(&$bonus_out,&$total_amount,$total_num,$direction,$strength) { $total_tmp = intval($total_amount * 100 + 0.5); $bonus_val = intval($bonus_out * 100 + 0.5); $min_amount = 1; $base_amount = $min_amount * $total_num; if($base_amount == $total_tmp) { return false; } if($direction == self::direct_asc) { //金额变大 $delta = $this->delta_asc($total_tmp - $base_amount,$total_num + 1, $strength); $bonus_val += $delta; $total_tmp = $total_tmp - $delta; } else { //金额变小 $delta = $this->delta_dec($bonus_val - self::min_amount, $strength); $bonus_val = $bonus_val - $delta + self::min_amount; $total_tmp = $total_tmp + $delta; } $total_amount = $total_tmp / 100; $bonus_out = $bonus_val / 100; return true; } }