Ir ao conteúdo
  • Cadastre-se

C tabuleiro de sudoku em linguagem c


Visitante

Posts recomendados

preciso de ajudar para fazer um programa em c 

 

o programa deve apresentar um tabuleiro de sudoku, e permitir que o usuário jogue nesse tabuleiro. O tabuleiro inicial deve ser lido de um arquivo, que contém 81 números entre 0 e 9, que são os valores de cada posição do tabuleiro. O valor 0 é usado para representar uma casa vazia. Caso o arquivo não exista, deve inicializar com um tabuleiro default (que pode ser vazio). 

O programa deve ter um laço principal que consiste em:

apresenta o tabuleiro – caso o tabuleiro esteja completo e correto (fim do jogo), esse fato deve ser informado;

lê uma tecla do usuário. Essa tecla pode ser:

um dígito entre 1 e 9 – representa o início de uma jogada, descrita abaixo;

a letra ‘g’ – grava o estado atual do jogo; o programa pede o nome de um arquivo e grava o tabuleiro nesse arquivo;

a letra ‘l’ – ler um jogo salvo anteriormente; o programa pede o nome do arquivo e substitui o tabuleiro pelo conteúdo dessa arquivo (caso consiga ler o arquivo);

a letra ‘s’ – o usuário pede para sair do jogo; o programa pede confirmação.

volta à apresentação do tabuleiro

Uma jogada consiste em o usuário digitar 3 números: a linha, a coluna e o valor a colocar nessa posição. O programa deve avisar o usuário (e não aceitar a jogada), se algum desses valores for inválido (não tiver entre 1 e 9), se a posição escolhida não estiver vazia, ou se essa jogada levar a uma situação inválida do tabuleiro (pelas regras do sudoku).

Após cada jogada válida, o tabuleiro deve ser gravado no arquivo que foi lido no início do programa. Dessa forma, sempre que o programa começa, o usuário volta à mesma situação em que estava na última vez que jogou

Link para o comentário
Compartilhar em outros sites

@mmqs     esse jogo de sodoku é bem interessante ,  ele é tipo um quebra cabeça ,  e com todas essas opções e melhoramentos vai demorar bastante para programa lo e deixar ele funcionando bem ,  e para ter gráficos com melhor qualidade seria bom usar o visual studio ,  e para gravar e ler o jogo no arquivo use a função fopen , e se for usar o mouse para jogar , como nos jogos que já existem   ,  use as funções da biblioteca windows.h , para detectar a posição do mouse , e poste o que você já conseguiu fazer sobre esse exercício , para ajudarmos se precisar de alguma correção .

Link para o comentário
Compartilhar em outros sites

@devair1010 eu também to precisando de ajuda nesse programa mas o professor não explicou metade das coisas para fazer esse arquivo, consegui só o inicio até agora e não sei como faço para salvar o arquivo e sobrescrever ele depois

int main()
{
    FILE *arq;
    arq= fopen("jogo","a");
    if (arq==NULL){
        printf("não foi possivel abrir");
        return 1;
    }
    int i,j,m[9][9];
    for(i=0; i<9; i++){
        for(j=0; j<9; j++){
           
               fprintf(arq,"  ");
        
        }
        fprintf(arq,"\n");
    }
    
    for(i=0; i<9; i++){
        for(j=0; j<9; j++){
            scanf("%d",&m[i][j]);
            if(m[i][j]>=10 || m[i][j]==0 ){
                printf("digite só números entre 1 e 9");
            }
        }
    }

    fclose(arq);


    return 0;
}

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Em 02/01/2021 às 07:45, devair1010 disse:

@mmqs     esse jogo de sodoku é bem interessante ,  ele é tipo um quebra cabeça ,  e com todas essas opções e melhoramentos vai demorar bastante para programa lo e deixar ele funcionando bem ,  e para ter gráficos com melhor qualidade seria bom usar o visual studio ,  e para gravar e ler o jogo no arquivo use a função fopen , e se for usar o mouse para jogar , como nos jogos que já existem   ,  use as funções da biblioteca windows.h , para detectar a posição do mouse , e poste o que você já conseguiu fazer sobre esse exercício , para ajudarmos se precisar de alguma correção .

 

acho improvavel que o professor queira que eles façam uma GUI, ate porque mudaria o foco pra C++ ou dificultaria MUITO usando só C, nao é pra nivel universitario fazer uma gui em C.

 

