unit UKarnaugh;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Spin, Grids, AxCtrls, OleCtrls, vcf1, Outline, DirOutln,
FileCtrl, ExtCtrls, Math, Buttons, Mask, ShellApi;

type
TFKarnaugh = class(TForm)
StringGrid1: TStringGrid;
Panel1: TPanel;
LabelDigiteQuantidadeParametros: TLabel;
Label3: TLabel;
LabelValoracoes: TLabel;
SpinEditNumeroVariaveis: TSpinEdit;
Panel2: TPanel;
EditValoracoes: TMaskEdit;
Panel3: TPanel;
LabelFormula: TLabel;
LabelFormulaSimplificada: TLabel;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
EFormulaGerada: TEdit;
EFormulaSimplificada: TEdit;
Button1: TButton;
Button2: TButton;
procedure BitBtn3Click(Sender: TObject);
procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure SpinEditNumeroVariaveisChange(Sender: TObject);
procedure EditValoracoesKeyPress(Sender: TObject; var Key: Char);
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure EditValoracoesChange(Sender: TObject);
procedure EditValoracoesExit(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
private
procedure GeraNovoMapa;
procedure GeraFormula;
public
NumeroVariaveis : integer;
function Potencia(Base, Expoente : integer) : integer;
end;

var
FKarnaugh: TFKarnaugh;

implementation

uses UCodigoGray, UTabelaVerdade;

{$R *.DFM}

function TFKarnaugh.Potencia(Base, Expoente : integer) : integer;
//Funcao Matematica de Potencia
var X : integer;
begin
Result := 1;
for X := 1 to Expoente do Result := Result * Base;
end;

procedure TFKarnaugh.GeraNovoMapa;
(* É gerado um mapa zerado quando o programa inicia e quando o numero de
variaveis é alterado *)
var X,Y,Z:integer;
begin

NumeroVariaveis := SpinEditNumeroVariaveis.Value;

//Esta linha define a largura da coluna de acordo c/ a quantidade de variaveis
StringGrid1.DefaultColWidth := 6 * ((NumeroVariaveis + 1) div 2) + 4;

//Este trecho define o número de linhas e colunas do mapa
if NumeroVariaveis = 1 then
begin
StringGrid1.ColCount := 2;
StringGrid1.RowCount := 3;
end
else
if odd(NumeroVariaveis) then
begin
StringGrid1.ColCount := 1 + Potencia(2, (NumeroVariaveis + 1) div 2);
StringGrid1.RowCount := 1 + (StringGrid1.ColCount - 1) div 2;
end
else
begin
StringGrid1.ColCount := 1 + Potencia(2, NumeroVariaveis div 2);
StringGrid1.RowCount := StringGrid1.ColCount;
end;

//Este trecho zera a entrada dos valores da fórmula
EditValoracoes.Text := '';
EditValoracoes.MaxLength := Potencia(2, NumeroVariaveis);
for X := 1 to EditValoracoes.MaxLength do
EditValoracoes.Text := EditValoracoes.Text + '0';

//Este trecho zera as células da tabela ref. aos valores da fórmula
for X := 1 to StringGrid1.ColCount - 1 do
for Y := 1 to StringGrid1.RowCount - 1 do
StringGrid1.Cells[X,Y] := '0';

//Estes algoritmos estão sendo chamados em outro arquivo
FTabelaVerdade.GeraTabelaVerdade;
FCodigoGray.GeraCodigoGray;

{ Este trecho preenche as células cinzas da tabela com as valorações das
variáveis }
Z := 0;
if NumeroVariaveis = 1 then
begin
StringGrid1.Cells[0,1] := '0';
StringGrid1.Cells[0,2] := '1';
STringGrid1.Cells[1,0] := '';
StringGrid1.Cells[2,0] := '';
end
else
for X := 1 to StringGrid1.RowCount - 1 do
begin
StringGrid1.Cells[0,X] := copy(FCodigoGray.ListBox1.Items[Z],0,NumeroVariaveis div 2);
for Y := 1 to StringGrid1.ColCount - 1 do
begin
if X = 1 then
StringGrid1.Cells[Y,0] := copy(FCodigoGray.ListBox1.Items[Y - 1], NumeroVariaveis div 2 + 1,
NumeroVariaveis - NumeroVariaveis div 2);
inc(Z);
end;
end;

end;

procedure TFKarnaugh.GeraFormula; //Procedure que Gera a Formula Simplificada

var
X,Y,Z,NumeroDiferencas,IndiceDiferenca : integer;
ListaValoracoes, ListaSimplificada : TStringList;
SubFormula : string;

const
ou = 'v';
e = '^';
nao = #$AC; //Caracter 172

function Tamanho(S:string) : integer;
var X : integer;
begin
Result := 0;
for X := 1 to length(S) do if S[X] <> #$20 then inc(Result);
end;

function TraduzLista : String;
var
X,Y : integer;
Formula : string;
begin
(* Transforma as valoracoes das variaveis de ZEROS e UNS armazenada na lista
de strings para uma saida com as variaveis proposicionais nomeadas a partir da
letra P com interpretacoes de VERDADEIRO ou FALSO, incluindo na formula os
símbolos ( , ) , ^ , v e ¬ quando necessário *)
for X := 0 to ListaValoracoes.Count - 1 do
begin
if (ListaValoracoes.Count > 1) and (length(ListaValoracoes[X])>1) then
Formula := Formula + '('; //Insere o (
for Y := 1 to length(ListaValoracoes[X]) do
begin
if Y > 1 then Formula := Formula + E; //Insere o ^
if ListaValoracoes[X][Y] = '0' then Formula := Formula + Nao; //Insere o ¬
Formula := Formula + chr(111 + Y); //Aqui é nomeada a variável
end;
if ListaValoracoes.Count > 1 then
begin
if length(ListaValoracoes[X])>1 then Formula := Formula + ')'; //Insere o )
if X < ListaValoracoes.Count - 1 then Formula := Formula + Ou; //Insere o ^
end;
end;
Result := Formula;
end;

begin
ListaValoracoes := TStringList.Create; //Cria uma lista de strings vazia

(* Quando a interpretacao da formula for 1 de acordo com o mapa, então é
adicionado à lista de strings a concatenacao das valoracoes das variaveis da
coluna com as valoracoes da variavel da linha correspondente no mapa, gerando
um resultado na forma de uma string de zeros e uns. *)
for X := 1 to StringGrid1.ColCount - 1 do
for Y := 1 to StringGrid1.RowCount - 1 do
if StringGrid1.Cells[X,Y] = '1' then
ListaValoracoes.Add(StringGrid1.Cells[X,0] + StringGrid1.Cells[0,Y]);
EFormulaGerada.Text := TraduzLista;

(* Algoritmo para criar a fórmula simplificada. É percorrida a lista de string
comparando as linhas de duas em duas - caracter por caracter - para localizar
aquelas em que as valoracoes diferem por apenas uma variavel. Quando
encontrada, entao na primeira linha a variável é substituída por um espaço em
branco e a segunda linha é eliminada. *)
{X := 0;
while X < ListaValoracoes.Count do //X faz a contagem da primeira string
begin
Y := X;
inc(Y);
while Y < ListaValoracoes.Count do //Y faz a contagem da segunda string. Por isso comeca a partir de X e nao de zero.
begin
IndiceDiferenca := 0;
Z := 0;
while (Z < length(ListaValoracoes[X])) do //Z faz a contagem de caracteres da string para poder compará-los
begin
inc(Z);
if ListaValoracoes[X][Z] <> ListaValoracoes [Y][Z] then
if IndiceDiferenca = 0 then //Se ainda não foi encontrado diferença
IndiceDiferenca := Z //É armazenado o índice onde a diferença foi encontrada
else //Se já tinha sido encontrado alguma diferença então há mais de uma diferença
begin
IndiceDiferenca := 0; //É anulado o índice onde a diferença foi encontrada
break; //Se encontrada mais de duas diferencas interrompe o laço
end;
end;
if IndiceDiferenca <> 0 then //Se encontrada uma unica diferenca...
begin
SubFormula := ListaValoracoes[X];
(* No lugar da variavel da primeira linha em que a valoração difere é
adicionado um espaco em branco *)
SubFormula[IndiceDiferenca] := #$20;
ListaValoracoes[X] := SubFormula;
ListaValoracoes.Delete(Y); //A outra linha é excluída
end;
end;
inc(X);
end;}

ListaValoracoes.Free; //Elimina a lista de strings
end;

procedure TFKarnaugh.BitBtn3Click(Sender: TObject);
begin
Close
end;

procedure TFKarnaugh.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Coluna, Linha: Longint;
ListaString : TStringList;
begin
//Procedimento para que quando o mouse clicar no mapa, inverta as valorações
with StringGrid1 do
begin
MouseToCell(X, Y, Coluna, Linha);
if (Coluna>0) and (Linha>0) then
begin
if Cells[Coluna, Linha] = '0' then
Cells[Coluna, Linha] := '1'
else
Cells[Coluna, Linha] := '0';
end;

(* Neste trecho, a entrada é atualizada de acordo com as alteracoes feitas
no mapa acima *)
ListaString := TStringList.Create;
for Coluna := 1 to ColCount - 1 do
for Linha := 1 to RowCount - 1 do
ListaString.Add('');
for Coluna := 1 to ColCount - 1 do
for Linha := 1 to RowCount - 1 do
ListaString[FTabelaVerdade.ListBox2.Items.IndexOf(StringGrid1.Cells[Coluna,0] + StringGrid1.Cells[0,Linha])] := Cells[Coluna,Linha];
EditValoracoes.Text := '';
for Coluna := 0 to ListaString.Count - 1 do
EditValoracoes.Text := EditValoracoes.Text + ListaString[Coluna];
ListaString.Free;

end
end;

procedure TFKarnaugh.SpinEditNumeroVariaveisChange(Sender: TObject);
begin
GeraNovoMapa;
end;

procedure TFKarnaugh.EditValoracoesKeyPress(Sender: TObject; var Key: Char);
begin
if not (Key in ['0','1',#8]) then Key:=#0
end;

procedure TFKarnaugh.Button1Click(Sender: TObject);
begin
FCodigoGray.Show;
end;

procedure TFKarnaugh.FormShow(Sender: TObject);
begin
GeraNovoMapa;
end;

procedure TFKarnaugh.EditValoracoesChange(Sender: TObject);
var X,Y : integer;
begin
//Cada vez que a entrada for alterada, é atualizado o mapa
for X := 1 to StringGrid1.RowCount - 1 do
for Y := 1 to StringGrid1.ColCount - 1 do
begin
StringGrid1.Cells[Y,X] := copy(EditValoracoes.Text,
FTabelaVerdade.ListBox2.Items.IndexOf(StringGrid1.Cells[Y,0] + StringGrid1.Cells[0,X])+1,1);
end;

GeraFormula;
end;

procedure TFKarnaugh.EditValoracoesExit(Sender: TObject);
//Completa com zeros a entrada de valores se ela for preenchida incompleta.
var X : integer;
begin
for X := length(EditValoracoes.Text) + 1 to EditValoracoes.MaxLength do
EditValoracoes.Text := EditValoracoes.Text + '0';
end;

procedure TFKarnaugh.Button2Click(Sender: TObject);
begin
FTabelaVerdade.Show;
end;

procedure TFKarnaugh.BitBtn2Click(Sender: TObject);
const
page = 'http://www.cic.unb.br/~alan/';
begin
if ShellExecute(0, 'open', page, nil, nil, Sw_SHowNormal) <= 32 then
MessageBox(0, 'Erro', 'Error', 0)
end;

end.