Styling a sudoku grid

隐身守侯 提交于 2019-12-31 04:15:07

问题


I’ve created a sudoku puzzle creator / solver and need a bit of help with some CSS to style it.

Typically they are styled like this:

.

Some naming I’m using.

Cell - each individual cell which contains a single number.

Box - one of the 9 boxes each containing 3 x 3 cells

Grid - the entire 9x9 playing area.

My html is partially generated by my ruby / Sinatra app (at least the repeating DIV’s are) and structured as such :

#game {
  margin-left: auto;
  margin-right: auto;
  width: 360px;
}
.cell input {
  display: inline-block;
  float: left;
  width: 40px;
  height: 40px;
  border-style: solid;
  border-width: 1px;
  text-align: center;
  font-size: 15px;
}
<form action="/" method="post">
  <div id="game">
    <div class="cell">
      <input name="cell[0]" type="text" maxlength="1" value=<%=val%>>
    </div>

    <div class="cell">
      <input name="cell[1]" type="text" maxlength="1" value=<%=val%>>
    </div>

    <!-- ... -->

    <div class="cell">
      <input name="cell[79]" type="text" maxlength="1" value=<%=val%>>
    </div>

    <div class="cell">
      <input name="cell[80]" type="text" maxlength="1" value=<%=val%>>
    </div>
  </div>
</form>

This allows me to create the basic 9x9 grid with my first cell (0) in the top left corner and moving left to right, a row at a time, to the last cell (80) in the bottom right.

The difficulty is styling each cell so that the grid can appear split not only into rows and columns but also into the 9 larger boxes. Again see this grid for reference.

Currently I have a couple of options :

  1. Completely rewrite my sudoku code so that I draw out the DIV’s in a different order. Wrapping each box in a grouping DIV. This would make the CSS relatively straight forward. This would be a major change and I really don’t want to go down this route.

  2. Manually ID each cell and write the corresponding CSS for all 81 cells. Better than above but still a ball ache and not particularly slick.

I do have the option of dynamically generating the CSS styling (performance is not an issue). What I’m looking for is some help with devising an algorithm that will determine (based on it’s linear index 0..80) how each cell should be styled.

For example all the cells in the top row (0..8) will have a thick top border (3px) and a thin bottom border (1px). The bottom of all the cells in row 3 (18..26) would have a thick border but the top of those cells would have a thin border. The left hand side of all the cells in the first column would have a thick border, but the right hand side of those cells would have a thin border. And so on.


回答1:


The following is a slight modification of an example in the table element section in HTML5 CR, illustrating the use of colgroup for grouping columns and tbody for grouping rows. This grouping lets you set different borders around the groups than otherwise around cells.

<style>
table { border-collapse: collapse; font-family: Calibri, sans-serif; }
colgroup, tbody { border: solid medium; }
td { border: solid thin; height: 1.4em; width: 1.4em; text-align: center; padding: 0; }
</style>
<table>
  <caption>Sudoku of the day</caption>
  <colgroup><col><col><col></colgroup>
  <colgroup><col><col><col></colgroup>
  <colgroup><col><col><col></colgroup>
  <tbody>
   <tr> <td>1 <td>  <td>3 <td>6 <td>  <td>4 <td>7 <td>  <td>9
   <tr> <td>  <td>2 <td>  <td>  <td>9 <td>  <td>  <td>1 <td>
   <tr> <td>7 <td>  <td>  <td>  <td>  <td>  <td>  <td>  <td>6
  <tbody>
   <tr> <td>2 <td>  <td>4 <td>  <td>3 <td>  <td>9 <td>  <td>8
   <tr> <td>  <td>  <td>  <td>  <td>  <td>  <td>  <td>  <td>
   <tr> <td>5 <td>  <td>  <td>9 <td>  <td>7 <td>  <td>  <td>1
  <tbody>
   <tr> <td>6 <td>  <td>  <td>  <td>5 <td>  <td>  <td>  <td>2
   <tr> <td>  <td>  <td>  <td>  <td>7 <td>  <td>  <td>  <td>
   <tr> <td>9 <td>  <td>  <td>8 <td>  <td>2 <td>  <td>  <td>5
</table>



回答2:


By combining Jukka K. Korpela's answer with Mike's answer and adding a bit of jQuery magic, I have created two solutions.

$(document).ready(function () {
    var data = [
        1, 0, 3, 6, 0, 4, 7, 0, 9, // 0x0
        0, 2, 0, 0, 9, 0, 0, 1, 0, // 0x1
        7, 0, 0, 0, 0, 0, 0, 0, 6, // 0x2
        2, 0, 4, 0, 3, 0, 9, 0, 8, // 1x0
        0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x1
        5, 0, 0, 9, 0, 7, 0, 0, 1, // 1x2
        6, 0, 0, 0, 5, 0, 0, 0, 2, // 2x0
        0, 0, 0, 0, 7, 0, 0, 0, 0, // 2x1
        9, 0, 0, 8, 0, 2, 0, 0, 5  // 2x2
    ];

    // Build page content.
    $('body').append($('<div>').addClass('wrapper')
        .append($('<div>').addClass('col')
          .append($('<h1>').html('First Method'))
          .append(generateSudokuGrid()))
        .append($('<div>').addClass('col')
          .append($('<h1>').html('Second Method'))
          .append(generateSudokuGrid2())));

    // Populate grids with data.
    $('table[class^="sudoku"]').each(function (index, grid) {
        populateGrid($(grid), data);
    });
});