Para abrir o arquivo sem sobrescrever é só usar o fopen com a+ , mas no caso como você vai precisar ler/escrever em posições especificas do arquivo você vai usar muito as funcoes fseek e fsetpos..  como o arquivo vai ficar depende muito de como você quiser programar essa leitura, pra facilitar eu provavelmente faria as linhas colunas como no sudoku e criaria funcoes usando o fseek e fsetpos pra posicionar o ponteiro do stream exatamente onde você vai precisar ler/escrever no arquivo..

 

tipo assim:

 

supondo que seja somente 9 posições (1 a 3), o arquivo ficaria assim

 

1 2 3

2 3 3

3 1 1

 

ai você faz uma funcao assim

 

GetValue(int line_pos, int col_pos, FILE *pfile)

{

    fseek (pfile , (line_pos * col_pos) * 2 - 1 , SEEK_SET );

    return fread (ou fgetc, ou qualquer outra coisa pra ler do ponteiro)

}

 

ai se você quiser pegar a posicao linha 2 coluna 2 você faz o GetValue(2, 2, file)

 

deve funcionar, nao testei nada, mas o caminho é por ai.

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, DiogoM12 disse:

acho improvavel que o professor queira que eles façam uma GUI, ate porque mudaria o foco pra C++ ou dificultaria MUITO usando só C, nao é pra nivel universitario fazer uma gui em C

 

Acho que tem razão :) 

Em especial porque uma interface gráfica para um tabuleiro de 9 x 9 números não acrescenta quase nada

 

1 hora atrás, DiogoM12 disse:

Para abrir o arquivo sem sobrescrever é só usar o fopen com a+ , mas no caso como você vai precisar ler/escrever em posições especificas do arquivo você vai usar muito as funcoes fseek e fsetpos..  como o arquivo vai ficar depende muito de como você quiser programar essa leitura, pra facilitar eu provavelmente faria as linhas colunas como no sudoku e criaria funcoes usando o fseek e fsetpos pra posicionar o ponteiro do stream exatamente onde você vai precisar ler/escrever no arquivo..

 

É verdade, append mode uaria "a", mas não é o caso aqui: de nada serve o passado do tabuleiro. Não há memória ou função em guardar isso. Apenas se deve gravar o tabuleiro como ficou depois de cada movimento, para que se possa reiniciar QUALQUER jogo interrompido. É só isso. Não tem propósito algum em gravar os movimentos, já que não está previsto voltar o jogo.

 

Se fosse o caso --- e pode ser uma coisa legal no jogo porque assim se poderia voltar N movimentos e tentar uma solução melhor --- o mais óbvio seria o simples: a jogada NH na posição N. E assim era só fazer as contas:

  • cada jogada usa apenas 81 posições e cada uma tem um dígito. Basta meio byte para cada posição, usando BCD, comum desde os anos 60.
  • com preguiça? basta usar um byte para cada posição.
  • quer controlar o tempo? Pode ser legal, já que é um diferencial importante nesse jogo. Então que tal 100 bytes para cada jogada? Sem pensar muito, cada jogada coloca um número e só cabem 81 números, certo? Então a jogada 32 pode ficar na posição 32. 
  • para não fazer contas, deixa o registro zero em branco. Então por exemplo a segunda jogada estaria em SEEK_SET, o início do arquivo em C, mais 2 vezes o tamanho do registro, que seriam esses 41, 81 ou 100 bytes ou como queira gravar isso. E o tamanho total não poderia nunca passar de 81 vezes isso...
  • Assim um fseek() e um fread() e leria o tabuleiro para qualquer posiçõa do jogo
  • E no início poderia deixar o tempo desde o inicio e desde a jogada anterior, para guiar o cara num jogo que tenha um tempo máximo a cumprir, tipo alguns minutos para colocar um certo número de peças

No entanto isso seria uma frescura a mais e não está no enunciado.

 

De volta ao enunciado:

 

Em 01/01/2021 às 22:23, Visitante disse:

Após cada jogada válida, o tabuleiro deve ser gravado no arquivo que foi lido no início do programa. Dessa forma, sempre que o programa começa, o usuário volta à mesma situação em que estava na última vez que jogou

 

Como vê é só isso. Tem que salvar a cada jogada para permitir o reinício. Nada mais.

 

1 hora atrás, DiogoM12 disse:

