javascript - 单词搜索游戏。如何搜索网格并突出显示结果?

标签 javascript frontend wordsearch

我是编程新手,没有 JavaScript 经验,而且我有一项作业要为学校完成。我需要创建一个单词搜索游戏,它有一个表单/按钮搜索,可以查找单词并在网格中突出显示它。我已经创建了 HTML/CSS 布局,但我无法将其链接到 JavaScript。我希望能够搜索“BANGKOK”、“LONDON”、“SINGAPORE”、“HAVANA”和“KYOTO”等词,但我只能搜索/突出显示网格中的一个字母/单元格,而且我不知道我不知道如何用网格中的字母组成一个字符串,这样我就可以找到这些单词。我被困在这里了。真的很想理解。有人可以帮助我/指导/向我解释它是如何工作的吗?我读了很多东西,但似乎找不到我要找的东西。我真的很感激。 我还需要突出显示的单词在找到时保持突出显示。

这是我到目前为止所拥有的:https://jsfiddle.net/fwg8hequ/10/

function search() {
  var text = document.getElementById("query").value;
  var query = new RegExp("(\\b" + text + "\\b)", "gim");
  var e = document.getElementById("searchtext").innerHTML;
  var enew = e.replace(/(<span>|<\/span>)/igm, "");
  document.getElementById("searchtext").innerHTML = enew;
  var newe = enew.replace(query, "<span>$1</span>");
  document.getElementById("searchtext").innerHTML = newe;

}
@charset "UTF-8";

/* CSS Document */

@font-face {
  font-family: 'RobotoSlab';
  src: url('RobotoSlab-bold.ttf');
}

@font-face {
  font-family: 'RobotoMono';
  src: url('RobotoMono-Regular.ttf');
}

.container {
  position: relative;
  width: 1000px;
  height: 800px;
  background: #ffcc78;
}

.header {
  position: absolute;
  left: 24.7%;
  right: 26%;
  top: 5.25%;
  bottom: 86.75%;
  overflow: auto;
}

.header img {
  width: 58px;
  height: 58px;
  left: 247px;
  top: 46px;
  float: left;
}

.header h1 {
  left: 33.8%;
  right: 28.4%;
  width: 378px;
  height: 64px;
  font-family: RobotoSlab;
  font-style: normal;
  line-height: normal;
  font-size: 48px;
  letter-spacing: -1px;
  color: #E25C5C;
  line-height: 5.28%;
  float: right;
}

form {
  position: absolute;
  left: 24.7%;
  right: 26%;
  top: 18.75%;
  bottom: 75%;
}

input[type=text] {
  float: left;
  left: 24.7%;
  right: 35.8%;
  top: 18.75%;
  bottom: 75%;
  width: 410px;
  height: 50px;
  background: #FFFFFF;
  border: 1px solid #417505;
  box-sizing: border-box;
  border-radius: 5px;
}

