You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
8.4 KiB
252 lines
8.4 KiB
/**
|
|
* Hanoi.java
|
|
* Copyright 2009 by Michael Peter Christen, Frankfurt a. M., Germany
|
|
* First published 03.12.2009 at http://yacy.net
|
|
*
|
|
* $LastChangedDate$
|
|
* $LastChangedRevision$
|
|
* $LastChangedBy$
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program in the file lgpl21.txt
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.yacy.ai.example;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import net.yacy.ai.greedy.AbstractFinding;
|
|
import net.yacy.ai.greedy.AbstractModel;
|
|
import net.yacy.ai.greedy.Agent;
|
|
import net.yacy.ai.greedy.Challenge;
|
|
import net.yacy.ai.greedy.Context;
|
|
import net.yacy.ai.greedy.ContextFactory;
|
|
import net.yacy.ai.greedy.Engine;
|
|
import net.yacy.ai.greedy.Finding;
|
|
import net.yacy.ai.greedy.Goal;
|
|
import net.yacy.ai.greedy.Model;
|
|
import net.yacy.ai.greedy.Unirole;
|
|
|
|
public class Hanoi {
|
|
|
|
public static class Coin {
|
|
public final int size;
|
|
public Coin(int size) {
|
|
this.size = size;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object other) {
|
|
return (other != null && other instanceof Coin && this.size == ((Coin) other).size);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return this.size;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return Integer.toString(size);
|
|
}
|
|
}
|
|
|
|
public static class Move extends AbstractFinding<Unirole> implements Finding<Unirole> {
|
|
public final int from, to;
|
|
public Move(int from, int to) {
|
|
super(Unirole.unirole);
|
|
this.from = from;
|
|
this.to = to;
|
|
}
|
|
|
|
public Move(int from, int to, int prio) {
|
|
super(Unirole.unirole, prio);
|
|
this.from = from;
|
|
this.to = to;
|
|
}
|
|
|
|
@Override
|
|
public Object clone() {
|
|
return new Move(this.from, this.to, this.getPriority());
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object other) {
|
|
return (other != null
|
|
&& other instanceof Move
|
|
&& this.from == ((Move) other).from
|
|
&& this.to == ((Move) other).to);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return 3 * this.from + 7 * this.to;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return from + " -> " + to;
|
|
}
|
|
}
|
|
|
|
public static class Board extends AbstractModel<Unirole, Move> implements Model<Unirole, Move>, Cloneable {
|
|
private final List<Coin>[] stacks;
|
|
public int moves;
|
|
@SuppressWarnings("unchecked")
|
|
public Board(int height) {
|
|
super(Unirole.unirole);
|
|
stacks = new ArrayList[3];
|
|
for (int i = 0; i < 3; i++) this.stacks[i] = new ArrayList<Coin>();
|
|
while (height > 0) {
|
|
this.stacks[0].add(new Coin(height--));
|
|
}
|
|
this.moves = 0;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
StringBuilder s = new StringBuilder();
|
|
s.append(stacks[0].toString());
|
|
s.append(",");
|
|
s.append(stacks[1].toString());
|
|
s.append(",");
|
|
s.append(stacks[2].toString());
|
|
return s.toString();
|
|
}
|
|
|
|
@Override
|
|
public Object clone() {
|
|
Board b = new Board(0);
|
|
for (int i = 0; i < 3; i++) {
|
|
for (Coin s: this.stacks[i]) b.stacks[i].add(s);
|
|
}
|
|
b.moves = this.moves;
|
|
return b;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object other) {
|
|
if (other == null || !(other instanceof Board)) return false;
|
|
Board b = (Board) other;
|
|
for (int i = 0; i < 3; i++) {
|
|
if (this.stacks[i].size() != b.stacks[i].size()) return false;
|
|
for (int j = 0; j < this.stacks[i].size(); j++) {
|
|
if (!this.stacks[i].get(j).equals(b.stacks[i].get(j))) return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
int c = 0;
|
|
for (int i = 0; i < 3; i++) {
|
|
for (Coin s: this.stacks[i]) c += s.hashCode();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
public void applyFinding(Move finding) {
|
|
this.stacks[finding.to].add(this.stacks[finding.from].remove(this.stacks[finding.from].size() - 1));
|
|
this.moves++;
|
|
}
|
|
|
|
private int getPriority(Move finding) {
|
|
int p = 1000 - this.moves;
|
|
if (finding.from == 0) p += 2;
|
|
if (finding.from == 1) p--;
|
|
if (finding.from == 2) p++;
|
|
if (finding.to == 0) p--;
|
|
if (finding.to == 1) p += 2;
|
|
if (finding.to == 2) p++;
|
|
return p;
|
|
}
|
|
|
|
public List<Move> explore() {
|
|
final List<Move> moves = new ArrayList<Move>();
|
|
for (int from = 0; from < 3; from++) {
|
|
toloop: for (int to = 0; to < 3; to++) {
|
|
if (from == to) continue toloop;
|
|
Coin fromCoin = (this.stacks[from].size() == 0) ? null : this.stacks[from].get(this.stacks[from].size() - 1);
|
|
if (fromCoin == null) continue toloop;
|
|
Coin toCoin = (this.stacks[to].size() == 0) ? null : this.stacks[to].get(this.stacks[to].size() - 1);
|
|
if (toCoin != null && fromCoin.size >= toCoin.size) continue toloop;
|
|
Move move = new Move(from, to);
|
|
move.setPriority(getPriority(move));
|
|
moves.add(new Move(from, to));
|
|
}
|
|
}
|
|
return moves;
|
|
}
|
|
|
|
public int getRanking(int findings, Unirole role) {
|
|
return stacks[1].size() - stacks[0].size();
|
|
}
|
|
|
|
public boolean isTermination(Unirole role) {
|
|
return stacks[0].isEmpty() && stacks[2].isEmpty();
|
|
}
|
|
|
|
public Unirole isTermination() {
|
|
return (stacks[0].isEmpty() && stacks[2].isEmpty()) ? Unirole.unirole : null;
|
|
}
|
|
}
|
|
|
|
public static class Strategy implements Goal<Unirole, Move, Board> {
|
|
|
|
// we check if there was ever a fulfilled status
|
|
// in case of a problem-solving algorithm we want to stop
|
|
// as soon as a fulfilled status is reached.
|
|
// therefore we use that status for the pruning method to prune all
|
|
// tasks that may follow to the fullfillment board
|
|
|
|
public Strategy() {
|
|
}
|
|
|
|
public boolean isFulfilled(Board model) {
|
|
return model.isTermination(Unirole.unirole);
|
|
}
|
|
|
|
public boolean isSnapshot(Board model) {
|
|
return false; // no snapshots
|
|
}
|
|
|
|
public boolean pruning(Board model) {
|
|
// if the have ever found a solution then prune all other findings
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
|
|
Engine<Unirole, Move, Board> engine = new Engine<Unirole, Move, Board>(Runtime.getRuntime().availableProcessors() + 1);
|
|
engine.start();
|
|
ContextFactory<Unirole, Move, Board> cfactory = new ContextFactory<Unirole, Move, Board>(new Strategy(), Long.MAX_VALUE, false, false);
|
|
Context<Unirole, Move, Board> context = cfactory.produceContext(new Board(3));
|
|
Agent<Unirole, Move, Board> agent = new Agent<Unirole, Move, Board>(context);
|
|
engine.inject(agent);
|
|
agent.getContext().awaitTermination(1000000, false);
|
|
Challenge<Unirole, Move, Board> result = agent.getContext().takeResult();
|
|
agent.getContext().announceCompletion();
|
|
engine.stop();
|
|
Finding<Unirole>[] moves = result.getAgent().getFindings();
|
|
for (int i = 0; i < moves.length; i++) {
|
|
System.out.println(i + ": " + moves[i].toString());
|
|
}
|
|
System.out.println("terminated");
|
|
}
|
|
}
|