GetValue(int line_pos, int col_pos, FILE *pfile)

{

    fseek (pfile , (line_pos * col_pos) * 2 - 1 , SEEK_SET );

    return fread (ou fgetc, ou qualquer outra coisa pra ler do ponteiro)

}

 

1 hora atrás, DiogoM12 disse:

deve funcionar, nao testei nada, mas o caminho é por ai.

 

Isso que escreveu funciona sim. Mas o caminho não é por aí. Apenas deve ler o tabuleiro no início, perguntando o nome do arquivo porque pode ter vários jogos salvos. 

A partir daí é o que está escrito lá: salva o estado para poder reiniciar se parar. E segue o jogo.

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Não é questao de guardar os movimentos, você precisa de funcoes pra ler e escrever cada posicao individual no arquivo, funcoes pra ler de 3 em 3 (linha e coluna) e funcoes pra ler de 9 em 9 (linha e coluna) pra conseguir satisfazer todas as condicoes do jogo.

 

Fazendo as funcoes pra cada posicao fazer o de 3 em 3 ou 9 em 9 fica fácil.

 

Sem contar que o input do usuario (linha, coluna, valor) já seria exatamente o que precisa pra funcao escrever/ler do arquivo. Eu só dei o exemplo de ler , mas poderia muito bem ser o de escrever também.

 

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

2 minutos atrás, DiogoM12 disse:

Não é questao de guardar os movimentos, você precisa de funcoes pra ler e escrever cada posicao individual no arquivo, funcoes pra ler de 3 em 3 (linha e coluna) e funcoes pra ler de 9 em 9 (linha e coluna) pra conseguir satisfazer todas as condicoes do jogo


Não, não precisa. No Sudoku e como descrito no enunciado a posição é irrelevante: apenas grave o tabuleiro como ficou a cada movimento e leia o próximo comando. E se for sair já estará tudo certo. Se for outro movimento apenas continue no loop: coloque o movimento na tela e grave o tabuleiro no disco. Essa é a mecânica.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@DiogoM12  sim , a criação de uma GUI é bem difícil ,  mas pelo que escrevi ali acima não diz nada sobre criar GUI ,  apenas que pode usar a biblioteca windows.h para detectar a posição do mouse no console e fazer as jogadas ,  mas pelo enunciado as jogadas sao feitas pelo teclado mesmo .

Link para o comentário
Compartilhar em outros sites

4 horas atrás, arfneto disse:


Não, não precisa. No Sudoku e como descrito no enunciado a posição é irrelevante: apenas grave o tabuleiro como ficou a cada movimento e leia o próximo comando. E se for sair já estará tudo certo. Se for outro movimento apenas continue no loop: coloque o movimento na tela e grave o tabuleiro no disco. Essa é a mecânica.

 

você ja jogou sudoku? a cada momento que você inserir um novo numero no jogo você tem que calcular a linha e a coluna inteira pra ver se o resultado está correto pra você conseguir "zerar" , logico que a pessoa pode fazer manualmente como se tivesse fazendo no papel, mas não seria mais interessante se o programa conseguisse fazer isso automaticamente pra indentificar se o resultado final está certo ou nao? Acho que uma das intenções do programa é essa. Aprender a lidar com a manipulacao de dados no arquivo.

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

 

3 horas atrás, DiogoM12 disse:

Acho que uma das intenções do programa é essa. Aprender a lidar com a manipulacao de dados no arquivo

 

Não, não é. Entenda que a única razão de gravar no arquivo é poder começar de onde parou, a menos da versão "bonus" que eu expliquei, que permitiria navegar pelas jogadas.

 

Se leu de fato o que eu expliquei e acompanhou as contas pode ter concluído que mesmo assim é bobagem manipular o arquivo. São no máximo 9x9 jogadas que podem ser mantidas facilmente em 41 ou 81 bytes por jogada. Isso quer dizer que um tabuleiro não pode custar mais que 9*9*9*9 bytes ou metade disso usando BCD. Pouco mais de 6K bytes. Então se pode gravar o jogo inteiro a cada vez em uma fração de segundo e de nada serve ficar buscando a jogada usando a conta óbvia de SEEK_SET + N * sizeof(tabuleiro). Não há razão para otimizar algo tão pequeno.

 

3 horas atrás, DiogoM12 disse:

a cada momento que você inserir um novo numero no jogo você tem que calcular a linha e a coluna inteira pra ver se o resultado está correto pra você conseguir "zerar" , logico que a pessoa pode fazer manualmente como se tivesse fazendo no papel, mas não seria mais interessante se o programa conseguisse fazer isso automaticamente pra indentificar se o resultado final está certo ou nao?

 

Em 01/01/2021 às 22:23, Visitante disse:

O programa deve ter um laço principal que consiste em:

apresenta o tabuleiro – caso o tabuleiro esteja completo e correto (fim do jogo), esse fato deve ser informado

 

Como vê, não se trata de "ser mais interessante" ou "fazer automaticamente", é o básico do enunciado.

 

Primeiro isso e depois lê o comando se o jogo não terminou.

 

Os comandos

  • g para gravar
  • l para ler
  • s para sair, que pode gravar também o estado final do tabuleiro
  • uma jogada, que é um número entre 1 e 9 inclusive, e a coordenada. Claro que o enunciado é meio bobinho e diz para digitar o numero e depois a linha e coluna, mas nada impede que o programa aceite os 3 digitos ou uma coordenada com letras para facilitar. Algo tipo linha-coluna-valor por exemplo seria bem mais satisfatório para o cara que está jogando, certo? Clicar na célula não acrescenta muito...  Exceto talvez clicar num bloco de números e depois na célula, para não ter que soltar o mouse. Mas o teclado numérico parece mais ágil pra jogar

O tabuleiro

como esse  que você pode comprar

Tem 9 linhas, nove colunas e os nove sub-tabuleiros de 3x3 células
image.png.357f5f7962abd6bb847ce043624e2ef3.png

 

As tais regras:

  • cada linha tem que ter os números de 1 a 9 sem repetir
  • cada coluna tem que ter os números de 1 a 9 sem repetir
  • cada sub-tabuleiro 3x3 tem que ter os números de 1 a 9 sem repetir
  • o jogo começa com alguns números já posicionados e vem em jornais e revistas. 18 números parece que é um início comum. Eis um exemplo resolvido e que aparentemente vinha com 23 pistas (os números em preto)

    image.png.980958062a527413b3b4656bd5ec647a.png
  • Claro que pode começar com um tabuleiro vazio mas não sei se teria sentido afinal...
  • Para o jogo acho que o mais legal seria comprar uma revista e criar os arquivos correspondentes e sortear na hora

 

 

 

 

 

 

 

 

 

 

 

 

Uma maneira de começar algo assim

 

Para terminar logo e começar a jogar (ou entregar o trabalho) o mais simples é seguir o enunciado e não inventar muito.
 

Escreva em torno dos dados....

 

O ovo ou a galinha?
 

Claro que um tabuleiro não deveria vir do nada então é bom ter um ou dois para começar, como esse aí de cima. E então antes de ler precisa poder gravar e mostrar um jogo.

 

Como mostrar um trem desses?

De qualquer jeito, desde que dê para entender e começar a testar ainda hoje :) Vendo o tabuleiro comum vem algo assim à mente:
 

Vou mostrar uma maneira de fazer isso com simplicidade e alguma segurança.

 

E depois se pode refinar a interface, já que ela nada tem a ver com as regras ou a mecânica. Ou ao menos não deveria ter. 

 

Prosseguindo: uma tela ingênua:

image.png.aa0963b1b5de6c58ace1fa379ae434a0.png

Bem bobinho, mas não precisa de gráficos e tem os 81 números e tem as marcas parecidas com um tabuleiro comum separando os grids 3x3.

 

Rodando o programa as linhas aparecem contínuas. Esse picotado é porque o editor de texto separa linha a linha. Não ganharia nenhum concurso mas dá pra programar em meia hora então...

 

É claro um porre ficar alinhando essas coisas em um programa e vai levar uma vida pra alinhar e outra vida a cada mudança. Então o mais ingênuo e simples é usar um arquivo e digitar direto nele os códigos das letras, usando o popular recortar e colar direto no editor de texto. Claro, para quem tem Linux e sabe usar o editor vi é um passeio criar algo assim, mas dá pra usar o bloco de notas no Windows e uma dose de paciência. Ou qualquer IDE. E assim pode trocar as linhas por 'x' ou '\' e '/' ou asteriscos ou sei lá. Sim, vou deixar um exemplo com essas letras aí. ;) 

 

