万事不求人系列之-智能点餐算法实现-JavaScript实现智能点餐
作为一个成长中的架构师,编码能力是万不能停止的,这个算法是之前在上一家单位帮助同事们自助订餐写的,纯爱好自己码敲的,刚好这段时间重新整理代码,发现了它,分享给大家,请大家品评指教。
- 使用场景介绍:随着各种订餐APP的出现,找饭馆团购券,为自己订点好吃的或者团购固定人数的券都很方便,但是很多时候我们遇到的是这样的场景:知道用餐人数是几人,但是总经费或人均消费标准有限制,让你点菜,你就得一方面考虑荤素搭配,有菜有汤有主食,另一方面还得考虑经费限制;还有一种情况是就这么多总经费,人数又不确定(如之前答应去临走又有事告假的),人少可以多点几个硬菜,人多只能综合考虑,拿主食顶上。这两种场景,对点菜的人提出了很高的要求,本算法就是针对此种情况,只要给出用餐人数或固定金额,自动为你科学点菜,妈妈再也不用担心你是个点菜盲。
- 基本效果截图:

- 初始化默认参数:
var dishRate=[0.4,0.5,0.1]; // meat,vege,cold
var leastAveragePayed = 10; // Average consumption money
var defaultAveragePayed = 20; // default consumption money
var eatRiceFlag = true; // if eat rice or other things
var eatRiceRate = 8; // the rate people eat rice;
var eachRicePayed = 3; // each rice cost how much
var moneyLimit = false;
var outRangeMoney = 5; // can over money
9 var allDishArray = []; // 饭店所有的菜品基本参数有:荤蔬搭配比例、人均最少消费、默认人均消费、要米饭还是其他主食、要米饭的概率、每碗米饭的价钱、是否有总消费限制、上下浮动的空间、饭店所有的菜品(这个需要初始化,将菜品按荤蔬凉菜汤米饭等类别分开,具体代码没有贴上来,看附件里)
- 点击“开始点菜"执行的方式解释:
function execute(){
var peoples=eatPeoples.value;
var money=payMoney.value;
if("" == peoples){
resultMes.innerText = "请输入用餐人数!";
return;
}
if(!/^\d+$/.test(peoples) || (("" != money) && !/^\d+$/.test(money))){
resultMes.innerText = "输入格式不对,请重新输入!";
return;
}
if(""!=money.replace(/[\s]+/g,"")){
moneyLimit = true;
}
randomChooseDish(peoples,money);
}做了一些基本的输入有效性验证,比如人数不能为空,输入格式校验等,然后进入randomChooseDish方法开始点菜
randomChooseDish方法如下:
function randomChooseDish(peoples,money){
var tempPeoples=parseInt(peoples);
var tempSumMoney= (""==money)?tempPeoples*parseInt(defaultAveragePayed):parseInt(money);
if(!checkCondition(tempPeoples,tempSumMoney)){
return;
}
var dishNumArray= getDishNumArray(tempPeoples); //get dishNumArray var hasPayedMoney=0;
if(eatRiceFlag){
// eat rice,reduce the rice money
hasPayedMoney = eachRicePayed*tempPeoples;
} var beenChoosedArray = beginChooseDishesAndIndexs(dishNumArray); sortChoosedArray(beenChoosedArray);
// when dishes are been choosed ,should check
checkAndChangeDishes(beenChoosedArray,hasPayedMoney,tempSumMoney); // show result
showChooseResult(beenChoosedArray,hasPayedMoney,tempPeoples);
}确定人数和总金额,checkCondition做基本的条件判断,比如人数不能少于2人,总金额/人数不能低于人均最低值等;getDishNumArray用于根据人数和初始化荤素比例计算每类菜品需要点的数量;beginChooseDishesAndIndexs用于开始随机点菜;sortChoosedArray用于排序,从贵到便宜,这样对于便宜的菜可以有更多搭配的方式;checkAndChangeDishes用于对选择的菜进行金额限制检查,如果超过限制则开始从最便宜的菜调整菜,直到菜单合格;showChooseResult用于将结果显示到页面上。下面是具体每个函数的源码,有注释。
- checkCondition做基本的条件判断
function checkCondition(tempPeoples,tempSumMoney){
if(tempPeoples<2){
//alert();
resultMes.innerText = "一个人下馆子?太奢侈了.";
return false;
}
if(tempPeoples>25){
//alert();
resultMes.innerText = "人数太多,一桌坐不下!";
return false;
} if(tempSumMoney<tempPeoples*leastAveragePayed){
//alert();
resultMes.innerText ="太抠了吧,都不到人均消费10块!";
return false;
}
return true;
} - getDishNumArray用于根据人数和初始化荤素比例计算每类菜品需要点的数量
// get meat,vege,cold numArray
function getDishNumArray(tempPeoples){
var numArray=[Math.ceil(tempPeoples*dishRate[0]),getRandomRate(8)?Math.ceil(tempPeoples*dishRate[1]):Math.floor(tempPeoples*dishRate[1]),Math.round(tempPeoples*dishRate[2])]; // meat,vege,cold if(getSumArray(numArray)<=tempPeoples+1 || tempPeoples>=10){
var soupNum = Math.floor(tempPeoples/4)
numArray[numArray.length]=soupNum>2?2:soupNum; // add soup,soup num small then 2
} eatRiceFlag = getRandomRate(eatRiceRate);
if(!eatRiceFlag){
// eat others
var mainRiceNum = Math.floor(tempPeoples/3);
numArray[numArray.length]=mainRiceNum>5?5:mainRiceNum; // add rice, mainrice nums small then 5
}
return numArray;
} - beginChooseDishesAndIndexs用于开始随机点菜
function beginChooseDishesAndIndexs(dishNumArray){
var resultArray=[];
var hasChoosedDishes=[]; // save be choosed dish
var hasChoosedIndexs=[]; // save be choosed in sourceArray index
var m = getRandom(dishNumArray.length); //random pos start
var dishLength=dishNumArray.length;
for(var i=0;i<dishLength;i++){
var index = ((i+m)>=dishLength)?i+m-dishLength:(i+m);
var dishNum=dishNumArray[index];
var tempSingleChoosed = []; // temp singleType choosed array
for(var n=0;n<dishNum;n++){
var singleTypeArray = allDishArray[index];
var singleTypeIndex = getRandom(singleTypeArray.length);
//alert(tempSingleChoosed+"and"+singleTypeIndex);
while(tempSingleChoosed.length <= singleTypeArray.length && checkIfInArray(tempSingleChoosed,singleTypeIndex)){
singleTypeIndex = getRandom(singleTypeArray.length); // if now index is choosed,choose again
//alert("reGet"+singleTypeIndex);
}
if(tempSingleChoosed.length == singleTypeArray.length){
continue; // if singleTypeDish all been choosed, beak this circle,to next type dish
}
hasChoosedDishes[hasChoosedDishes.length] = singleTypeArray[singleTypeIndex]
tempSingleChoosed[tempSingleChoosed.length] = singleTypeIndex; // ramark the temp position
hasChoosedIndexs[hasChoosedIndexs.length] = index+","+singleTypeIndex; // ramark the position
}
} // all dish has choosed
resultArray.push(hasChoosedDishes);
resultArray.push(hasChoosedIndexs);
return resultArray;
} - sortChoosedArray用于排序
// when dishes been choosed ,sort it,from big to small
function sortChoosedArray(beenChoosedArray){
var hasChoosedDishes=beenChoosedArray[0]; // save be choosed dish
var hasChoosedIndexs=beenChoosedArray[1]; // save be choosed in sourceArray index
for(var i=0;i<hasChoosedDishes.length;i++){
for(var j=i;j<hasChoosedDishes.length;j++){
if(getDishAmount(hasChoosedDishes[i])>getDishAmount(hasChoosedDishes[j])){
var temp = hasChoosedDishes[i];
hasChoosedDishes[i] = hasChoosedDishes[j];
hasChoosedDishes[j] = temp;
// also should syn the choosedIndex
var temp2 = hasChoosedIndexs[i];
hasChoosedIndexs[i] = hasChoosedIndexs[j];
hasChoosedIndexs[j] = temp2;
}
}
}
//alert(hasChoosedDishes);
} - checkAndChangeDishes用于对选择的菜进行金额限制检查
// check if over money ,change less cost dish
function checkAndChangeDishes(beenChoosedArray,hasPayedMoney,tempSumMoney){
var outRange = moneyLimit?0:outRangeMoney;
while((hasPayedMoney+getSumArray(beenChoosedArray[0]))>tempSumMoney+outRange){
if(getRandomRate(8)){
changeOneToLessExpensive(beenChoosedArray);// random choose one dish then change it to less expensive
sortChoosedArray(beenChoosedArray); // reSort
}else{
removeDish(beenChoosedArray); // remove the most or least Expensive dish
}
}
} - showChooseResult用于将结果显示到页面上
// show the choose result
function showChooseResult(beenChoosedArray,hasPayedMoney,tempPeoples){
var hasChoosedDishes=beenChoosedArray[0]; // save be choosed dish
var hasChoosedIndexs=beenChoosedArray[1]; // save be choosed in sourceArray index
var tempcoldMes="凉菜:",tempVegeMes="蔬菜:",tempMeatMes="肉菜:",tempSoupMes="汤:",tempRiceMes="主食:";
for(var i in hasChoosedDishes){
var choosedIndex = hasChoosedIndexs[i];
var thisChoosedDish = hasChoosedDishes[i];
var thisDishArray = thisChoosedDish.split("@");
var allDishArrayIndex = (choosedIndex.split(","))[0];
switch (allDishArrayIndex){
case "0":tempMeatMes += thisDishArray[0]+":"+thisDishArray[1]+",";break;
case "1":tempVegeMes += thisDishArray[0]+":"+thisDishArray[1]+",";break;
case "2":tempcoldMes += thisDishArray[0]+":"+thisDishArray[1]+",";break;
case "3":tempSoupMes += thisDishArray[0]+":"+thisDishArray[1]+",";break;
case "4":tempRiceMes += thisDishArray[0]+":"+thisDishArray[1]+",";break;
default:break;
}
hasPayedMoney += parseInt(thisDishArray[1]);
}
var resultMessage="";
if(tempcoldMes.length>3){
resultMessage += tempcoldMes.slice(0,-1)+"\n\n";
}
if(tempVegeMes.length>3){
resultMessage += tempVegeMes.slice(0,-1)+"\n\n";
}
if(tempMeatMes.length>3){
resultMessage += tempMeatMes.slice(0,-1)+"\n\n";
}
if(tempSoupMes.length>2){
resultMessage += tempSoupMes.slice(0,-1)+"\n\n";
}
if(tempRiceMes.length>3){
resultMessage += tempRiceMes.slice(0,-1)+"\n\n";
}else if(eatRiceFlag){
resultMessage += "主食:"+tempPeoples+"碗米饭("+eachRicePayed+"元/碗)"+"\n\n";
}
resultMessage += "共花费"+hasPayedMoney+"元"+"\n"; resultMes.innerText = resultMessage;
}
- 初始化默认参数:
万事不求人系列之-智能点餐算法实现-JavaScript实现智能点餐的更多相关文章
- 分布式理论系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab
分布式理论系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab 本文介绍一致性算法: 2PC 到 3PC 到 Paxos 到 Raft 到 Zab 两类一致性算法(操作原 ...
- ABP(现代ASP.NET样板开发框架)系列之21、ABP展现层——Javascript函数库
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之21.ABP展现层——Javascript函数库 ABP是“ASP.NET Boilerplate Project ...
- 转载部长一篇大作:常用排序算法之JavaScript实现
转载部长一篇大作:常用排序算法之JavaScript实现 注:本文是转载实验室同门王部长的大作,找实习找工作在即,本文颇有用处!原文出处:http://www.cnblogs.com/ywang172 ...
- Visual Studio 2013开启JavaScript的智能提示功能
在前一次的发布的时候,我们共享了Visual Studio 2013中Windows Azure移动服务的集成和功能.其中包含了移动服务表脚本的编辑能力的介绍.这一次的发布,我们将描述在Visual ...
- JavaScript 排序算法(JavaScript sorting algorithms)
JavaScrip 排序算法(JavaScript Sorting Algorithms) 基础构造函数 以下几种排序算法做为方法放在构造函数里. function ArrayList () { va ...
- webpack4 系列教程(十二):处理第三方JavaScript库
教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步<webpack4 系列教程(十二):处理第三方 JavaScript 库>原文地址.或者来我的小站看更多内容:godbm ...
- 十大经典排序算法的 JavaScript 实现
计算机领域的都多少掌握一点算法知识,其中排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大 ...
- 【HANA系列】SAP HANA XS使用服务器JavaScript Libraries详解
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用服务器 ...
- .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块
.Net Core ORM选择之路,哪个才适合你 因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...
随机推荐
- $(window).load()和$(document).ready()
一.前言 我们在编写前端代码的js文件时,往往是会先写一个$(function(){}),然后才会在大括号里面继续写我们自己的代码.当时并不能理解为什么要添加这样一个东西,只是把它当做一个标签一样添加 ...
- SpringBoot01 InteliJ IDEA安装、Maven配置、创建SpringBoot项目、yml属性配置、多环境配置、自定义properties配置
1 IntelliJ IDEA 安装 下载地址:点击前往 注意:需要下载专业版本的,注册码在网上随便搜一个就行啦 2 MAVEN工具的安装 2.1 获取安装包 下载地址:点击前往 2.2 安装过程 到 ...
- Linux cloc
一.简介 cloc是一个基于perl的.十分好用的代码统计工具,它所支持的语言还算十分丰富.不过,还是有很多用的较少的语言是不支持的. 二.安装配置 1)官网安装教程 http://cloc.so ...
- Part2_lesson4---ARM寻址方式
所谓寻址方式就是处理器根据指令中给出的信息来找到指令所需操作数的方式. 1.立即数寻址 ADD R0,R0,#0x3f; R0<-R0+0x3f 在以上指令中,第二个源操作数即为立即数,要求以“ ...
- SpringMVC 2.5.6 +Hibernate 3.2.0
spring MVC配置详解 现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时 ...
- JavaScript 算法应用: 遍历DOM树的两种方式
1 常见的DOM树结构: 2 DOM数遍历有两种方式: 3 广度优先代码: 4 深度优先遍历代码
- overflow 在ie7下失效
问题原因: 当父元素的后代元素的样式拥有position:relative属性时,父元素的overflow:hidden属性就会失效. 解决方法: 在父元素中使用position:relative;即 ...
- 保证Service不被Kill的解决方案
1.Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样 2.通过 startForegroun ...
- 一、Numpy基础--数组
(一)Numpy数组对象 Numpy中的nadrray是一个多维数组对象,该对象由两部分组成: 实际的数据 描述这些数据的元数据 大部分的数组操作仅仅修改元数据部分,而不改变底层的实际数据. 数组的数 ...
- 【小梅哥FPGA进阶教程】第十二章 数字密码锁设计
十二.数字密码锁设计 本文由山东大学研友袁卓贡献,特此感谢 实验目的 实现数字密码锁设计,要求矩阵按键输出且数码管显示输入密码,密码输入正确与否均会有相应标志信号产生. 实验平台 芯航线FPGA核心板 ...