button {
  position: absolute;
  left: 66.5%;
  right: 27.3%;
  top: 18.75%;
  bottom: 75%;
  background: linear-gradient(180deg, #76AD0C 0%, #417505 100%);
  border-radius: 5px;
  font-family: RobotoSlab;
  font-style: normal;
  line-height: normal;
  font-size: 15px;
  color: #FFFFFF;
  float: right;
}

.grid-container {
  display: grid;
  grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
  background-color: #E25C5C;
  position: absolute;
  left: 24.7%;
  right: 26%;
  top: 30.5%;
  bottom: 7.88%;
  padding: 2px;
  border-radius: 5px;
}

.grid-item {
  background-color: #ffcc78;
  border: 2px solid #E25C5C;
  left: 26.2%;
  right: 27.2%;
  font-family: RobotoMono;
  line-height: 36px;
  font-size: 36px;
  letter-spacing: 2.9px;
  font-style: normal;
  font-weight: normal;
  text-align: center;
  padding: 2px;
}

#searchtext span {
  background-color: #F5A623;
}
<div class="container">

  <div class="header">
    <img src="icon.png" alt="Icon" height="58" width="58">

    <h1>WORD SEARCH</h1>

  </div>



  <form>
    <input name="query" id="query" type="text">
  </form>
  <button type="button" onClick="search();">SEARCH</button>



  <div class="grid-container" id="searchtext">

    <div class="grid-item">W</div>
    <div class="grid-item">S</div>
    <div class="grid-item">I</div>
    <div class="grid-item">A</div>
    <div class="grid-item">L</div>
    <div class="grid-item">C</div>
    <div class="grid-item">E</div>
    <div class="grid-item">O</div>
    <div class="grid-item">I</div>
    <div class="grid-item">V</div>

    <div class="grid-item">V</div>
    <div class="grid-item">A</div>
    <div class="grid-item">L</div>

    <div class="grid-item">B</div>
    <div class="grid-item">A</div>
    <div class="grid-item">N</div>
    <div class="grid-item">G</div>
    <div class="grid-item">K</div>
    <div class="grid-item">O</div>
    <div class="grid-item">K</div>


    <div class="grid-item">U</div>

    <div class="grid-item">T</div>
    <div class="grid-item">L</div>
    <div class="grid-item">O</div>
    <div class="grid-item">N</div>
    <div class="grid-item">D</div>
    <div class="grid-item">O</div>
    <div class="grid-item">N</div>
    <div class="grid-item">O</div>
    <div class="grid-item">I</div>


    <div class="grid-item">U</div>

    <div class="grid-item">S</div>
    <div class="grid-item">I</div>
    <div class="grid-item">N</div>
    <div class="grid-item">G</div>
    <div class="grid-item">A</div>
    <div class="grid-item">P</div>
    <div class="grid-item">O</div>
    <div class="grid-item">R</div>
    <div class="grid-item">E</div>


    <div class="grid-item">A</div>
    <div class="grid-item">L</div>
    <div class="grid-item">C</div>
    <div class="grid-item">O</div>
    <div class="grid-item">G</div>
    <div class="grid-item">E</div>
    <div class="grid-item">E</div>
    <div class="grid-item">U</div>
    <div class="grid-item">V</div>
    <div class="grid-item">R</div>

    <div class="grid-item">H</div>
    <div class="grid-item">A</div>
    <div class="grid-item">V</div>
    <div class="grid-item">A</div>
    <div class="grid-item">N</div>
    <div class="grid-item">A</div>
    <div class="grid-item">T</div>
    <div class="grid-item">L</div>
    <div class="grid-item">A</div>
    <div class="grid-item">A</div>

    <div class="grid-item">A</div>
    <div class="grid-item">B</div>
    <div class="grid-item">I</div>
    <div class="grid-item">S</div>
    <div class="grid-item">S</div>
    <div class="grid-item">N</div>
    <div class="grid-item">O</div>
    <div class="grid-item">R</div>
    <div class="grid-item">I</div>
    <div class="grid-item">S</div>

    <div class="grid-item">N</div>
    <div class="grid-item">K</div>
    <div class="grid-item">Y</div>
    <div class="grid-item">O</div>
    <div class="grid-item">T</div>
    <div class="grid-item">O</div>
    <div class="grid-item">A</div>
    <div class="grid-item">H</div>
    <div class="grid-item">B</div>
    <div class="grid-item">E</div>

    <div class="grid-item">Z</div>
    <div class="grid-item">M</div>
    <div class="grid-item">P</div>
    <div class="grid-item">T</div>
    <div class="grid-item">R</div>
    <div class="grid-item">E</div>
    <div class="grid-item">S</div>
    <div class="grid-item">J</div>
    <div class="grid-item">R</div>
    <div class="grid-item">L</div>

    <div class="grid-item">F</div>
    <div class="grid-item">P</div>
    <div class="grid-item">E</div>
    <div class="grid-item">K</div>
    <div class="grid-item">T</div>
    <div class="grid-item">A</div>
    <div class="grid-item">M</div>
    <div class="grid-item">L</div>
    <div class="grid-item">O</div>
    <div class="grid-item">J</div>


  </div>






</div>

最佳答案

让我们尝试分解一下您的搜索功能的作用:

 function search() {
    // get the searched text OK
    var text = document.getElementById("query").value;

    // make a regexp out of the searched text OK
    var query = new RegExp("(\\b" + text + "\\b)", "gim");

    // retrieve the html content of the grid items's container OK
    var e = document.getElementById("searchtext").innerHTML;

    // remove all the spans tags from this html content (span tags in #searchtext are red)
    var enew = e.replace(/(<span>|<\/span>)/igm, "");

    // set the html stripped from the span tags as the content of #searchtext
    document.getElementById("searchtext").innerHTML = enew;

    // in the html stripped from span, wrap with spans all contents matching the search string
    var newe = enew.replace(query, "<span>$1</span>");

    // set the final html as the content of #searchtext
    document.getElementById("searchtext").innerHTML = newe;

}

首先,您要提取 html 代码并尝试在此 html 代码中查找文本。 但由于您保留了大部分标签(仅删除了 span),因此您将无法仅在 div 内容中找到文本(您的搜索将被 div 标签本身污染)。

我们可以用替换来做复杂的事情,但必须有另一种方法。

现在让我们分解一下当前的问题: 我们想编写一个函数,根据搜索文字游戏的规则(水平、垂直对 Angular 线)在网格中突出显示搜索的单词。

`function highlightSearchedWord() {....}`

没有内置的 JavaScript 函数可以做到这一点,因此我们必须分解问题。

function highlightSearchedWord() {
    var text = getSearchedWord();
    highlightText(text);
}

我们可以解决 getSearchedWord:

function getSearchedWord() {
    var text = document.getElementById("query").value;
    return text;
}

现在在highlightText中我们需要找到一个单词,即能够读取网格中给定位置的字母,将它们与搜索到的文本进行比较,如果找到该单词则保留位置列表并突出显示这些位置。

网格中的位置可以看作坐标x(字母的列索引)和y(字母的行索引)。

在 javascript 中,我们可以使用大括号 {} 定义结构化对象,因此位置 0,0(网格第一行的第一个字母)将是 { x: 0, y: 0}

网格的第一个字母位于网格的第一个 div (.grid-item) 中。 Javascript 为您提供了根据类名检索元素的方法。

`document.getElementsByClassName()`

Documentation of getElementsByClassName

因此,我们可以通过编写 var items= document.getElementsByClassName('grid-item'); 来列出所有网格元素

让我们定义函数getItems:

function getItems() {
    var items= document.getElementsByClassName('grid-item');
    return items;
}

由此我们可以轻松推导出一个新函数:

function getLetterAtPos(pos) {
    var items = getItems();
    // items is an array so we have to convert position {x, y} to index
    return items[posToIndex(pos)].innerHTML;
}

其中 posToIndex 为:

function posToIndex(pos) {
    // if the grid is 10x10 the first element of first row is index 0 (0 * 10 + 0)
    // !remember first indice is 0!
    // the first item of second row is index 10 (1 * 10 + 0)
    // the second item of the third row is index 21 (1 * 10 + 1)
    return pos.y * 10 + pos.x;
}

我会加快速度以限制答案的大小,但评论应该会有所帮助。

突出显示位置的方法也可能有所帮助:

首先定义一个CSS类来进行突出显示(从元素中添加或删除类比在跨度中包装/展开其内容更容易):

CSS:

.highlight {
    background-color:#F5A623;
}

然后是 javascript 辅助函数

js:

function addClass(elem, className) {
    // HTMLElement.className is a string with one or several class names separated by a space
    var classNames =  elem.className.split(" ");
    // we search the array classNames with indexOf to check if the class needs to be added
    if (classNames.indexOf(className) == -1) {
        // the class name is not found in the existing class names of this element so we just concatenate className to t elem.className
        elem.className += " " + className;
    }
}

function removeClass(elem, className) {
    // same as above we split elem.className into an array of classNames
    var classNames = elem.className.split(" ");
    // we search for index of the className we want to remove
    // index === -1 means not found, otherwise the index is the position of className in classNames
    var index = classNames.indexOf(className);
    if (index !== -1) {
        // javascript's version of remove at, splice(index, 1) means remove one item at index
        classNames.splice(index, 1);
        // join(' ') re concatenate classNames into a string of space separated class names
        elem.className = classNames.join(' ');
    }
}

function highlightPos(pos) {
    var item = getItems()[posToIndex(pos)];
    addClass(item, 'highlight');
}