Para facilitar a vida use um marcador para colocar as peças no tabuleiro, algo como um 'X' não seria novidade. Assim basta ler o arquivo e ir inserindo as peças que leu do arquivo. De um arquivo vem o gabarito e de outro as peças. Um tem 14 linhas, ou pelo menos 9 linhas, certo? E o outro no máximo 81 peças. Inserir cor seria trivial, e poderia ficar como nos jogos online. Mas não é o caso agora.

 

Uma função dessas
 

int         boxL(const char*,const char*);

 

Uma função assim para fazer o óbvio:
 

    boxL("sdkbox.txt", sudoku); // mostra na tela

 

o primeiro argumento é o tabuleiro, o segundo tem as peças, e o resultado seria como está na tela: o tabuleiro montado.

 

Como gravar um arquivo?
 

int         grava_tabuleiro(const char*,const char*);

 

sem surpresas:
 

    int res = grava_tabuleiro("1234567890X987654321", "teste.txt");

 

Sim, uma string com as peças. Como diz o enunciado zero fica em branco, um a nove é o número. O programa é nosso e podemos definir todo o resto. Tanto faz.

 

Exemplo para gravar o tabuleiro que mostrei:
 

    res = grava_tabuleiro("\
003050072\
500400030\
000000109\
000000900\
851xxx7xx\
000020000\
084700000\
300100008\
20900050",
	"exemplo.txt");

 

Deixando uma linha com 'x' só para mostrar que uma solução genérica permite que desenhe o tabuleiro e as peças de qualquer jeito, sem ter que compilar o programa. Claro, argumentos na linha de comando seriam bem normais aí...

 

Claro que em C se pode continuar qualquer string terminando a linha com '\' e assim fica trivial conferir e copiar da revista

 

Como ficaria nessa interface bobinha?

 

Precisa ler isso de volta. Difícil? Não, não deve ser difícil ler um arquivo de uma linha.
 

char*       le_tabuleiro(const char*);

 

Claro, lê de um arquivo e retorna a string com o tabuleiro. E aquela função boxL() mostra na tela... Algo assim
 

    char* sudoku = le_tabuleiro("exemplo.txt");

 

Pois é. Gravamos o tabuleiro nesse arquivo então deve ser possível ler de volta e chamar a função e ver na tela... Claro que o tabuleiro é o mesmo. Claro que não há razão pra se preocupar com eficiência ou algo assim.
 

    boxL("sdkbox.txt", sudoku); // mostra na tela

 

Algo assim basta. Será que serve?

image.png.05748cb74c2f43e21f5f99d191516c57.png

 

Pois é. Dá pra ler e está certinho. Da primeira vez. Talvez fosse melhor ter mais linhas separando, mas para escrever rapidinho já dá pra testar e implementar a lógica que falta pra terminar o programa. Já é boa parte dele afinal. 

 

O trecho exemplo que lê, grava e mostra o tabuleiro acima:

 

    // o exemplo do post
    res = grava_tabuleiro("\
003050072\
500400030\
000000109\
000000900\
851xxx7xx\
000020000\
084700000\
300100008\
20900050",
        "exemplo.txt");

    sudoku = le_tabuleiro("exemplo.txt");
    boxL("sdkbox.txt", sudoku); // mostra na tela
    free(sudoku); // nao vai usar mais

 

A partir daí seria só:

  • gravar o tabuleiro, trivial porque a função é a mesma
  • verificar se o jogo terminou. trivial porque é só manipular a string
  • ler o comando
  • se for uma jogada gravar o valor e gravar o novo arquivo

Claro que há muitas maneiras de escrever isso. Só estou mostrando isso porque demorou muito mais para postar aqui com esse editor terrível do forum do que escrever o programa de exemplo.

 

E o arquivo do tabuleiro? 

 

Como eu disse, basta usar control-c control-v e digitar os códigos das letras que quer usar. Veja por exemplo o que eu usei

mas pode ser apenas asteriscos, ou apenas os 81 caracteres e pronto.

 

Mas como eu fiz é mais flexível: Esse seria o "sdkbox.txt" que eu digitei no vi copiando da tabela:
 

201 205 205 205 205 205 205 205 205 205 209 205 205 205 205 205 205 205 205 205 209 205 205 205 205 205 205 205 205 205 187
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
199 196 196 196 196 196 196 196 196 196 197 196 196 196 196 196 196 196 196 196 197 196 196 196 196 196 196 196 196 196 182
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
199 196 196 196 196 196 196 196 196 196 197 196 196 196 196 196 196 196 196 196 197 196 196 196 196 196 196 196 196 196 182
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
186 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 179 032 088 032 032 088 032 032 088 032 186
200 205 205 205 205 205 205 205 205 205 207 205 205 205 205 205 205 205 205 205 207 205 205 205 205 205 205 205 205 205 188

 

Claro que 032 é um espaço, e tem muitos. 088 é o 'X' maiúsculo e é o marcador para as peças. Adivinha quantos 'X' tem? 81. Quantas linhas tem? 13 claro. Podiam ser só 9. Mas assim posso usar tabuleiros de outros tamanhos ou com outros propósitos: na hora de mostrar é só ir pondo as peças, como uma criança faria para copiar da revista para o tabuleiro de madeira.

 

E usando control-C control-v leva minutos, em especial no vi.

 

E como gravar um tabuleiro?
 

int grava_tabuleiro(const char* tab, const char* arquivo)
{
    if (tab == NULL) return -1;
    if (arquivo == NULL) return -2;
    FILE* out = fopen(arquivo, "w");
    if (out == NULL) return -3;
    int res = fputs(tab, out);
    fclose(out);
    return res;
};

 

Nada especial, certo? retorna negativo ou o número de peças. Nem 10 linhas. Tem que gravar para poder ler...

 

E como ler?
 

char* le_tabuleiro(const char* tab)
{
    if (tab == NULL) return NULL;
    // um tabuleiro tem 9x9 valores entre 0 e 9
    // 0 indica sem peca na posicao
    FILE* in = fopen(tab, "r");
    if (in == NULL) return NULL;
    char* p = malloc(SUDOKU_TAM);
    if (p == NULL) return NULL;
    fgets(p, SUDOKU_TAM, in);
    if (strlen(p) > 1)
        if (p[strlen(p) - 1] == '\n')
            p[strlen(p) - 1] = 0;
    return (char*)p;
};

 

Pois é: mais umas 10 linhas: SUDOKU_TAM vale quanto? 82, claro. Assim fica mais fácil de digitar.

 

E pra mostrar isso?
 

int         boxL(const char* gabarito, const char* tabuleiro )
{
    if (gabarito == NULL) return -1;
    if (tabuleiro == NULL) return -2;
    FILE* grade = fopen(gabarito, "r");
    if (grade == NULL) return -1;
    const char* mascara = "%d%c";
    const char marca = 'X';
    int res = 0;
    unsigned val = 0;
    unsigned delim = 0;
    unsigned N = strlen(tabuleiro);
    unsigned usadas = 0;
    while( 1 )
    {
        res = fscanf( grade, mascara, &val, &delim );
        if (res != 2)
        {
            fclose(grade);
            return 0;
        };
        // ok: leu um valor. Se for um 'X' pega
        // a proxima peca
        if (val == marca)
        {
            if (usadas >= N)
            {
                val = ' '; // ja colocou todas as pecas
            }
            else
            {
                val = tabuleiro[usadas];
                // so para o sudoku: apenas de 1 a 9
                if ((val <= '0') || (val > '9')) val = ' ';
                usadas += 1;
            }
        };
        if ( delim != '\n' )
            printf("%c", val );
        else
            printf("%c\n", val );
    };  // while()
    return 0;
}

 

Um loop, 3 if. Basta isso. Lê e encaixa as peças no tabuleiro. Assim pode editar o tabuleiro e as peças sem mexer no programa. Mesmo que o tabuleiro esteja vazio, porque o enunciado diz que ele pode estar.

 

Então um programa que preenche aquele tabuleiro, grava em disco, lê de volta e põe na tela para conferir seria algo como
 

int main(void)
{
    int res = 0;
    char* sudoku = NULL;
    unsigned pagina = GetConsoleOutputCP();
    SetConsoleOutputCP(437); // para as linhas do tabuleiro
    // o exemplo do post
    res = grava_tabuleiro("\
003050072\
500400030\
000000109\
000000900\
851xxx7xx\
000020000\
084700000\
300100008\
20900050",
        "exemplo.txt");
    if (res < 0)
    {
        printf("grava() retornou %d\n", res);
        return -1;
    };

    sudoku = le_tabuleiro("exemplo.txt");
    if (sudoku == NULL) return -1;
    if (strlen(sudoku) == 0) return -2;
    if (strlen(sudoku) > SUDOKU_TAM) sudoku[SUDOKU_TAM] = 0; // trunca
    boxL("sdkbox.txt", sudoku); // mostra na tela
    free(sudoku); // nao vai usar mais
    SetConsoleOutputCP(pagina); // restaura
    return 0;
}

 

Escrevendo em torno dos dados fica fácil de ler: grava o arquivo com o tabuleiro inicial, para poder ler. Lê e mostra na tela para comparar com o que copiamos da internet...

 

Essa não é a solução para o enunciado. Só estou mostrando uma maneira segura de escrever coisas assim. E que deu certo da primeira vez, ao menos até o que eu testei que foi de fato quase nada :D . Em acho que uma hora.

 

Como eu disse, o simples seria ler os 3 parâmetros na linha de comando: o arquivo inicial, o gabarito do tabuleiro e o total de peças.

 

Eis o programa "todo" em C
 

Spoiler




#define     SUDOKU_TAM 82

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <windows.h> 

int         boxL(const char*,const char*);
int         grava_tabuleiro(const char*,const char*);
char*       le_tabuleiro(const char*);

int main(void)
{
    int res = 0;
    char* sudoku = NULL;
    unsigned pagina = GetConsoleOutputCP();
    SetConsoleOutputCP(437); // para as linhas do tabuleiro
    // o exemplo do post
    res = grava_tabuleiro("\
003050072\
500400030\
000000109\
000000900\
851xxx7xx\
000020000\
084700000\
300100008\
20900050",
        "exemplo.txt");
    if (res < 0)
    {
        printf("grava() retornou %d\n", res);
        return -1;
    };

    sudoku = le_tabuleiro("exemplo.txt");
    if (sudoku == NULL) return -1;
    if (strlen(sudoku) == 0) return -2;
    if (strlen(sudoku) > SUDOKU_TAM) sudoku[SUDOKU_TAM] = 0; // trunca
    boxL("sdkbox.txt", sudoku); // mostra na tela
    free(sudoku); // nao vai usar mais
    SetConsoleOutputCP(pagina); // restaura
    return 0;
}

int         boxL(const char* gabarito, const char* tabuleiro )
{
    if (gabarito == NULL) return -1;
    if (tabuleiro == NULL) return -2;
    FILE* grade = fopen(gabarito, "r");
    if (grade == NULL) return -1;
    const char* mascara = "%d%c";
    const char marca = 'X';
    int res = 0;
    unsigned val = 0;
    unsigned delim = 0;
    unsigned N = strlen(tabuleiro);
    unsigned usadas = 0;
    while( 1 )
    {
        res = fscanf( grade, mascara, &val, &delim );
        if (res != 2)
        {
            fclose(grade);
            return 0;
        };
        // ok: leu um valor. Se for um 'X' pega
        // a proxima peca
        if (val == marca)
        {
            if (usadas >= N)
            {
                val = ' '; // ja colocou todas as pecas
            }
            else
            {
                val = tabuleiro[usadas];
                // so para o sudoku: apenas de 1 a 9
                if ((val <= '0') || (val > '9')) val = ' ';
                usadas += 1;
            }
        };
        if ( delim != '\n' )
            printf("%c", val );
        else
            printf("%c\n", val );
    };  // while()
    return 0;
}

int grava_tabuleiro(const char* tab, const char* arquivo)
{
    if (tab == NULL) return -1;
    if (arquivo == NULL) return -2;
    FILE* out = fopen(arquivo, "w");
    if (out == NULL) return -3;
    int res = fputs(tab, out);
    fclose(out);
    return res;
};

char* le_tabuleiro(const char* tab)
{
    if (tab == NULL) return NULL;
    // um tabuleiro tem 9x9 valores entre 0 e 9
    // 0 indica sem peca na posicao
    FILE* in = fopen(tab, "r");
    if (in == NULL) return NULL;
    char* p = malloc(SUDOKU_TAM);
    if (p == NULL) return NULL;
    fgets(p, SUDOKU_TAM, in);
    if (strlen(p) > 1)
        if (p[strlen(p) - 1] == '\n')
            p[strlen(p) - 1] = 0;
    return (char*)p;
};

 

 

O autor do post deixou o forum, mas de todo modo não vou  postar uma solução. Mas acho que ficou claro um caminho e o que falta.

 

 

  • Obrigado 1
  • Amei 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...