摩尔斯电码的训练器

513 阅读2分钟

最近有一个课程设计的作业

要求如下:

用一个按键(例如空格键),代表电报按键;

给出一系列字母,让用户进行电报按键练习,给出节奏错误信息、拼写错误信息等。

因此处不限制使用何种语言,则采用了html+js来实现

如何判断按键的节奏?

此处我根据按键的快慢来判断是节奏是快的还是慢的。因此需要计算按下按键和抬起按键的耗时。

此处会遇到一个问题是,持续的按键会被识别为多次按键。因此需要加一个判断以排除持续按键的问题。

// 定义需要计算时间的参数
let keyupTime = 0,
    keydownTime = 0,
    keydownCount = 0;
//定义keycode是32的控制是否按起
let is32Up = false;

// 监听键盘按下的事件
$(document).keydown(function(event) {
    // 输出对应的keycode 
    console.log('keydown event..' + event.keyCode);
    // 是否为空格
    if (event.keyCode == 32) {
        // 用于判断是否首次按下,用于排除连续按键的情况
        keydownCount++;
        if (keydownCount == 1) { // 首次按下
            keydownTime = new Date().getTime();
            console.log('keydownTime:' + keydownTime);
        }
        if (!is32Up) // 按键未抬起
            return;
        is32Up = false;
    }
});
// 监听键盘被抬起的事件
$(document).keyup(function(event) {
    console.log('keyup event..' + event.keyCode);
    if (event.keyCode == 32) {
        keyupTime = new Date().getTime();
        console.log('keyupTime:' + keyupTime);
        if (keyupTime != 0 && keydownTime != 0) {
            let spanTime = keyupTime - keydownTime;
            console.log('spanTime:' + spanTime);
            checkSpanTime(spanTime);
            keyupTime = 0, keydownTime = 0, keydownCount = 0;
            is32Up = false; // 重置
        }
    }
});

如何用数据存储摩尔斯电码表?

此处使用的是map, 用01的数组来表示长短节奏的电码。

 // 定义密码表
const MOSTABLE = {
    'A': [0, 1],
    'B': [1, 0, 0, 0],
    'C': [1, 0, 1, 0],
    'D': [1, 0, 0],
    'E': [0],
    'F': [0, 0, 1, 0],
    'G': [1, 1, 0],
    'H': [0, 0, 0, 0],
    'I': [0, 0],
    'J': [0, 1, 1, 1],
    'K': [1, 0, 1],
    'L': [0, 1, 0, 0],
    'M': [1, 1],
    'N': [1, 0],
    'O': [1, 1, 1],
    'P': [0, 1, 1, 0],
    'Q': [1, 1, 0, 1],
    'R': [0, 1, 0],
    'S': [0, 0, 0],
    'T': [1],
    'U': [0, 0, 1],
    'V': [0, 0, 0, 1],
    'W': [0, 1, 1],
    'X': [1, 0, 0, 1],
    'Y': [0, 1, 0, 0],
    'Z': [1, 1, 0, 0],
    '1': [0, 1, 1, 1, 1],
    '2': [0, 0, 1, 1, 1],
    '3': [0, 0, 0, 1, 1],
    '4': [0, 0, 0, 0, 1],
    '5': [0, 0, 0, 0, 0],
    '6': [1, 0, 0, 0, 0],
    '7': [1, 1, 0, 0, 0],
    '8': [1, 1, 1, 0, 0],
    '9': [1, 1, 1, 1, 0],
    '0': [1, 1, 1, 1, 1, 1],
    '?': [0, 0, 1, 1, 0, 0],
    '/': [1, 0, 0, 1, 0],
    '()': [1, 0, 1, 1, 0, 1],
    '——': [1, 0, 0, 0, 0, 1],
    '.': [0, 1, 0, 1, 0, 1]
};

随机生成待训练的字母?

// 随机生成待训练的字母
const alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '?', '/', '()', '——', '.'];
// 设置训练的个数
let num = 10;
// 存放随机训练的字符,用char类型的数组
let randomTrainTable = [];
for (let index = 0; index < num; index++) {
let idx = Math.round(Math.random() * 40);
randomTrainTable.push(alphabets[idx]);
$('.alphabet-area').append('<label title="' + getCharsFromTable(alphabets[idx]) + '">' + alphabets[idx] + '</label>');
}

