Przejdź do głównej treści

Krzyżówki Online

Grafika Krzyżówki

Odkryj świat interaktywnych krzyżówek! Wejdź do gry, w której Twoje zainteresowania naprawdę mają znaczenie. Wybierz dziedzinę, dopasuj poziom trudności i zanurz się w zestawie zagadek, które za każdym razem są inne, generowane dynamicznie przy każdym uruchomieniu.

Sprawdzaj wiedzę i rozwijaj umysł To idealny sposób na trening pamięci, utrwalanie pojęć i poszerzanie wiedzy — niezależnie od tego, czy wolisz programowanie, geografię, fotografię czy fizykę.

Rywalizuj ze sobą i zdobywaj kolejne poziomy Każda krzyżówka to nowa szansa, by udowodnić, że poradzisz sobie z wyzwaniami — szybciej, lepiej i dokładniej niż wcześniej.

Gotowy na wyzwanie? Kliknij, wybierz zestaw i rozpocznij przygodę. Za każdym razem czeka na Ciebie nowa łamigłówka — sprawdź, jak daleko zajdziesz!

Jak obsługiwać aplikację?
  1. Wybierz dziedzinę i poziom trudności,
  2. Kliknij na jedno z pól oznaczonych cyferką i wprowadź odpowiedź,
  3. Wypełnij wszystkie pola,
  4. Kliknij przycisk Sprawdź.

Odpowiedzi możesz poprawiać również po sprawdzeniu, klikając w podświetlone czerwone lub zielone pola i wprowadzając odpowiedź ponownie. Kierunek wprowadzania odpowiedzi możesz zmieniać wciskając Shift w trakcie wprowadzania odpowiedzi.

Loading...

Pytania poziomo:

Pytania pionowo:

Kierunek: poziomo · Shift — zmiana kierunku.

Kod po stronie przeglądarki

