Skip to content

Commit

Permalink
part 11 initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Francois committed Feb 9, 2021
1 parent 9945d69 commit 2d9e754
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@
argument = "test-set 3 --weak"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "test-set 4 --weak"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "position 427566236745127177115664464254 --weak"
isEnabled = "NO">
Expand Down
4 changes: 2 additions & 2 deletions Connect4/Solver/Solver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public final class Solver {
Position.Dimension.width / 2 + (1 - 2 * (index % 2)) * (index + 1) / 2
}.reversed()

//8388593 prime = 64MB of transposition table
transpositionTable = TranspositionTable(size: 8388593)
// fixed transpostion table size
transpositionTable = TranspositionTable()
}

/**
Expand Down
51 changes: 26 additions & 25 deletions Connect4/Solver/TranspositionTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,73 +22,74 @@ import Foundation
/**
* Transposition Table is a simple hash map with fixed storage size.
* In case of collision we keep the last entry and overide the previous one.
*
* We use 56-bit keys and 8-bit non-null values
*/
final internal class TranspositionTable {

private var table : UnsafeMutablePointer<UInt>
private var size : Int
typealias KeyType = UInt32
typealias ValueType = Int8

private var keys : UnsafeMutablePointer<KeyType>
private var values : UnsafeMutablePointer<ValueType>
private static var size = 1 << 23 + 9

/**
* Allocate and initialize to zero a mutable pointer.
* We don't use UnsafeMutableBufferPointer because we don't need collection protocol
* We'll store a 56 bit key in low bytes and an 8 bit value in high byte
* - parameter size: number of entries
*/
internal init(size: Int) {
self.size = size
table = UnsafeMutablePointer<UInt>.allocate(capacity: size)
table.initialize(repeating: .zero, count: size)
internal init() {
keys = UnsafeMutablePointer<KeyType>.allocate(capacity: Self.size)
keys.initialize(repeating: .zero, count: Self.size)
values = UnsafeMutablePointer<ValueType>.allocate(capacity: Self.size)
values.initialize(repeating: .zero, count: Self.size)
}

deinit {
table.deallocate()
keys.deallocate()
values.deallocate()
}

/**
* Compute the index in the transition table for the given key.
*/
private func index(for key: UInt) -> Int {
Int(bitPattern: key) % size
Int(bitPattern: key) % Self.size
}

/**
* Store a value for a given key
* - parameter key: 56-bit key
* - parameter value: non-null 8-bit value. null (0) value are used to encode missing data.
* - parameter key: must be less than key_size bits.
* - parameter value: must be less than value_size bits. null (0) value is used to encode missing data
*/
internal func put(key: UInt, value: Int) {
assert(key < (UInt(1) << 56))
assert(value < (1 << 8))
assert(value > -(1 << 8))
assert(value <= ValueType.max)
assert(value >= ValueType.min)

let position = index(for: key)
let entryPointer = table.advanced(by: position)

entryPointer.pointee = (key + (UInt(bitPattern: value) << 56))
keys.advanced(by: position).pointee = KeyType(truncatingIfNeeded: key)
values.advanced(by: position).pointee = ValueType(truncatingIfNeeded: value)
}

/**
* Get the value of a key
* - parameter key: 56-bit key
* - parameter value: 8-bit value associated with the key if present, 0 otherwise.
* - parameter key: must be less than key_size bits.
* - returns: value_size bits value associated with the key if present, 0 otherwise.
*/
internal func get(key: UInt) -> Int {
assert(key < (UInt(1) << 56))

let position = index(for: key)
let entry = table.advanced(by: position).pointee

guard entry & ((1 << 56) - 1) == key else { return 0 }
guard (keys.advanced(by: position).pointee == KeyType(truncatingIfNeeded: key)) else { return .zero }

return Int(bitPattern: (entry >> 56))
return Int(values.advanced(by: position).pointee)
}

/**
* Empty the Transition Table.
*/
internal func reset() {
table.assign(repeating: .zero, count: size)
keys.assign(repeating: .zero, count: Self.size)
values.assign(repeating: .zero, count: Self.size)
}
}
12 changes: 6 additions & 6 deletions Connect4Tests/TranspositionTableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ import XCTest
class TranspositionTableTests: XCTestCase {

func testInit() throws {
let table = TranspositionTable(size: 97)
let table = TranspositionTable()
XCTAssertEqual(table.get(key: 42), 0)
}

func testPutAndGet() throws {
let table = TranspositionTable(size: 97)

let table = TranspositionTable()
table.put(key:42, value: 1)
table.put(key:96, value: 2)

XCTAssertEqual(table.get(key: 42), 1)
XCTAssertEqual(table.get(key: 96), 2)

table.put(key: 42 + 97, value: 3)
table.put(key: 42 + (1 << 23) + 9, value: 3)
XCTAssertEqual(table.get(key: 42), 0)
XCTAssertEqual(table.get(key: 42 + 97), 3)
XCTAssertEqual(table.get(key: 42 + (1 << 23) + 9), 3)
}

func testReset() throws {
let table = TranspositionTable(size: 97)
// let table = TranspositionTable(size: 97)
let table = TranspositionTable()
table.put(key:42, value: 1)
table.reset()

Expand Down

0 comments on commit 2d9e754

Please sign in to comment.