Giter Site home page Giter Site logo

Comments (9)

KYLChiu avatar KYLChiu commented on September 6, 2024 2

@ccjeremylo @yibeili

As discussed the issue is due to circular responsibilities of searcher and move ordering. Searcher depends on move ordering for AB-pruning but move ordering depends on searcher to update it's depedent attributes. To break this circular juggling I propose:

  • We keep the existing MoveOrder (maybe renamed to MoveOrderingHeuristic or MoveOrderingStrategy) parent class with evaluate signature:
def evaluate(self, move: chess.Move) -> float:
    pass

FYI: TIL this is known as a strategy pattern.

  • All child classes of MoveOrder, e.g. MvvLvaHeuristic or KillerMoveHeurstic now are built every time when we need to call order moves. We inject the dependencies on construction. All information now comes from the searcher, which means the searcher owns any dependencies. The runtime difference for doing this should be negligble because of python's pass by assignment principle.

For example for KillerMoveHeuristic:

class KillerMoveHeuristic(MoveOrder):
	def __init__(self, killer_table):
		self._killer_table = killer_table

where killer_table is now a MinimaxVariant level object.

  • _ordered_moves in MinimaxVariant will take in the MoveOrder child class as an argument as well, allowing it to decide which evaluate function to call.
@staticmethod
def _ordered_moves(move_ordering_strategy: MoveOrder, legal_moves: Any) -> Any:
        return sorted(
            legal_moves,
            key=lambda move: (move_ordering_strategy.evaluate(move),),
            reverse=True,
        )
  • We will move the _build_moveorder factory onto MinimaxVariant - and possibly change it to be a dispatching function, so that we can determine which move ordering we need once, and just call that create function over and over again. Whether this will need some sort of Dependency Injection is not quite clear to me yet, hopefully not.

from sporkfish.

KYLChiu avatar KYLChiu commented on September 6, 2024 2

where killer_table is now a MinimaxVariant level object.

What does level mean here?

@yibeili As in the killer_table will move into the MinimaxVariant class, which will own the object (i.e. be responsible for it's creation and deletion).

from sporkfish.

KYLChiu avatar KYLChiu commented on September 6, 2024 2

i am not too sure :( my first question is that what problem will circular calling cause? and secondly, what if we have a separate class storing the info searcher wants from moveorder and the info moveorder from searcher?

@yibeili Circular design is usually avoided because it introduces tight coupling. Tight coupling causes rigidity; as you saw, each time we introduce a new type of move ordering, we need to extend the evaluate function. See Open/Closed principle. I'm sure chatGPT can give you more.

Re the second question, introducing a segway container class to hold your dependencies and inserting them when needed is called Dependency Injection. However this isn't much different to what I'm proposing here - instead of injecting them at run time and having mutable classes, we inject them on construction.

from sporkfish.

KYLChiu avatar KYLChiu commented on September 6, 2024 1

From the above it looks like PV, Hash/TT, and IID require information from the searcher in some way (the transposition table or PV approximation move). Moreover for history, killer and countermove heuristic, not only do we need this information from the searcher, we need to update their respective tables there too (i.e. we only update the table when there is a cutoff, which we can't possibly know in the move ordering class).

In the current evaluate function we only pass (board, move):
def evaluate(self, board: Board, move: chess.Move) -> float:

It looks like this won't be enough to encompass all cases. Any ideas on how to incorporate generically?

from sporkfish.

yibeili avatar yibeili commented on September 6, 2024 1

where killer_table is now a MinimaxVariant level object.

What does level mean here?

from sporkfish.

yibeili avatar yibeili commented on September 6, 2024 1

i am not too sure :( my first question is that what problem will circular calling cause? and secondly, what if we have a separate class storing the info searcher wants from moveorder and the info moveorder from searcher?

from sporkfish.

KYLChiu avatar KYLChiu commented on September 6, 2024 1

Will discuss further details with you offline - the design looks quite nice to me, biggest question I have is that I am not sure how we can combine mover order strategies using this design. The static method:

@staticmethod
def _ordered_moves(move_ordering_strategy: MoveOrder, legal_moves: Any) -> Any:
        return sorted(
            legal_moves,
            key=lambda move: (move_ordering_strategy.evaluate(move),),
            reverse=True,
        )

only takes in a single unique move_ordering_strategy, so how do we mix and match them?

@ccjeremylo Mixing and matching will be done through multiple inheritance or composition. Lets call it the CompositeMoveOrdering - this will have

class CompositeMoveOrdering(MoveOrder, MvvLva, Killer, ...)

or

class CompositeMoveOrdering(MoveOrder):

  def __init__(MvvLva, Killer, ...):

from sporkfish.

ccjeremylo avatar ccjeremylo commented on September 6, 2024

Interesting - look forward to this 👀

from sporkfish.

ccjeremylo avatar ccjeremylo commented on September 6, 2024

Will discuss further details with you offline - the design looks quite nice to me, biggest question I have is that I am not sure how we can combine mover order strategies using this design. The static method:

@staticmethod
def _ordered_moves(move_ordering_strategy: MoveOrder, legal_moves: Any) -> Any:
        return sorted(
            legal_moves,
            key=lambda move: (move_ordering_strategy.evaluate(move),),
            reverse=True,
        )

only takes in a single unique move_ordering_strategy, so how do we mix and match them?

from sporkfish.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.