/** * 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 . */ 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 implements Finding { 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 implements Model, Cloneable { private final List[] 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(); 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 explore() { final List moves = new ArrayList(); 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 { // 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 engine = new Engine(Runtime.getRuntime().availableProcessors() + 1); engine.start(); ContextFactory cfactory = new ContextFactory(new Strategy(), Long.MAX_VALUE, false, false); Context context = cfactory.produceContext(new Board(3)); Agent agent = new Agent(context); engine.inject(agent); agent.getContext().awaitTermination(1000000, false); Challenge result = agent.getContext().takeResult(); agent.getContext().announceCompletion(); engine.stop(); Finding[] moves = result.getAgent().getFindings(); for (int i = 0; i < moves.length; i++) { System.out.println(i + ": " + moves[i].toString()); } System.out.println("terminated"); } }