function populateGrid(grid, data) {
    grid.find('td').each(function (index, td) {
        $(td).text(data[index] || '');
    });
}

/* First Method */
function generateSudokuGrid(data) {
    return $('<table>').append(multiPush(3, function () {
        return $('<colgroup>').append(multiPush(3, function () {
            return $('<col>');
        }));
    })).append(multiPush(3, function () {
        return $('<tbody>').append(multiPush(3, function () {
            return $('<tr>').append(multiPush(9, function () {
                return $('<td>');
            }));
        }));
    })).addClass('sudoku');
}

/* Second Method */
function generateSudokuGrid2(data) {
    return $('<table>').append(multiPush(9, function () {
        return $('<tr>').append(multiPush(9, function () {
            return $('<td>');
        }));
    })).addClass('sudoku2');
}

function multiPush(count, func, scope) {
    var arr = [];
    for (var i = 0; i < count; i++) {
        arr.push(func.call(scope, i));
    }
    return arr;
}
/* First Method */
table.sudoku {
    border-collapse: collapse;
    font-family: Calibri, sans-serif;
}
.sudoku colgroup, tbody {
    border: solid medium;
}
.sudoku td {
    border: solid thin;
    height: 1.4em;
    width: 1.4em;
    text-align: center;
    padding: 0;
}

/* Second Method */
table.sudoku2 {
    border-collapse: collapse;
    font-family: Calibri, sans-serif;
}
.sudoku2 tr:nth-of-type(3n) {
    border-bottom: solid medium;
}
.sudoku2 td:nth-of-type(3n) {
    border-right: solid medium;
}
.sudoku2 td {
    border: solid thin;
    height: 1.4em;
    width: 1.4em;
    text-align: center;
    padding: 0;
}

/* Presentation Formatting [Ignore] */
table[class^="sudoku"] {
  margin: 0 auto;
}
.wrapper {
  width: 100%;
}
.col {
  display: inline-block;
  width: 50%;
  text-align: center;
  margin: 0 auto;
  padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>



回答3:


If it were me, I would have used a table with 9 rows and 9 columns.

Then used :nth-of-type(3n) in the CSS selectors to set the border on every third row and column.




回答4:


I would create the Sudoku board as following:

<section class="sudoku">
       <div class="sudoku-row">
           <div class="sudoku-square">
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value"></a></div>
              <div class="cell"><a class="cell-value "></a></div> 
          </div>

and the LESS will be like this

@cell-size: 50px;
.sudoku {
  margin: 70px auto;  
  width: 478px;
  background: #777;    
  border: 2px solid #000;
  box-shadow: 15px 15px 20px #111;

  .sudoku-row {    
    .sudoku-square {      
      float: left;
      border: 1px solid #000;

      .cell:nth-child(3n+1) {
        clear: both;
      }
      .cell {
        float: left;        
        position: relative;
        height: @cell-size;
        width: @cell-size;
        background:#fff;        
        border: 1px solid #000;
        box-sizing: content-box;        

        a {
          margin: 0;
          padding: 0;
        }
        a.cell-value {
          display: block;
          font-size: 30px;            
          color: #000;
          width: @cell-size;
          height: @cell-size;
          text-align: center;          
        }

        a.cell-value:hover {
        text-decoration: none;
        }
      }      
    }
    clear: both;
  }
}

you can find a live demo here




回答5:


Great solution Jukka. I used a combination of this and the following .erb code to dynamically generate the table and pop the contents in.

@current_solution is my array holding the values for each cell.

<table>
  <colgroup><col><col><col>
  <colgroup><col><col><col>
  <colgroup><col><col><col>

  <% 3.times do |all_box_rows_value|%>
  <tbody>
    <% 3.times do |box_row_value| %> 
      <%  all_box_rows = all_box_rows_value * 27 %>
        <% all_rows = ((box_row_value +1 ) * 9)-9 %>
        <tr><%9.times do |row| %>
          <% index = all_box_rows+all_rows+row %>
          <% value = @current_solution[index] %><td>
          <% colour_class = get_colour_class index %>
          <input name="cell[]" type="text" maxlength="1" autocomplete="off" value=<%=value%> >
        <% end %>
      <% end %>      
  <% end %>    
</table>


来源:https://stackoverflow.com/questions/19697033/styling-a-sudoku-grid

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!