// to reset highlights between searches
function clearHighlights() {
    var items = getGridItems();
    for (var i = 0; i < items.length; i++) {
        removeClass(items[i], 'sel');
    }
}

引用文献:

split , indexOfsplice

现在要读取网格中的单词,我们必须至少找到搜索文本的第一个字母的位置,然后尝试匹配搜索文本的每个字母:

function findLetterPositions(letter) {
    // we define a new array to receive our results
    var positions = [];
    // there are 10 columns x 10 rows of items
    var itemCount = 10 * 10;
    for (let i = 0; i < itemCount; i++) {
        var pos = indexToPos(i);
        // we compare letters lowercased
        if (getLetterAtPos(pos).toLowerCase() === letter.toLowerCase()) {
            // we have found letter at pos, so we add it to our array of positions (push)
            positions.push(pos);
        }
    }
    return positions;
}

indexToPos 被定义为 posToIndex 的逆操作(获取索引,返回 pos):

function indexToPos(index) {
    var y = Math.floor(index / columnCount);
    var x = index - y * columnCount;
    return { x: x, y: y };
}

对于每个找到的位置,我们需要尝试匹配从该位置开始并沿指定方向搜索文本的每个字母。例如右边(给定第一个字母的初始位置):

function tryAndMatchRight(text,initialPos) {

    var x = initialPos.x;
    var y = initialPos.y;
    var columnCount = 10;
    // we need to check that we are far enough from the edge of the grid for the whole word to fit, otherwise give up by returning
    if (x + text.length > columnCount) {
        return;
    }
    // word found == true by default, the for loop below will try to prove otherwise
    var wholeWordFound = true;
    // we will keep track of the letter positions we're trying
    var wordPositions = [];
    // obviously
    wordPositions.push(initialPos);
    // we will try each letter of text starting from the second (index 1) to the end of text (index length-1)
    for (var x2 = 1; x2 < text.length; x2++) {
        // building the position object for the current letter
        var pos = { x: x + x2, y: y};
        // if the comparaison fails we can stop
        if (text[x2].toLowerCase() !== getLetterAtPos(pos).toLowerCase()) {
            wholeWordFound = false;
            break;
        }
        wordPositions.push(pos);
    }
    if (wholeWordFound) {
        highLightPositions(wordPositions);
    }
}

function hightlightPositions(positions) {
    for(var i = 0; i < positions.length; i++) {
        highlightPos(positions[i]);
    }
}

总结一下,单击搜索按钮时调用的函数可以是:

function search() {
    clearHighlights();
    var text = getSearchedText();
    var firstLetterPositions = findLetterPositions(text[0]);
    for (var i = 0; i < firstLetterPositions.length; i++) {
        var initialPos = firstLetterPositions[i];
        tryAndMatchRight(text,initialPos);
        // we only did it rightward, but other directions need their own functions
        // tryAndMatchDown(text,initialPos); 
        // tryAndMatchDownRight(text,initialPos);
        // tryAndMatchUpRight(text,initialPos);
    }
}

Fully working solution as a fiddle here

如果您确实想了解编程,我希望您会欣赏这个答案,它演示了编程主要是如何将大问题分解为较小的问题,直到问题可以通过语言本身提供的工具轻松解决(和理解)。

无论如何,这对我来说很有趣!干杯

(PS:正如Evochrome在下面的评论中所述,两个辅助函数addClass和removeClass已经通过普通js这样解决了 element.classList.add("mystyle") element.classList.remove("mystyle"))

关于javascript - 单词搜索游戏。如何搜索网格并突出显示结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52354391/

相关文章:

javascript - 将很长的变量从 PHP 传递到 Javascript

java - 在单词搜索游戏中找到所有可能性

json - 显示 Json 数组 Angular 5 HttpClient

html - 相对于图像定位文本

mysql - 我应该使用网站表单还是DIY表单程序作为MySQL前端?

flutter - 如何在 flutter 中制作填字游戏类型的拼图?

C++ Wordsearch 拼图网格二维数组

javascript - 如何正确使用 onClick 从按钮列表中上传的文件发送数据?

javascript - Javascript InfoVis 工具包的 'Hello, World' 是什么?

javascript - 我应该在 View 中引用 controller.model 还是 controller.content?