整个逻辑较简单就直接贴代码了↓↓↓↓

<!DOCTYPE html>
<html>

<head>
    <title>摩尔斯电码训练</title>
    <style>
        .area {
            padding: 20px 20px;
            margin: 20px 20px;
            border-bottom: 1px solid lightblue;
        }
        
        .key-area label {
            color: grey;
            font-size: 30px;
        }
        
        .alphabet-area label {
            margin: 10px 10px;
            font-size: 50px;
        }
    </style>
</head>

<body style="text-align: center;">
    <h1>摩尔斯电码训练</h1>
    <div class="area alphabet-area" id="alphabet-area">
        <h2>待训练的随机字符(鼠标移到字母上可查看提示,单位正确得分为10,红色为错误,绿色为正确)</h2>

    </div>
    <h2>请按空格↓↓↓您的输入↓↓↓</h2>
    <div class="area key-area" id="key-area">

    </div>
    <h3>你的输入↓↓↓结果如下↓↓↓</h3>
    <div class="area result-area" id="result-area">
    </div>
</body>

<!-- <script src="./jquery.min.js"></script> -->
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

<script>
    $(function() {

        // 定义密码表
        const MOSTABLE = {
            'A': [0, 1],
            'B': [1, 0, 0, 0],
            'C': [1, 0, 1, 0],
            'D': [1, 0, 0],
            'E': [0],
            'F': [0, 0, 1, 0],
            'G': [1, 1, 0],
            'H': [0, 0, 0, 0],
            'I': [0, 0],
            'J': [0, 1, 1, 1],
            'K': [1, 0, 1],
            'L': [0, 1, 0, 0],
            'M': [1, 1],
            'N': [1, 0],
            'O': [1, 1, 1],
            'P': [0, 1, 1, 0],
            'Q': [1, 1, 0, 1],
            'R': [0, 1, 0],
            'S': [0, 0, 0],
            'T': [1],
            'U': [0, 0, 1],
            'V': [0, 0, 0, 1],
            'W': [0, 1, 1],
            'X': [1, 0, 0, 1],
            'Y': [0, 1, 0, 0],
            'Z': [1, 1, 0, 0],
            '1': [0, 1, 1, 1, 1],
            '2': [0, 0, 1, 1, 1],
            '3': [0, 0, 0, 1, 1],
            '4': [0, 0, 0, 0, 1],
            '5': [0, 0, 0, 0, 0],
            '6': [1, 0, 0, 0, 0],
            '7': [1, 1, 0, 0, 0],
            '8': [1, 1, 1, 0, 0],
            '9': [1, 1, 1, 1, 0],
            '0': [1, 1, 1, 1, 1, 1],
            '?': [0, 0, 1, 1, 0, 0],
            '/': [1, 0, 0, 1, 0],
            '()': [1, 0, 1, 1, 0, 1],
            '——': [1, 0, 0, 0, 0, 1],
            '.': [0, 1, 0, 1, 0, 1]
        };

        // 从密码表中,将01转为.-  用于提示
        function getCharsFromTable(c) {
            return getCharsFromKeyArr(MOSTABLE[c]);
        }

        // 参数为01的数组  , 转换为.-的字符串
        function getCharsFromKeyArr(a) {
            let r = '';
            for (let i = 0; i < a.length; i++) {
                if (a[i] == 0)
                    r += '.';
                else if (a[i] == 1)
                    r += '-';
            }
            return r;
        }

        // 输出结果
        function showResult(ch, rightAnswer, userAnswer, right, curIdx) {
            $('.result-area').append("<p style='color:" +
                (right ? "green" : "red") + "'>字符:" + ch + " 应输入:" + getCharsFromTable(ch) + " 你的输入:" + userAnswer +
                " 是否正确:" + (right ? '√' : 'x') + " 得分: " + (right ? '10' : '0') + " </p>");
            let sel = "#alphabet-area > label:nth-child(" + (curIdx + 2) + ")";
            if (right) {
                $(sel).css("color", "green");
            } else {
                $(sel).css("color", "red");
            }
            curIndex++;
            // 清空
            curKeyArr = [];
            $("#key-area").empty();
        }

        // 随机生成待训练的字母
        const alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '?', '/', '()', '——', '.'];
        // 设置训练的个数
        let num = 10;
        // 存放随机训练的字符,用char类型的数组
        let randomTrainTable = [];
        for (let index = 0; index < num; index++) {
            let idx = Math.round(Math.random() * 40);
            randomTrainTable.push(alphabets[idx]);
            $('.alphabet-area').append('<label title="' + getCharsFromTable(alphabets[idx]) + '">' + alphabets[idx] + '</label>');
        }

        // 定义当前在训练的字符序号
        let curIndex = 0;
        // 存当前的输入 0 or 1 
        let curKeyArr = [];
        // 计算得分
        let score = 0;

        // 处理按键时长对应的事件
        function checkSpanTime(spanTime) {

            if (curIndex < num) {
                // 当前的字符
                let curChar = randomTrainTable[curIndex];
                // 当前字符的摩斯密码
                let curCharArr = MOSTABLE[curChar];

                console.log("curChar:", curChar, " curCharArr:", curCharArr);
                if (spanTime < 120) {
                    curKeyArr.push(0);
                    $(".key-area").append("<label class='key-short'>.</label>");
                } else {
                    curKeyArr.push(1);
                    $(".key-area").append("<label class='key-long'>-</label>");
                }
                // 密码长度
                let n = curCharArr.length;
                console.log("n", n, "curKeyArr:", curKeyArr.length, 'curKeyArr', curKeyArr);
                if (curKeyArr.length == n) {
                    // 长度相同的情况下,判断密码是否正确
                    let isRight = true;
                    for (let i = 0; i < n; i++) {
                        if (curKeyArr[i] != curCharArr[i]) {
                            isRight = false;
                            break;
                        }
                    }
                    console.log('isRight:', isRight, 'curIndex:', curIndex);
                    // 当前字符输入的摩斯密码正确
                    if (isRight) {
                        score += 10;
                        // 输出到结果面板
                        showResult(curChar, getCharsFromTable(curChar), getCharsFromKeyArr(curKeyArr), true, curIndex);
                    } else {
                        //TODO 输出错误信息
                        alert('你的输入有误,正确答案为:' + getCharsFromTable(curChar));
                        showResult(curChar, getCharsFromTable(curChar), getCharsFromKeyArr(curKeyArr), false, curIndex);
                    }

                } else {
                    // TODO 判断当前输入是否正确
                    for (let i = 0; i < curKeyArr.length; i++) {
                        if (curKeyArr[i] != curCharArr[i]) {
                            //输出错误
                            alert('当前输入输入有误,当前应输入:   ' + (curCharArr[i] == 0 ? '节奏应短些 . ' : '节奏应长些 - ') + ', 完整答案为: ' + getCharsFromTable(curChar));
                            showResult(curChar, getCharsFromTable(curChar), getCharsFromKeyArr(curKeyArr), false, curIndex);
                            break;
                        }
                    }
                }
            } else {
                //完成本次训练
                alert('恭喜你已完成本次训练,本次得分:' + score);
                window.location.reload();
            }


        }

        // 定义需要计算时间的参数
        let keyupTime = 0,
            keydownTime = 0,
            keydownCount = 0;
        //定义keycode是32的控制是否按起
        let is32Up = false;

        // 监听键盘按下的事件
        $(document).keydown(function(event) {
            // 输出对应的keycode 
            console.log('keydown event..' + event.keyCode);
            // 是否为空格
            if (event.keyCode == 32) {
                // 用于判断是否首次按下,用于排除连续按键的情况
                keydownCount++;
                if (keydownCount == 1) { // 首次按下
                    keydownTime = new Date().getTime();
                    console.log('keydownTime:' + keydownTime);
                }
                if (!is32Up) // 按键未抬起
                    return;
                is32Up = false;
            }
        });
        // 监听键盘被抬起的事件
        $(document).keyup(function(event) {
            console.log('keyup event..' + event.keyCode);
            if (event.keyCode == 32) {
                keyupTime = new Date().getTime();
                console.log('keyupTime:' + keyupTime);
                if (keyupTime != 0 && keydownTime != 0) {
                    let spanTime = keyupTime - keydownTime;
                    console.log('spanTime:' + spanTime);
                    checkSpanTime(spanTime);
                    keyupTime = 0, keydownTime = 0, keydownCount = 0;
                    is32Up = false; // 重置
                }
            }
        });
    });
</script>

</html>

效果如下: