我在 CLIPSJNI 中有一个 AI 项目,名为“购买割草机的建议”
我有两个 .CLP 文件:konowledgebase.clp、control.clp 和 1 个 java 文件:Ksiarki.java
知识库.clp:
(defrule philips ""
(naped ENGINE)
(mechanizm TRADYCYJNY)
(dodatki KOSZ)
(cena DO_500)
=>
(assert(result
(producent "Philips")
(typ "XDD3")
(rodzaj "spalinowa"))
(cena "450")))
控制.clp:
(deftemplate currentState
(slot name (default none))
(slot state (default middle))
(slot text)
(slot answerType (default radioButton))
(multislot selected)
(multislot answers)
)
(deftemplate result
(slot producent (type STRING))
(slot typ (type STRING))
(slot rodzaj (type STRING))
(slot cena (type INTEGER))
)
; Startup window
(defrule system-banner ""
=>
(assert (currentState
(text START_TEXT)
(name start)
(state initial)
(answers))
)
)
; Results window
(defrule EndOfQuestions ""
?state<-(currentState)
(end)
=>
(retract ?state)
(assert (currentState
(text NO_RESULTS_END_TEXT)
(state final)
))
)
; Pytanie o powierzchnie
(defrule selectPowierzchnia ""
?state<-(currentState)
(not(pytaniePowierzchnia))
=>
(retract ?state)
(assert (pytaniePowierzchnia))
(assert (currentState
(name powierzchnia)
(text SELECT_PYTANIE_POWIERZCHNIA)
(answerType checkBox)
(answers 10 20 30 40 50 100 200 300 400 500 1000 2000 3000 4000 5000)
(selected)
))
)
; Pytanie o mechanizm tnacy ====== bezsilnikowy ======
(defrule selectMechanizm ""
?state<-(currentState)
(not(pytanieMechanizm))
(powierzchnia)
(naped NOENGINE)
(naped ELECTRIC)
=>
(retract ?state)
(assert (pytanieMechanizm))
(assert (currentState
(name mechanizm)
(text SELECT_PYTANIE_MECHANIZM)
(answerType checkBox)
(answers TRADYCYJNY ROTACYJNY ZYLKOWY WRZECIONOWY BIJAKOWY KARCZUJACY LISTWOWY)
(selected)
))
)
; Pytanie o mechanizm tnacy ====== elektryczny ======
(defrule selectMechanizm ""
?state<-(currentState)
(not(pytanieMechanizm))
(powierzchnia)
(naped ELECTRIC)
(naped ENGINE)
=>
(retract ?state)
(assert (pytanieMechanizm))
(assert (currentState
(name mechanizm)
(text SELECT_PYTANIE_MECHANIZM)
(answerType checkBox)
(answers TRADYCYJNY ROTACYJNY ZYLKOWY WRZECIONOWY BIJAKOWY KARCZUJACY LISTWOWY)
(selected)
))
)
; Pytanie o mechanizm tnacy ====== spalinowy ======
(defrule selectMechanizm ""
?state<-(currentState)
(not(pytanieMechanizm))
(powierzchnia)
(naped ENGINE)
=>
(retract ?state)
(assert (pytanieMechanizm))
(assert (currentState
(name mechanizm)
(text SELECT_PYTANIE_MECHANIZM)
(answerType checkBox)
(answers TRADYCYJNY ROTACYJNY ZYLKOWY WRZECIONOWY BIJAKOWY KARCZUJACY LISTWOWY)
(selected)
))
)
; Pytanie o dodatki
(defrule selectDodatki ""
?state<-(currentState)
(not(pytanieDodatki))
(mechanizm TRADYCYJNY|ROTACYJNY|ZYLKOWY|WRZECIONOWY|BIJAKOWY|KARCZUJACY|LISTWOWY)
=>
(retract ?state)
(assert (pytanieDodatki))
(assert (currentState
(name dodatki)
(text SELECT_PYTANIE_DODATKI)
(answerType checkBox)
(answers MULCZOWANIE KOSZ TARCZA ROZRUSZNIK BLOKADA NAPED NIE)
(selected)
))
)
; Pytanie o cene
(defrule selectCena ""
?state<-(currentState)
(not(pytanieCena))
(dodatki MULCZOWANIE|KOSZ|TARCZA|ROZRUSZNIK|BLOKADA|NAPED)
=>
(retract ?state)
(assert (PytanieCena))
(assert (currentState
(name cena)
(text SELECT_PYTANIE_CENA)
(answerType checkBox)
(answers 10 20 30 40 50 100 200 300 400 500 1000 2000 3000 4000 5000)
(selected)
))
(assert (end))
)
(defrule suma_pow_init
?i<-(powierzchnia ?p $?rp)
(not(suma_pow ?))
=>
(retract ?i)
(assert(powierzchnia $?rp))
(assert(suma_pow ?p)))
(defrule sumuj
?i<-(powierzchnia ?p $?rp)
?j<-(suma_pow ?s $?rs)
=>
(retract ?i ?j)
(assert(powierzchnia $?rp))
(assert(suma_pow (+ ?p ?s))))
(defrule nast_pyt_pow1
(powierzchnia)
(suma_pow ?s)
(test(< ?s 150))
=>
(assert(naped NOENGINE))
(assert(naped ELECTRIC)))
(defrule nast_pyt_pow2
(powierzchnia)
(suma_pow ?s)
(test(>= ?s 150))
(test(< ?s 750))
=>
(assert(naped ELECTRIC))
(assert(naped ENGINE)))
(defrule nast_pyt_pow3
(powierzchnia)
(suma_pow ?s)
(test(< ?s 750))
=>
(assert(naped ENGINE)))
(defrule suma_cen_init
?i<-(cena ?c $?rc)
(not(suma_cen ?))
=>
(retract ?i)
(assert(cena $?rc))
(assert(suma_cen ?c)))
(defrule sumuj_ceny
?i<-(cena ?c $?rc)
?j<-(suma_cen ?s $?rs)
=>
(retract ?i ?j)
(assert(cena $?rc))
(assert(suma_cen (+ ?c ?s))))
(defrule nast_pyt_cena1
(cena)
(suma_cen ?s)
(test(< ?s 450))
=>
(assert(cena MALA)))
(defrule nast_pyt_cena1
(cena)
(suma_cen ?s)
(test(< ?s 500))
(test(>= ?s 450))
=>
(assert(cena DO_500)))
(defrule nast_pyt_cena2
(cena)
(suma_cen ?s)
(test(>= ?s 500))
(test(< ?s 750))
=>
(assert(cena DO_750)))
(defrule nast_pyt_cena3
(cena)
(suma_cen ?s)
(test(>= ?s 750))
(test(< ?s 1500))
=>
(assert(cena DO_1500)))
(defrule nast_pyt_cena4
(cena)
(suma_cen ?s)
(test(>= ?s 1500))
(test(< ?s 3000))
=>
(assert(cena DO_3000)))
(defrule nast_pyt_cena5
(cena)
(suma_cen ?s)
(test(>= ?s 3000))
(test(< ?s 5000))
=>
(assert(cena DO_5000)))
(defrule nast_pyt_cena6
(cena)
(suma_cen ?s)
(test(>= ?s 5000))
(test(< ?s 10000))
=>
(assert(cena DO_10000)))
(defrule nast_pyt_cena7
(cena)
(suma_cen ?s)
(test(>= ?s 10000))
=>
(assert(cena OD_10000)))
Kosiarki.java:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.List;
import java.util.Properties;
import javax.swing.SwingUtilities;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JCheckBox;
import javax.swing.JTextPane;
import javax.swing.JToggleButton;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import CLIPSJNI.Environment;
import CLIPSJNI.FactAddressValue;
import CLIPSJNI.MultifieldValue;
import CLIPSJNI.PrimitiveValue;
import CLIPSJNI.SymbolValue;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import java.util.Comparator;
import javax.swing.table.TableColumn;
public class Kosiarki implements ActionListener
{
private Environment clips;
private Properties properties;
private ButtonGroup answerButtons;
private JTextPane textPane;
private JButton nextButton;
private JPanel answerPanel;
private JTable answersTable;
private String assertedKosiarka;
private String lastAssertedKosiarka="";
public Kosiarki()
{
// okno
JFrame frame=new JFrame("AI Name Project");
frame.getContentPane().setLayout(new GridLayout(3, 1));
frame.setSize(500, 300);
frame.setLocationByPlatform(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// panel - piewszy wiersz tableli 1x3 - do wyswietlania tekstow(glownie pytan)
JPanel textPanel=new JPanel();
textPane=new JTextPane();
textPane.setOpaque(false);
textPane.setEditable(false);
StyledDocument doc=textPane.getStyledDocument();
SimpleAttributeSet center=new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPanel.add(textPane);
// panel - drugi wiersz tableli 1x3 - do wyswietlania checkboksow i radiobuttonow
answerPanel=new JPanel();
answerButtons=new ButtonGroup();
// panel - trzeci i ostatni wiersz tableli 1x3 - do wyswietlania przycisku "next"
JPanel nextButtonPanel=new JPanel();
nextButton=new JButton();
nextButton.setActionCommand("next");
nextButtonPanel.add(nextButton);
nextButton.addActionListener(this);
// wstawiamy na okno wszystkie trzy panele
frame.getContentPane().add(textPanel);
frame.getContentPane().add(answerPanel);
frame.getContentPane().add(nextButtonPanel);
frame.setVisible(true);
// inicjalizacja CLIPS-a
clips=new Environment();
clips.load("control.clp");
clips.load("knowledgeBase.clp");
clips.reset();
clips.run(1);
// ititializing file with properties
properties=new Properties();
loadProperties(new File("configuration.properties"));
// w praktyce pokazujemy okno wstepne
nextUIState();
}
private void nextUIState()
{
answerPanel.removeAll();
// pobieramy aktualny stan UI
MultifieldValue currentStateMultifieldValue=(MultifieldValue)clips.eval("(find-all-facts((?f currentState))TRUE)");
List<FactAddressValue> currentStateList=currentStateMultifieldValue.listValue();
if(currentStateList.isEmpty())
{
return;
}
FactAddressValue currentState=currentStateList.get(0);
// sprawdzamy czy nie "zablokowalismy" sie na "name"
assertedKosiarka=currentState.getFactSlot("name").toString();
if(assertedKosiarka.contentEquals(lastAssertedKosiarka))
{
clips.run(1);
nextUIState();
return;
}
lastAssertedKosiarka=assertedKosiarka;
// ustawienie nazw przycisku "next"/"restart"/"start"
if(currentState.getFactSlot("state").toString().equals("final"))
{
nextButton.setActionCommand("restart");
nextButton.setText(properties.getProperty("RESTART").toString());
// Dodatkowo wypisywanie wynikow
MultifieldValue namesMultifieldValue=(MultifieldValue)clips.eval("(find-all-facts((?f result))TRUE)");
List<FactAddressValue> nameList=namesMultifieldValue.listValue();
if(!nameList.isEmpty())
{
textPane.setText(properties.getProperty("RESULTS_END_TEXT").toString());
System.out.println("pasujące kosiarki:");
String headers[]={
properties.getProperty("PRODUCENT"),
properties.getProperty("TYP"),
properties.getProperty("RODZAJ"),
properties.getProperty("CENA")};
ArrayList<Result> resultList=new ArrayList<Result>();
for(FactAddressValue name : nameList)
{
resultList.add(new Result(
name.getFactSlot("producent").getValue().toString(),
name.getFactSlot("typ").getValue().toString(),
name.getFactSlot("rodzaj").getValue().toString(),
name.getFactSlot("cena").getValue().toString()));
}
Collections.sort(resultList, new ResultComperator());
String data[][]=new String[nameList.size()][4];
int i=0;
for(Result result : resultList)
{
data[i][0]=properties.getProperty(result.getProducent());
data[i][1]=result.getTyp();
data[i][2]=result.getRodzaj();
data[i][3]=result.getCena();
String newName=data[i][0] + "(" + data[i][1] + ")";
System.out.println(newName);
i++;
}
answersTable=new JTable(data, headers);
answersTable.setPreferredScrollableViewportSize(new Dimension(answerPanel.getWidth()- 25, answerPanel.getHeight()- 25));
answersTable.getTableHeader().setReorderingAllowed(false);
answersTable.setEnabled(false);
TableColumn column=new TableColumn();
column=answersTable.getColumnModel().getColumn(0);
column.setMaxWidth(100);
JScrollPane scrollPane=new JScrollPane(answersTable);
answerPanel.add(scrollPane);
}
else
{
textPane.setText(properties.getProperty("NO_RESULTS_END_TEXT").toString());
}
answerPanel.repaint();
return;
}
else if(currentState.getFactSlot("state").toString().equals("initial"))
{
nextButton.setActionCommand("start");
nextButton.setText(properties.getProperty("START").toString());
}
else
{
nextButton.setActionCommand("next");
nextButton.setText(properties.getProperty("NEXT").toString());
}
// ustawienie tekstu(np. pytania)
String text=((SymbolValue)currentState.getFactSlot("text")).stringValue();
textPane.setText(properties.getProperty(text).toString());
// Wstawiamy przyciski(comboboksy/radioboksy)
boolean checkboxes=false;
if(currentState.getFactSlot("answerType").toString().equals("checkBox"))
{
checkboxes=true;
}
answerPanel.removeAll();
answerButtons=!checkboxes ? new ButtonGroup(): null;
MultifieldValue answersMultifieldValue=(MultifieldValue)currentState.getFactSlot("answers");
List<PrimitiveValue> answersList=answersMultifieldValue.listValue();
for(PrimitiveValue answer : answersList)
{
JToggleButton button;
if(checkboxes)
{
button=new JCheckBox(properties.getProperty(answer.toString()).toString(), false);
}
else
{
button=new JRadioButton(properties.getProperty(answer.toString()).toString(), false);
}
// zaznaczanie domyslnie aktywnych przyciskow
MultifieldValue selectedMultifieldValue=(MultifieldValue)currentState.getFactSlot("selected");
List<PrimitiveValue> selectedList=selectedMultifieldValue.listValue();
for(PrimitiveValue selected : selectedList)
{
if(answer.toString().equals(selected.toString()))
{
button.setSelected(true);
break;
}
}
button.setActionCommand(answer.toString());
answerPanel.add(button);
if(!checkboxes)
{
answerButtons.add(button);
}
}
answerPanel.repaint();
}
@Override
public void actionPerformed(ActionEvent event)
{
// po kliknieciu przycisku "next" dodawane sa fakty do CLIPS-a
if(event.getActionCommand().equals("next"))
{
for(Component component : answerPanel.getComponents())
{
if(component instanceof JToggleButton)
{
JToggleButton button=(JToggleButton)component;
if(button.isSelected())
{
String toAssert="(" + assertedKosiarka + " " + button.getActionCommand()+ ")";
clips.assertString(toAssert);
System.out.println(toAssert);
}
}
}
clips.run(1);
nextUIState();
return;
}
// po kliknieciu przycisku "start"
if(event.getActionCommand().equals("start"))
{
clips.assertString("(start)");
System.out.println("(start)");
clips.run(1);
nextUIState();
return;
}
// po kliknieciu przycisku "restart" resetujemy srodowisko CLIPS-a
if(event.getActionCommand().equals("restart"))
{
clips.reset();
System.out.println("clips.reset");
clips.run(1);
nextUIState();
return;
}
}
private void loadProperties(File propertiesFile)
{
InputStream is;
try
{
is=new FileInputStream(propertiesFile);
properties.load(is);
}
catch(FileNotFoundException e)
{
System.out.println("Cannot find configuration file.");
}
catch(IOException e)
{
System.out.println("Some problems with configuration file.");
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
new Kosiarki();
}
}
);
}
}
class Result
{
private String producent;
private String typ;
private String rodzaj;
private String cena;
public String getProducent()
{
return producent;
}
public void setProducent(String producent)
{
this.producent=producent;
}
public String getTyp()
{
return typ;
}
public void setTyp(String typ)
{
this.typ=typ;
}
public String getRodzaj()
{
return rodzaj;
}
public void setRodzaj(String rodzaj)
{
this.rodzaj=rodzaj;
}
public String getCena()
{
return cena;
}
public void setCena(String cena)
{
this.cena=cena;
}
public Result()
{
}
public Result(String producent, String typ, String rodzaj, String cena)
{
this.producent=producent;
this.typ=typ;
this.rodzaj=rodzaj;
this.cena=cena;
}
}
class ResultComperator implements Comparator<Result>
{
public int compare(Result o1, Result o2)
{
return o1.getProducent().compareTo(o2.getProducent());
}
}
它编译得很好,但是当我在命令行上启动它时,我有:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Kosiarki.nextUIState(Kosiarki.java:199)
at Kosiarki.<init>(Kosiarki.java:101)
at Kosiarki$1.run(Kosiarki.java:333)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Sour
ce)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
还有更多的例外。我想补充一点,我对java很弱,我写这个是看另一个程序的例子。
我需要这方面的帮助。知识库不是问题,只有这个java文件。