Programować każdy może (3)
Nie wiem czy jeszcze dziś potrafię, bo nie mam stosownego narzędzia - ale mam dowód, że kiedyś potrafiłem.
Napisałem to, ponieważ nie umiałem ułożyć układanki w pudełku, ale potrafiłem napisać program, który szukał rozwiązania.
Łamigłówka była elementem jakiejś fajnej gry przygodowej, którą A. zainstalowała na domowym iPadze, i której nie potrafiłem przejść, bo była właśnie ta łamigłówka. Programowanie zajęło mi z 8 godzin jak nic, przy czym dużo czasu kosztowało stworzenie środowiska do pisania w C (wyszło, że gcc na Linixie i vi jest nawłaściwsze), a dużo ponowne nauczenie się podstaw tego języka. Algorytm rekurencyjny był najmiejszym problemem.
Programowanie jest fajne!
#include #include #define DEBUG 2 #define NN 8 #define MM 6 int Lww = 0, Lwu =0; struct Figura { int n; // wielkosc w poziomie int m; // wielkosc w pionie int F[NN][MM]; // wskaznik na tablice opisującą int EEi; // wspolrzędna i punktu EE figury int PPi; // położenie figury na planszy - współrzędna i punktu EE lub -1 int PPj; // jak wyżej dla drugiej współrzędnej }; // #include "z2.h" #define LICZBA_FIGUR 11 struct Figura FFF [LICZBA_FIGUR] = { { 1, 1, { // #0 - pojedynczy kwadracik { 12 }, }, }, { 3, 3, { // #1 - odwrócone T { 0, 0, 1 }, // uwaga: wiersze są pionami! { 1, 1, 1 }, { 0, 0, 1 }, }, }, { 3, 3, { // #2 - krzyżyk { 0, 2, 0 }, { 2, 2, 2 }, { 0, 2, 0 }, }, }, { 3, 3, { // #3 takie M albo W - niebieskie schodki { 3, 3, 0 }, { 0, 3, 3 }, { 0, 0, 3 }, }, }, { 2, 3, { // #4 duże Gama - zielony, do górnego lewego rogu pasuje { 4, 4, 4 }, { 4, 0, 0 }, }, }, { 4, 2, { // #5 takie Zet ale naciągnięte { 5, 0 }, { 5, 5 }, { 0, 5 }, { 0, 5 }, }, }, { 4, 2, { // #6 T z przeciągniętym na prawo daszkiem { 6, 0 }, { 6, 6 }, { 6, 0 }, { 6, 0 }, }, }, { 3, 2, { // #7 takie L ale żeby je wstawić w prawy dolny róg { 0, 7 }, { 0, 7 }, { 7, 7 }, }, }, { 3, 3, { // #8 - ?? { 0, 8, 0 }, { 8, 8, 0 }, { 0, 8, 8 }, }, }, { 1, 5, { // #9 - pionowa pałka o dlugości 5 kratek { 9, 9, 9, 9, 9 }, }, }, { 2, 3, { // #10 - do wstawienia w prawy górny róg { 10, 0, 0 }, { 10, 10, 10 }, }, }, }; void drukuj_tablice (int PP [NN][MM]); void drukuj_figure (struct Figura F); // najważniejsza i jedyna funkcja co kładze figurę na planszy i woła siebie dla nasztępnej figury int wstaw_figure (int PPP[NN][MM], struct Figura FFF [LICZBA_FIGUR], int kk, int level) { int i, j, n, m, a, l; int Xi, Xj, Ei; int tmpEEi, tmpIIe; // trudne zmienne wykorzystywane przy obróbce wciętych figur int PP[NN][MM]; // lokalna tablica z planszą struct Figura FF [LICZBA_FIGUR]; // lokalny zestaw figur wraz z ich stanem i położeniem Lww++; // to jest statystyka dla ciekawych // Przekonany byłem, że w C może przenosić jako argumenty całe złożone struktury danyc... // ... to na pewno się da, ale ja nie wiem jak się to robi. A może to dało się w C++? // ... nie pamiętam, więc na głupka kopiuję nawet nie strncpy() ale for() for (j=0; j<MM; j++) // naprawdę nie pamiętam, kiedy przekazuje się do funkcji... for (i=0; i<NN; i++) // ... tablicę, a kiedy adres do tablicy PP[i][j] = PPP[i][j]; // ... wiec wolę skopiować aby mieć to lokalnie u siebie for (l=0; l<LICZBA_FIGUR; l++) { // to też ma być lokalne a nie wiem czy jest FF[l].n = FFF[l].n; FF[l].m = FFF[l].m; // FF[l].F = FFF[l].F; // tu kopiowany jest adres tych tablic z kształtem for (j=0; j<FFF[l].m; j++) for (i=0; i<FFF[l].n; i++) FF[l].F[i][j] = FFF[l].F[i][j]; FF[l].EEi = FFF[l].EEi; FF[l].PPi = FFF[l].PPi; FF[l].PPj = FFF[l].PPj; } // początek analizy figur na planszy // czy da sie tą figure posadzić? // wyznacz współrzędne punktu X - a więc najwyżej położonego pustego punktu j=0; a=1; while ( a && j 1) { printf ("\n* * * * * * Wciśnij Enter * * * * *"); getchar(); system ("clear"); // czy nie ma jakiejś tańszej metody czyszczenia ekranu niż wołanie powłoki systemu? } if (DEBUG > 0) { printf ("\nPoziom: %i, figura: %i \n\nStan pola PP:", level, kk); drukuj_tablice (PP); printf ("\nTestowana figura: %i, rozmar: %i, %i Ei: %i\nKształt figury:", kk, FF[kk].n, FF[kk].m, FF[kk].EEi); drukuj_figure (FF[kk]); printf ("\nProba polożenia figury na Xi=%i Xj=%i", Xi, Xj); } if (a) { // niemożliwe, aby nie było pustego punktu - poważnie? if (DEBUG > 0) { printf ("\n* ponoć wszystkie pola są zajęte? dziwne! Coś nie tak wieć wciśnij Enter!"); getchar (); } return -2; // znak, że błąd w danyc, sterowaniu, albo algorytmie } // sprawdzam, czy figura FF[kk] wlezie w obszar PP if (Xi + FF[kk].n - FF[kk].EEi > NN) { // nie wlezie w obszaw pola PP if (DEBUG > 0) printf ("\n- figura nie mieści sie w poziomie z prawej"); return -17; } if (Xi - FF[kk].EEi < 0) { if (DEBUG > 0) printf ("\n- figura nie mieści się z lewej"); return -18; } if (Xj + FF[kk].m > MM) { if (DEBUG > 0) printf ("\n- figura mie mieści się pionie"); return -19; } // sprawdzam, czy da się położyć figurę aby nie zawadzać o inne, już położone tmpEEi = FF[kk].EEi; a=1; // tmpEj - bo pierwsza linia jest krótsza o blade znaki figury tmpIIe = 0; j = Xj; m = 0; // przebieganie po drugim wymiarze while (a && m < FF[kk].m) { i = Xi - tmpIIe; n = tmpEEi; while (a && n < FF[kk].n) { if (PP[i][j] && FF[kk].F[n][m]) { // czy nakładają się pola z PP planszy i F figury a = 0; break; } i++; n++; } if (!a) break; tmpIIe = FF[kk].EEi; tmpEEi = 0; // druga linia analizowana normalnie j++; m++; } if (!a) { // nakładają się, więc koniec procedury if (DEBUG > 0) printf ("\n- figura %i nakłada się przy i=%i j=%i dla n=%i m=%i", kk, i, j, n, m); return -27; } // posadz figure skoro sie da // - tzn zmiana planszy PP // - tzn zmiana tabeli figur FFF bo kk-figura ma zapisane współrzędne gdzie posadzona Lwu++; // to jakaś statystyka dla ciekawych FF[kk].PPi = Xi; // ustaw wspolrzednne gdzie sie miesci ta figura - tj. wskaźnik używalności jej FF[kk].PPj = Xj; // uwaga na te dane, bo w PPi nie uwzględniono korekty EEi // posadź figurę na planszy tmpEEi = FF[kk].EEi; // tmpEj - bo pierwsza linia jest krótsza o blade znaki figury tmpIIe = 0; j = Xj; m = 0; // przebieganie po drugim wymiarze while (m < FF[kk].m) { i = Xi - tmpIIe; n = tmpEEi; while (n < FF[kk].n) { if (FF[kk].F[n][m]) // czy nakładają się pola z PP planszy i F figury PP[i][j] = FF[kk].F[n][m]; // numer figury znacznikiem, że pole zajęte tą figurą i++; n++; } tmpIIe = FF[kk].EEi; tmpEEi = 0; // druga linia analizowana normalnie j++; m++; } printf ("\n+ zmieściło się, więc położyłem figurę %i w Xi=%i Xj=%i\nNowy stan tablicy PP:", kk, Xi, Xj); drukuj_tablice (PP); // przeleć się po wszystkich figurach nie uzywanych probujac je wstawic // jeżeli nie ma już figur to sukces ! l=0; a=1; while (a && l<LICZBA_FIGUR) { if (FF[l++].PPi == -1) a = 0; } if (a) { printf ("\n+ oto jest rozwiązanie ! TaTaM !!! * * * * * Wciśnij Enter!"); getchar (); return 0; } for (l=0; l<LICZBA_FIGUR; l++) { // czy figura jest jeszcze nie używana if (FF[l].PPi == -1) { // jeżeli nie używana to ją wstawiaj printf ("\n+ wywoluje dla figury %i kolejny poziom %i", l, level+1); wstaw_figure ((PP), (FF), l, level+1); } } printf ("\n- na tym poziomie (%i) wszystko wywołano już wszystko i wszystko wróciło", level); } /*********************************************************************/ int main () { int i, j, k, l, n, m; int PP[NN][MM]; // wyzeruj plansze PP na której się będzie pracować for (i=0; i<NN; i++) for (j=0; j<MM; j++) PP[i][j] = 0; // przygotuj tabele figur // - policz ile jest figur // - wyznacz punkty EE // - wyzeruj położenie for (k=0; k<LICZBA_FIGUR; k++) { FFF[k].PPi = FFF[k].PPj = -1; // znacznik, że figura nie używana // tu jeszcze wyznaczam punkt EEi // wyjaśnienie - EEi to ile punktów pustych jest w pierwszym rzędzie od lewej FFF[k].EEi=0; for (i=0; i<FFF[k].n; i++) if (FFF[k].F[i][0]) { FFF[k].EEi = i; break; } } // główny kod programu printf ("\nProgram do rozwiązywania łaigłówki. 2012 (c) Eniac Software\n"); printf ("\nLiczba figur: %i", LICZBA_FIGUR); printf ("\nWydruk figur aby je sobie pooglądać"); for (k=0; k<LICZBA_FIGUR; k++) { printf ("\nFigura nr %i ma wymiary n=%i m=%i i parametr Ei=%i", k, FFF[k].n, FFF[k].m, FFF[k].EEi); drukuj_figure (FFF[k]); } for (k=0; k<LICZBA_FIGUR; k++) { printf ("\n"); wstaw_figure (PP, FFF, k, 0); } printf ("\nStatystyka - Wywołań: %i, Postawień: %i", Lww, Lwu); return 0; } void drukuj_tablice (int PP [NN][MM]) { int i, j; printf ("\n|"); for (i=0; i<NN; i++) printf (" %1i", i); printf (" |"); printf ("\n|"); for (i=0; i<NN; i++) printf ("--"); printf ("-|"); for (j=0; j<MM; j++) { printf ("\n|"); for (i=0; i<NN; i++) printf (" %1C", PP[i][j] ? '@' + PP[i][j] : '.'); printf (" |"); } printf ("\n|"); for (i=0; i<NN; i++) printf ("--"); printf ("-|"); printf ("\n|"); for (i=0; i<NN; i++) printf (" %1i", i); printf (" |"); printf ("\n"); } void drukuj_figure (struct Figura F) { int i, j; printf ("\n|"); for (i=0; i<F.n; i++) printf ("--"); printf ("-|"); for (j=0; j<F.m; j++) { printf ("\n|"); for (i=0; i<F.n; i++) { printf (" %1C", F.F[i][j] ? '@' + F.F[i][j] : '.'); } printf (" |"); } printf ("\n|"); for (i=0; i<F.n; i++) printf ("--"); printf ("-|"); }