Skip to content

Commit

Permalink
Adds com.fathzer.jchess.uci.helper.DeferredReadMoveLibrary
Browse files Browse the repository at this point in the history
  • Loading branch information
fathzer committed Nov 28, 2024
1 parent 2af1de0 commit 48a6d0c
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.fathzer.jchess.uci.helper;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;

import com.fathzer.games.MoveGenerator;
import com.fathzer.games.ai.evaluation.EvaluatedMove;
import com.fathzer.games.movelibrary.MoveLibrary;

/** A move library that encapsulates another move library and read its content outside of its constructor.
* <br>This typically allows an UCI engine to instantiate a move library during the launch process, and
* deferred the effective read of the moves during the <i>isReady</i> command execution as specified in
* UCI protocol.
* @param <M> The type of a move
* @param <B> The type of the move generator used by the UCI engine
*/
public class DeferredReadMoveLibrary<M, B extends MoveGenerator<M>> implements MoveLibrary<M, B> {
/** A interface that can read an object from an URL and sends an IOException if sommething goes wrong.
* @param <T> The type of the read object
*/
@FunctionalInterface
public static interface IOReader<T> {
/** Reads an object.
* @param url The url where to read the object
* @return The object
* @throws IOException If something went wrong
*/
T read(URL url) throws IOException;
}

private final String url;
private final IOReader<MoveLibrary<M, B>> reader;
private MoveLibrary<M, B> internal;

/** Constructor.
* @param url The url where to read the MoveLibrary
* @param reader The reader to read the library.
*/
public DeferredReadMoveLibrary(String url, IOReader<MoveLibrary<M,B>> reader) {
if (url==null || reader==null) {
throw new IllegalArgumentException();
}
this.url = url;
this.reader = reader;
}

/** {@inheritDoc}
* <br>If the move library is not initialized, an empty optional is returned.
*/
@Override
public Optional<EvaluatedMove<M>> apply(B board) {
if (internal==null) {
return Optional.empty();
}
return internal.apply(board);
}

/** Tests if this move library should be initialized.
* @return false if initialization has been made and succeeded.
* @see #init()
*/
public boolean isInitRequired() {
return internal==null;
}

/** Initializes this move library.
* @throws IOException
*/
public void init() throws IOException {
if (isInitRequired()) {
internal = reader.read(toURL(this.url));
}
}

static URL toURL(String path) throws IOException {
URL url;
try {
url = new URL(path);
} catch (MalformedURLException e) {
File file = new File(path);
if (!file.exists()) {
throw new FileNotFoundException();
}
url = file.toURI().toURL();
}
return url;
}

/** Gets the URL where the data should be/has been read.
* @return A String
*/
public String getUrl() {
return url;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.fathzer.jchess.uci.helper;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Optional;

import org.junit.jupiter.api.Test;

import com.fathzer.games.MoveGenerator;
import com.fathzer.games.ai.evaluation.EvaluatedMove;
import com.fathzer.games.ai.evaluation.Evaluation;
import com.fathzer.games.movelibrary.MoveLibrary;

class DeferredReadMoveLibraryTest {

@SuppressWarnings("unchecked")
private final MoveGenerator<String> mv = mock(MoveGenerator.class);

@Test
void test() throws Exception {
String httpsURL = "https://myApp.org/file.gz";
assertEquals(URI.create(httpsURL).toURL(), DeferredReadMoveLibrary.toURL(httpsURL));

assertThrows(IOException.class, () -> DeferredReadMoveLibrary.toURL("httpx://myApp.org/file.gz"));
assertThrows(IOException.class, () -> DeferredReadMoveLibrary.toURL("src/test/resources/unknownFile.json"));

final String path = "src/test/resources/FakeOpenings.txt";
final DeferredReadMoveLibrary<String, MoveGenerator<String>> rb = new DeferredReadMoveLibrary<>(path, this::readOpenings);
assertTrue(rb.isInitRequired());
assertTrue(rb.apply(mv).isEmpty());
rb.init();
assertFalse(rb.isInitRequired());
assertFalse(rb.apply(mv).isEmpty());
// A second init call should no throw any exception
rb.init();
}

private MoveLibrary<String, MoveGenerator<String>> readOpenings(URL url) {
return new MoveLibrary<String, MoveGenerator<String>>() {
@Override
public Optional<EvaluatedMove<String>> apply(MoveGenerator<String> board) {
return mv.equals(board) ? Optional.of(new EvaluatedMove<>("ok", Evaluation.score(100))) : Optional.empty();
}
};
}
}
1 change: 1 addition & 0 deletions src/test/resources/FakeOpenings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
File required by src/test/com.fathzer.jchess.uci.helper.DeferredReadBookTest.java

0 comments on commit 48a6d0c

Please sign in to comment.