Skip to content

Commit

Permalink
Add tests for board circuit and Fix found errors
Browse files Browse the repository at this point in the history
Shigoto-dev19 committed Feb 7, 2024
1 parent 0d7e04a commit 4d54a0a
Showing 2 changed files with 189 additions and 31 deletions.
152 changes: 152 additions & 0 deletions src/board.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { BoardCircuit, BoardUtils } from './client';

/*
Each ship is an array [x, y, z] where
x = x coordinate on the board
y = y coordinate on the board
z = is a binary where 0=horizontal & 1=verical orientation ship placements
*/

describe('Board Tests', () => {
describe('Valid Board Checks', () => {
function testValidBoard(ships: number[][]) {
const parsedShips = BoardUtils.parse(ships);
const hash = BoardUtils.hash(parsedShips);

const serializedBoard = BoardUtils.serializeBoard(ships);
const validationHash = BoardCircuit.validateBoard(serializedBoard);
expect(validationHash).toEqual(hash);
}

it("Prove valid board 1", () => {
const ships1 = [
[0, 0, 0],
[0, 1, 0],
[0, 2, 0],
[0, 3, 0],
[0, 4, 0],
];
testValidBoard(ships1);
});

it("Prove valid board 2", () => {
const ships2 = [
[9, 0, 1],
[9, 5, 1],
[6, 9, 0],
[6, 8, 0],
[7, 7, 0],
];
testValidBoard(ships2);
});

it("Prove valid board 3", () => {
const ships3 = [
[0, 1, 1],
[4, 3, 0],
[3, 3, 1],
[5, 9, 0],
[1, 7, 1],
];
testValidBoard(ships3);
});
});

describe('Out of Bound Checks', () => {
function testInvalidRange(ships: number[][], errorMessage?: string) {
const validationRangeError = () => {
const serializedBoard = BoardUtils.serializeBoard(ships);
BoardCircuit.validateBoard(serializedBoard);
}
expect(validationRangeError).toThrowError(errorMessage);
}

it("Range violation: board 1: negative", () => {
const ships = [
[-1, 0, 0],
[0, 1, 0],
[0, 2, 0],
[0, 3, 0],
[0, 4, 0],
];
testInvalidRange(ships);
});

it("Range violation: board 2: out of bounds x/ y", () => {
const ships = [
[0, 0, 0],
[0, 10, 0],
[0, 2, 0],
[0, 3, 0],
[0, 4, 0],
];
testInvalidRange(ships, 'Ship2 is out of board range!');
});

it("Range violation: board 3: out of bounds z", () => {
const ships = [
[0, 0, 0],
[0, 1, 0],
[0, 2, 0],
[0, 3, 0],
[0, 4, 2],
];
testInvalidRange(ships, 'Coordinate z should be 1 or 0!');
});
});

describe("Collision Checks", () => {
function testCollision(ships: number[][], errorMessage: string) {
const serializedBoard = BoardUtils.serializeBoard(ships);
const validationCollisionrror = () => {
BoardCircuit.validateBoard(serializedBoard);
}
expect(validationCollisionrror).toThrowError(errorMessage);
}

it("Placement violation: board 1", () => {
const ships1 = [
[0, 0, 0],
[0, 0, 0],
[0, 2, 0],
[0, 3, 0],
[0, 4, 0],
];
testCollision(ships1, 'Collision occured when placing Ship2!');
});

it("Placement violation: board 2", () => {
const ships2 = [
[0, 1, 1],
[4, 3, 0],
[3, 3, 0],
[5, 9, 0],
[1, 8, 1],
];
testCollision(ships2, 'Collision occured when placing Ship3!');
});

it("Placement violation: board 3", () => {
const ships3 = [
[0, 1, 1],
[4, 3, 0],
[5, 5, 0],
[3, 5, 0],
[1, 7, 1],
];
testCollision(ships3, 'Collision occured when placing Ship4!');
});

it("Placement violation: board 4", () => {
const ships4 = [
[9, 0, 1],
[9, 5, 1],
[6, 9, 0],
[6, 8, 0],
[7, 7, 1],
];
testCollision(ships4, 'Collision occured when placing Ship5!');
});
});
});

68 changes: 37 additions & 31 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -37,44 +37,46 @@ class BoardUtils {

return board
}
static parse(board: number[][]) {
return board.map((ship) => ship.map(Field))
}

