Kotlin Language Features Related to Null Handling

Any software engineer with a Java background would find the null handling features in the Kotlin language interesting. Let's summarize this topic with some examples. Nullable types: In Kotlin, types are non-nullable by default. If you want a variable to be able to hold a null value, you need to explicitly declare its type as nullable using the Type? syntax. For example, String? denotes a nullable string, while String represents a non-nullable string. Safe calls (?.): Kotlin introduces the safe call operator (?.) for handling nullable types. It allows you to safely invoke a method or access a property on a nullable object. If the object is null, the expression returns null instead of throwing a NullPointerException. Example: data class Person(val name: String, val age: Int, val address: String?) fun main() {     // Create a person with a nullable address     val person1 = Person("John Doe", 25, "123 Main Street")     val person2 = Person("Jane Doe", 30,...

Pulse Motorunun İncelenmesi

Pulse sisteminde bir pozisyonun değerlendirilmesi Evaluation sınıfı ile gerçekleşmektedir.

class Evaluation {

    int evaluate(Position position) {

        int myColor = position.activeColor;
        int oppositeColor = opposite(myColor);
        int value = 0;

        int materialScore = (evaluateMaterial(myColor, position) - evaluateMaterial(oppositeColor, position)) * materialWeight / MAX_WEIGHT;
        value += materialScore;

        int mobilityScore = (evaluateMobility(myColor, position) - evaluateMobility(oppositeColor, position)) * mobilityWeight / MAX_WEIGHT;
        value += mobilityScore;

        return value;
    }

    //...}
    

Burada önce pozisyondaki materyal skoru bulunmaktadır. Örneğin bir piyon fazlası var ise materyal skoru 1 olarak bulunur. Ardından mobilite skoru bulunmaktadır. Örneğin bir fil, çapraz karelerde serbest olarak dolaşabiliyorsa mobilite skoru yüksek olur. Satranç motorları güçlendikçe değerlendirme kriterleri de artmakta ve kod da karmaşıklaşmaktadır.

private int evaluateMaterial(int color, Position position) {
    int material = position.material[color];

    // Fil çifti için bonus skor ver
    if (position.pieces[color][BISHOP].size() >= 2) {
        material += 50;
    }

    return material;
}

Pozisyondaki materyal skoru belirlenirken, Position sınıfında sürekli güncel olarak tutulan int dizileri kullanılmaktadır. Aslında beyaz ve siyah için iki int değer tutulmaktadır. Birçok metot "color" parametresi aldığı için dizinin "color" elemanına erişmek, materyal skoru almak anlamına gelmektedir.

private int evaluateMobility(int color, Position position) {
    int knightMobility = 0;
    for (long squares = position.pieces[color][KNIGHT].squares; squares != 0; squares = remainder(squares)) {
        int square = next(squares);
        knightMobility += evaluateMobility(color, position, square, knightDirections);
    }
    //...}

Yukarıda bir at için mobilitenin belirlenmesi gösterilmiştir. Burada Position sınıfında yer alan taş yerleşim bilgilerinin kullanıldığı görülmektedir. Her at için gidebileceği kareler üzerinden mobilite hesaplanmaktadır.

class Position {

     Bitboard[][] pieces = new Bitboard[Color.values.length][PieceType.values.length];
}

Pozisyonu ifade eden sınıfta siyah ve beyaz için olmak üzere iki tane dizi tutulmaktadır. Bunlardan her biri altı tane Bitboard tutmaktadır. Örneğin "beyaz at" istediğimizde bize bunların yerleşimini ifade eden bir Bitboard dönecektir. Pozisyonların bit dizisi şeklinde ifade edilmesi oyun programlamada kullanılan önemli bir yöntemdir ve satrançta 64 bitlik bir Java long türü, bir satranç tahtasını ifade etmekte yeterli olacaktır. [3]

Hamle Oluşturma

Motor öncelikle tüm legal hamleleri belirlemektedir. Bunu MoveGenerator sınıfına yaptırır.

class MoveGenerator {

    private final MoveList moves = new MoveList<>(MoveEntry.class);

    MoveList getLegalMoves(Position position, int depth, boolean isCheck) {
        MoveList legalMoves = getMoves(position, depth, isCheck);

        int size = legalMoves.size;
        legalMoves.size = 0;
        for (int i = 0; i < size; ++i) {
            int move = legalMoves.entries[i].move;

            position.makeMove(move);
            // açmaz durumlarına karşı kontrol            if (!position.isCheck(opposite(position.activeColor))) {
                legalMoves.entries[legalMoves.size++].move = move;
            }
            position.undoMove(move);
        }

        return legalMoves;
    }

Burada özellikle Position sınıfının makeMove ve undoMove metotlarının ne kadar önemli olduğu ve hızlı olmaları gerektiği görülmektedir. Legal hamleler belirlenirken, hamleyi yapan tarafın şahının tehdit altında olmaması gerektiği (açmazda olma) kuralı da kontrol edilmektedir.

private void addMoves(MoveList list, Position position) {
    for (long squares = position.pieces[activeColor][PAWN].squares; squares != 0; squares = remainder(squares)) {
        int square = next(squares);
        addPawnMoves(list, square, position);
    }
}


Her taş çeşidi için olası hamleler belirlenirken bir kez daha BitBoard temsilinin önemi görülmektedir. Buradaki döngü programın birçok kısmında karşımıza çıkmaktadır. Geçerli hamleler belirlendikten sonra "En Değerli Kurban, En Değersiz Saldırgan" adı verilen sezgisel yaklaşıma göre değerlendirilmektedir. [5]


[3] Bošković, Borko, et al. "The representation of chess game." Information Technology Interfaces, 2005.
[4] https://chessprogramming.wikispaces.com/Pulse
[5] Groß, Roderich, et al. "Evolving chess playing programs." GECCO 2002. No. LSRO-CONF-2008-037. Morgan Kaufmann, 2002.



Comments

Popular posts from this blog

Trie Data Structure and Finding Patterns in a Collection of Words

Virtual Memory

NOTES ON COMPUTER ARCHITECTURE: Some important concepts in computer architecture