<style>
  .max-vh-75 {
    max-height: 75vh !important;
  }    
  .grid { margin-bottom: 1rem; }
  .cell {
    width: 36px;
    height: 36px;
    padding: 0;
    position: relative;    
  }
  .cell .letter {
    width: 100%;
    height: 100%;
    text-align: center;
    border: none; 
    background: transparent;  
  }    
  /* numer pola */
  .cell .number {
    font-size: 0.65rem;
    pointer-events: none;
  }
  [data-bs-theme=light] .cell { border: 1px solid #212529; }  
  [data-bs-theme=light] .cell.black { background:#212529; }
  [data-bs-theme=light] .cell.black input { background:#212529 !important; color:transparent; pointer-events:none; opacity: 0;}
  [data-bs-theme=golden] .cell { border: 1px solid #4a2f1b; }  
  [data-bs-theme=golden] .cell.black { background:#4a2f1b; }
  [data-bs-theme=golden] .cell.black input { background:#4a2f1b !important; color:transparent; pointer-events:none; opacity: 0;}
  [data-bs-theme=twilight] .cell { border: 1px solid #f3f6ff; }    
  [data-bs-theme=twilight] .cell.black { background:#f3f6ff; }
  [data-bs-theme=twilight] .cell.black input { background:#f3f6ff !important; color:transparent; pointer-events:none; opacity: 0;}
  [data-bs-theme=dark] .cell { border: 1px solid #f8f9fa; }    
  [data-bs-theme=dark] .cell.black { background:#f8f9fa; }
  [data-bs-theme=light] .cell.black input { background:#f8f9fa !important; color:transparent; pointer-events:none; opacity: 0;}
  .ok { background: var(--bs-success) !important; color: #ffffff !important}
  .bad { background: var(--bs-danger) !important;  color: #ffffff !important}
</style>
<div id="app">
  <div class="row">
    <div class="col-md-6 mb-3">
      <label for="domain" class="form-label">Dziedzina</label>
      <select class="form-select" id="domain" data-bind="value: domain">
        <option value="programming">programowanie</option>
        <option value="physics">fizyka</option>
        <option value="photography">fotografia</option>
        <option value="geography">geografia</option>
      </select>
    </div>
    <div class="col-md-6 mb-3">
      <label for="level" class="form-label">Poziom trudności</label>
      <select class="form-select" id="level" data-bind="value: level">
        <option value="beginner">początkujący</option>
      </select>
    </div>
  </div>
  <!-- ko if: loading --> 
  <div class="d-flex justify-content-center mb-3">
    <div class="spinner-border" role="status">
      <span class="visually-hidden">Loading...</span>
    </div>
  </div>
  <!-- /ko -->    
  <div class="row">
    <div class="col-md-6 mb-3">
      <div class="max-vh-75 overflow-auto">                  
        <!-- ko if: questionsH().length > 0 -->  
        <h2 class="h5">Pytania poziomo:</h2>
        <ul data-bind="foreach: questionsH" class="list-group list-group-flush">
          <li class="list-group-item" data-bind="text: $data"></li>
        </ul>
        <!-- /ko -->  
        <!-- ko if: questionsV().length > 0 -->    
        <h2 class="h5">Pytania pionowo:</h2>
        <ul data-bind="foreach: questionsV" class="list-group list-group-flush">
          <li class="list-group-item" data-bind="text: $data"></li>
        </ul>
        <!-- /ko -->  
      </div>    
    </div>
    <div class="col-md-6 mb-3">
      <p>
        Kierunek: <b id="dirLabel">poziomo</b> ·
        <kbd>Shift</kbd> — zmiana kierunku.
      </p>
      <table class="grid table table-borderless">
        <tbody data-bind="foreach: crossdata">
          <tr data-bind="foreach: $data">
            <td class="cell position-relative"
              data-bind="css: { black: $data === null }">
              <!-- numer pola z mapy numbers -->
              <span class="number position-absolute top-0 start-0 ms-1 mt-1 small fw-bold"
                data-bind="
                text: $root.numbers()[$parentContext.$index()] && 
                $root.numbers()[$parentContext.$index()][$index()],
                visible: $root.numbers()[$parentContext.$index()] &&
                $root.numbers()[$parentContext.$index()][$index()] !== null
                ">
              </span>
              <!-- pole do wprowadzenia liter -->
              <input class="letter"
                data-bind="
                attr: {                
                disabled: $data === null,
                'data-row': $parentContext.$index(),
                'data-col': $index()
                }
                " aria-label="Wprowadź literę">
            </td>
          </tr>
        </tbody>
      </table>
      <button id="checkBtn" class="btn btn-primary">Sprawdź</button>
      <button id="resetBtn" class="btn btn-secondary ms-2">Wyczyść</button>
      <span id="result" class="ms-3 fw-bold"></span>
    </div>
  </div>
</div>
<script>
// --------------------------------------
// Twój ViewModel
// --------------------------------------
let ViewModel = null;
let vm = null;    
document.addEventListener('DOMContentLoaded', function () {

    ViewModel = function() {
        const self = this;
        self.questionsH = ko.observableArray();
        self.questionsV = ko.observableArray();
        self.numbers = ko.observableArray();
        self.crossdata = ko.observableArray();
        self.numRows = ko.observable(0);
        self.numCols = ko.observable(0);
        self.domain = ko.observable('programming');
        self.level = ko.observable('beginner');
                        
        self.domain.subscribe(function(newVal){
            self.load(newVal, null);   // teraz zawsze dostaniesz aktualną wartość
        });
        self.level.subscribe(function(newVal){
            self.load(null, newVal);   // teraz zawsze dostaniesz aktualną wartość
        });
        
        self.loading = ko.observable(false);
        
        self.load = function(domain = null, level = null)
        {
            self.loading(true);
            self.questionsH([]);
            self.questionsV([]);
            self.numbers([]);
            self.crossdata([]);
            
            const params = {
                operation: 'load',
                inputdata: [],
                domain: domain ?? self.domain(),
                level: level ?? self.level(),
                token: '8374481edfd1dbf6801ee8f553bd6eea088e0dc2'
            };
            
            axios.post(urlSite('public/ajax/app/exec/42'), params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
               .then(function(response) {
                   const data = response.data;
                    self.questionsH(data.data.questions.horizontal);
                    self.questionsV(data.data.questions.vertical);
                    self.numbers(data.data.numbers);
                    self.crossdata(data.data.crossdata);    
                    self.numRows(data.meta.rows);
                    self.numCols(data.meta.cols);
                
                    initCrosswordLogic();
                    document.getElementById('result').textContent = '';
                    self.loading(false);
            }).catch(function(error) {
                self.loading(false);
                BootstrapToast.show({title: 'Błąd', message: error.response.data.message, when: 'teraz', type: 'danger', icon: 'bi-x-circle-fill'});                
            });
        };
    };

    vm = new ViewModel();
    ko.applyBindings(vm, document.getElementById('app'));
    
    vm.load();
    
});

// --------------------------------------
// Funkcja inicjalizująca oryginalną logikę
// --------------------------------------
function initCrosswordLogic() {

  const allInputs = Array.from(
    document.querySelectorAll('input[data-row][data-col]')
  );
  const inputs = allInputs.filter(i => !i.disabled);
  const resultEl = document.getElementById('result');
  let direction = 'right';
  const numRows = vm.numRows();
  const numCols = vm.numCols();  

  const dirLabel = document.getElementById('dirLabel');
  const setDir = (d) => {
    direction = d;
    dirLabel.textContent = d === 'right' ? 'poziomo' : 'pionowo';
  };

  function cell(r,c){return allInputs.find(i=>i.dataset.row==r && i.dataset.col==c)}

  function nextRight(i){
    let r=+i.dataset.row, c=+i.dataset.col+1;
    while(c<=numCols){
      const x=cell(r,c); if(x && !x.disabled) return x;
      c++;
    }
    return null;
  }
  function prevLeft(i){
    let r=+i.dataset.row, c=+i.dataset.col-1;
    while(c>=1){
      const x=cell(r,c); if(x && !x.disabled) return x;
      c--;
    }
    return null;
  }
  function nextDown(i){
    let r=+i.dataset.row+1, c=+i.dataset.col;
    while(r<=numRows){
      const x=cell(r,c); if(x && !x.disabled) return x;
      r++;
    }
    return null;
  }
  function prevUp(i){
    let r=+i.dataset.row-1, c=+i.dataset.col;
    while(r>=1){
      const x=cell(r,c); if(x && !x.disabled) return x;
      r--;
    }
    return null;
  }

  // Not used  
  //if(inputs[0]) inputs[0].focus();

  inputs.forEach(field => {
    field.maxLength = 1;

    field.addEventListener('input', () => {
      field.value = field.value.toUpperCase().slice(0,1);
      if(field.value){
        const nxt = direction==='right' ? nextRight(field) : nextDown(field);
        if(nxt) nxt.focus();
      }
    });

    field.addEventListener('keydown', e => {
      if(e.key === 'Shift'){
        setDir(direction === 'right' ? 'down' : 'right');
        return;
      }

      if(e.key === 'Backspace'){
        if(field.value === ''){
          e.preventDefault();
          const prev = direction==='right' ? prevLeft(field) : prevUp(field);
          if(prev){
            prev.focus();
            prev.value = '';
          }
        }
        return;
      }

      if(e.key === 'ArrowRight'){
        e.preventDefault();
        const x = nextRight(field); if(x) x.focus();
        return;
      }
      if(e.key === 'ArrowLeft'){
        e.preventDefault();
        const x = prevLeft(field); if(x) x.focus();
        return;
      }
      if(e.key === 'ArrowDown'){
        e.preventDefault();
        const x = nextDown(field); if(x) x.focus();
        return;
      }
      if(e.key === 'ArrowUp'){
        e.preventDefault();
        const x = prevUp(field); if(x) x.focus();
        return;
      }
    });

    field.addEventListener('click', e=>{
      if(e.shiftKey) setDir(direction==='right' ? 'down' : 'right');
    });

  });

  // sprawdzanie
  document.getElementById('checkBtn').onclick = () => {
    let correct = 0;
    let total = 0;
    let inputData = [];  
    inputs.forEach(i=>{
      inputData.push({
          row: i.dataset.row,
          col: i.dataset.col,
          value: i.value
      });        
    });
      
    const params = {
      operation: 'check',
      inputdata: inputData,
      domain: vm.domain(),
      level: vm.level(),        
      token: '8374481edfd1dbf6801ee8f553bd6eea088e0dc2'
    };
            
    axios.post(urlSite('public/ajax/app/exec/42'), params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
      .then(function(response) {
        const data = response.data.data;           
        let index = 0;
        
        inputs.forEach(i=>{                         
           const correctResult = data[index].correct; 
           total++;
           i.classList.remove('ok','bad');                                  
           if(correctResult) 
           {
             correct++; 
             i.classList.add('ok');
           } else 
           {
             i.classList.add('bad');
           }                      
           index++;
        });
       
        if (correct === total)
        {
          resultEl.textContent = "Wszystko poprawnie!";        
          BootstrapToast.show({
            title: 'Świetna robota!',
            message: 'Udało Ci się poprawnie rozwiązać całą krzyżówkę!',
            when: 'teraz',
            type: 'success',
            icon: 'bi-check-circle-fill'  
          });
        }
        else
        {
          resultEl.textContent = `Poprawnych: ${correct} z ${total}`;
          BootstrapToast.show({
            title: 'Jeszcze chwilka!',
            message: 'Niektóre odpowiedzi wymagają poprawek. Sprawdź ponownie i spróbuj jeszcze raz.',
            when: 'teraz',
            type: 'warning',
            icon: 'bi-exclamation-triangle-fill'  
          });
        }
      }).catch(function(error) {
        BootstrapToast.show({title: 'Błąd', message: error.response.data.message, when: 'teraz', type: 'danger', icon: 'bi-x-circle-fill'});
      });      
  };

  // reset
  document.getElementById('resetBtn').onclick = () => {
    inputs.forEach(i=>i.value='');
    inputs.forEach(i=>i.classList.remove('ok','bad'));
    resultEl.textContent = '';
    // Not used  
    //if(inputs[0]) inputs[0].focus();
  };
}
</script>

Kod po stronie serwera

Licencja

## BSD-3-Clause License Agreement
BSD-3-Clause
Сopyright (c) 2026 Dariusz Rorat

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3 grudnia 2025 5

Kategorie

Technologie

Dziękujemy!
()

Informacja o cookies

Moja strona internetowa wykorzystuje wyłącznie niezbędne pliki cookies, które są wymagane do jej prawidłowego działania. Nie używam ciasteczek w celach marketingowych ani analitycznych. Korzystając z mojej strony, wyrażasz zgodę na stosowanie tych plików. Możesz dowiedzieć się więcej w mojej polityce prywatności.