static hashBoard(board: Field[][]) {
static hash(board: Field[][]) {
return Poseidon.hash(board.flat());
}
}

class BoardCircuit {
//TODO Add meaningful error logs
static validateShipInRange(ship: Field[], shipLength: number) {
static validateShipInRange(ship: Field[], shipLength: number, errorMessage: string) {
// horizontal check: z=ship[2]=0
const checkHorizontal = () => {
ship[0].add(shipLength).assertLessThan(10);
ship[1].assertLessThan(10);
return Bool(true)
const hCheck = ship[0].add(shipLength).lessThan(10);
const vCheck = ship[1].lessThan(10);
return hCheck.and(vCheck)
}

// vertical check: z=ship[2]=1
const checkVertical = () => {
ship[0].assertLessThan(10);
ship[1].add(shipLength).assertLessThan(10);
return Bool(true)
const hCheck = ship[0].lessThan(10);
const vCheck = ship[1].add(shipLength).lessThan(10);
return hCheck.and(vCheck)
}

// verify z is binary
ship[2].assertLessThanOrEqual(1);
ship[2].assertLessThanOrEqual(1, 'Coordinate z should be 1 or 0!');

const isInRange = Provable.if(ship[2].equals(1), checkVertical(), checkHorizontal());
isInRange.assertTrue;
isInRange.assertTrue(errorMessage);
}

static placeShip = (ship: Field[], shipLength: number, boardMap: Field[]) => {
static placeShip(ship: Field[], shipLength: number, boardMap: Field[], errorMessage: string) {
const increment = Provable.if(ship[2].equals(1), Field(10), Field(0));
let index = ship[0].add(ship[1].mul(10));
for(let i=0; i<shipLength; i++) {
let coordinate = index.add(i).add(increment);
let check = boardMap.some(item => item.equals(coordinate).toBoolean());
Provable.log('check: ', check)
Bool(check).assertFalse('Ship collision detected!');
// Provable.log('check: ', check)
Bool(check).assertFalse(errorMessage);
boardMap.push(coordinate);
}
return boardMap
@@ -85,36 +87,40 @@ class BoardCircuit {
let boardMap: Field[] = [];
for (let i = 0; i < 5; i++) {
// range check
BoardCircuit.validateShipInRange(ships[i], shipLength[i]);
BoardCircuit.validateShipInRange(ships[i], shipLength[i], `Ship${i+1} is out of board range!`);
// collision check
boardMap = BoardCircuit.placeShip(ships[i], shipLength[i], boardMap);
Provable.log('boardMap: ', boardMap);
boardMap = BoardCircuit.placeShip(ships[i], shipLength[i], boardMap,`Collision occured when placing Ship${i+1}!`);
}
}

static validateBoard(serializedBoard: Field) {
const board = BoardUtils.deserializeBoard(serializedBoard);
this.validateShipsLocation(board);
const boardHash = BoardUtils.hashBoard(board);
const boardHash = BoardUtils.hash(board);

return boardHash
}
}

const player1Board = [
[4, 0, 0],
[0, 1, 0],
[0, 2, 0],
[0, 3, 0],
[0, 4, 0],
];
// const player1Board = [
// [0, 1, 0],
// [0, 1, 0],
// [0, 2, 0],
// [0, 3, 0],
// [0, 4, 0],
// ];

const serializedBoard = BoardUtils.serializeBoard(player1Board);
let deserializeBoard = BoardUtils.deserializeBoard(serializedBoard).flat().map(x => Number(x.toBigInt()));
// const serializedBoard = BoardUtils.serializeBoard(player1Board);
// let deserializeBoard = BoardUtils.deserializeBoard(serializedBoard).flat().map(x => Number(x.toBigInt()));

console.log('initial board: ', player1Board.flat());
console.log('deserialized board: ', deserializeBoard);
// console.log('initial board: ', player1Board.flat());
// console.log('deserialized board: ', deserializeBoard);

console.log('collision check: ', BoardCircuit.validateShipsLocation(player1Board.map(ship => ship.map(Field))))
// //TODO Add board integration tests
// //TODO? confirm board circuit is provable

//TODO Add board integration tests
// console.time('board witness');
// Provable.runAndCheck(() => {
// BoardCircuit.validateShipsLocation(player1Board.map(ship => ship.map(Field)))
// });
// console.timeEnd('board witness');

0 comments on commit 4d54a0a

Please sign in to comment.