From 68686f7c2f502b1284e4a935c5ef212079077351 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Thu, 6 Oct 2022 10:31:58 -0700 Subject: [PATCH 1/2] Add clean script --- clean.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 clean.sh diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..b25a506 --- /dev/null +++ b/clean.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# A script to clean all examples. +# Run this script from the root directory of the workshop repository. + +# Clean the auction example. +cd auction +leo clean +cd .. + +# Clean the basic bank example. +cd basic_bank +leo clean +cd .. + +# Clean the battleship example. +cd battleship +leo clean +cd .. + +# Clean the tictactoe example. +cd tictactoe +leo clean +cd .. + +# Clean the token example. +cd token +leo clean +cd .. + +# Clean the vote example. +cd vote +leo clean +cd .. From e5fa47eb7ebc949621a358c5db953f15547db65e Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Thu, 6 Oct 2022 10:32:28 -0700 Subject: [PATCH 2/2] Update examples --- auction/program.json | 4 +- auction/src/main.leo | 131 +++++++++-------- basic_bank/src/main.leo | 175 +++++++++++----------- battleship/imports/board.leo | 215 +++++++++++++-------------- battleship/imports/move.leo | 88 +++++------ battleship/imports/verify.leo | 249 +++++++++++++++---------------- battleship/src/main.leo | 200 ++++++++++++------------- tictactoe/src/main.leo | 204 +++++++++++++------------- token/src/main.leo | 269 +++++++++++++++++----------------- vote/src/main.leo | 167 +++++++++++---------- 10 files changed, 851 insertions(+), 851 deletions(-) diff --git a/auction/program.json b/auction/program.json index dd9f504..eafe608 100644 --- a/auction/program.json +++ b/auction/program.json @@ -3,8 +3,8 @@ "version": "0.0.0", "description": "", "development": { - "private_key": "APrivateKey1zkp5wvamYgK3WCAdpBQxZqQX8XnuN2u11Y6QprZTriVwZVc", - "address": "aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh" + "private_key": "APrivateKey1zkpG9Af9z5Ha4ejVyMCqVFXRKknSm8L1ELEwcc4htk9YhVK", + "address": "aleo1yzlta2q5h8t0fqe0v6dyh9mtv4aggd53fgzr068jvplqhvqsnvzq7pj2ke" }, "license": "MIT" } diff --git a/auction/src/main.leo b/auction/src/main.leo index 70eacd9..28a8b4c 100644 --- a/auction/src/main.leo +++ b/auction/src/main.leo @@ -1,70 +1,71 @@ -// A bid in an auction. -// - `owner` : The address of the account that owns the record associated with this bid. -// This is separate from the address of the account that placed the bid. -// - `gates` : The value associated with the record (always zero). -// - `bidder` : The address of the account that placed the bid. -// - `amount` : The amount of the bid. -// - `is_winner` : Whether the bid is the winning bid. -record Bid { - owner: address, - gates: u64, - bidder: address, - amount: u64, - is_winner: bool, -} +// The `program` scope defines the data types, functions, and state associated with the `auction` program. +program auction.aleo { -// Returns a new bid. -// - `bidder` : The address of the account that placed the bid. -// - `amount` : The amount of the bid. -// Requires that `bidder` matches the function caller. -// The owner of the record is set to the entity responsible for running the auction (auction runner). -// The address of the auction runner is aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh. -@program -function place_bid(bidder: address, amount: u64) -> Bid { - // Ensure the caller is the auction bidder. - console.assert_eq(self.caller, bidder); - // Return a new 'Bid' record for the auction bidder. - return Bid { - owner: aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh, - gates: 0u64, - bidder: bidder, - amount: amount, - is_winner: false, - }; -} + // A bid in an auction. + // - `owner` : The address of the account that owns the record associated with this bid. + // This is separate from the address of the account that placed the bid. + // - `gates` : The value associated with the record (always zero). + // - `bidder` : The address of the account that placed the bid. + // - `amount` : The amount of the bid. + // - `is_winner` : Whether the bid is the winning bid. + record Bid { + owner: address, + gates: u64, + bidder: address, + amount: u64, + is_winner: bool, + } -// Returns the winning bid. -// - `first` : The first bid. -// - `second` : The second bid. -// Requires that the function caller is the auction runner. -// Assumes that the function is invoked only after the bidding period has ended. -// In the event of a tie, the first bid is selected. -@program -function resolve(first: Bid, second: Bid) -> Bid { - // Ensure the caller is the auctioneer. - console.assert_eq(self.caller, aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh); - // Resolve the winner of the auction. - if (first.amount >= second.amount) { - return first; - } else { - return second; + // Returns a new bid. + // - `bidder` : The address of the account that placed the bid. + // - `amount` : The amount of the bid. + // Requires that `bidder` matches the function caller. + // The owner of the record is set to the entity responsible for running the auction (auction runner). + // The address of the auction runner is aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh. + transition place_bid(bidder: address, amount: u64) -> Bid { + // Ensure the caller is the auction bidder. + console.assert_eq(self.caller, bidder); + // Return a new 'Bid' record for the auction bidder. + return Bid { + owner: aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh, + gates: 0u64, + bidder: bidder, + amount: amount, + is_winner: false, + }; } -} -// Returns ownership of the bid to bidder. -// - `bid` : The winning bid. -// Requires that the function caller is the auction runner. -// Assumes that the function is invoked only after all bids have been resolved. -@program -function finish(bid: Bid) -> Bid { - // Ensure the caller is the auctioneer. - console.assert_eq(self.caller, aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh); - // Return 'is_winner' as 'true' in the winning 'Bid'. - return Bid { - owner: bid.bidder, - gates: bid.gates, - bidder: bid.bidder, - amount: bid.amount, - is_winner: true, - }; + // Returns the winning bid. + // - `first` : The first bid. + // - `second` : The second bid. + // Requires that the function caller is the auction runner. + // Assumes that the function is invoked only after the bidding period has ended. + // In the event of a tie, the first bid is selected. + transition resolve(first: Bid, second: Bid) -> Bid { + // Ensure the caller is the auctioneer. + console.assert_eq(self.caller, aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh); + // Resolve the winner of the auction. + if (first.amount >= second.amount) { + return first; + } else { + return second; + } + } + + // Returns ownership of the bid to bidder. + // - `bid` : The winning bid. + // Requires that the function caller is the auction runner. + // Assumes that the function is invoked only after all bids have been resolved. + transition finish(bid: Bid) -> Bid { + // Ensure the caller is the auctioneer. + console.assert_eq(self.caller, aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh); + // Return 'is_winner' as 'true' in the winning 'Bid'. + return Bid { + owner: bid.bidder, + gates: bid.gates, + bidder: bid.bidder, + amount: bid.amount, + is_winner: true, + }; + } } diff --git a/basic_bank/src/main.leo b/basic_bank/src/main.leo index 98a4cce..447aca3 100644 --- a/basic_bank/src/main.leo +++ b/basic_bank/src/main.leo @@ -1,107 +1,108 @@ -// A token, issued by a bank. -// - 'owner' : The address of the account that owns the record associated with this token. -// - 'gates' : The value associated with the record (always zero). -// - 'amount' : The amount of tokens owned by the account. -record Token { - owner: address, - gates: u64, - amount: u64, -} - -// An on-chain mapping, storing the amount of tokens owned by each account -// The account is stored as a to preserve user privacy. -mapping balances: field => u64; - -// Returns a new Token. -// - `owner` : The address of the account to issue the token to. -// - `amount`: The amount of tokens to issue. -// Requires that the function caller is the bank. -// The bank's address is aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a. -@program -function issue(owner: address, amount: u64) -> Token { - console.assert_eq(self.caller, aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a); - return Token { - owner: owner, - gates: 0u64, - amount: amount, - }; -} +// The `program` scope defines the data types, functions, and state associated with the `basic_bank` program. +program basic_bank.aleo { + // A token, issued by a bank. + // - 'owner' : The address of the account that owns the record associated with this token. + // - 'gates' : The value associated with the record (always zero). + // - 'amount' : The amount of tokens owned by the account. + record Token { + owner: address, + gates: u64, + amount: u64, + } -// Deposits some amount of money into the bank. -// Returns a new Token with the remaining amount of money. -// - `token` : A record containing tokens to deposit. -// - `amount`: The amount of tokens to deposit. -@program -function deposit(token: Token, amount: u64) -> Token { - let difference: u64 = token.amount - amount; + // An on-chain mapping, storing the amount of tokens owned by each account + // The account is stored as a to preserve user privacy. + mapping balances: field => u64; + + // Returns a new Token. + // - `owner` : The address of the account to issue the token to. + // - `amount`: The amount of tokens to issue. + // Requires that the function caller is the bank. + // The bank's address is aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a. + transition issue(owner: address, amount: u64) -> Token { + console.assert_eq(self.caller, aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a); + return Token { + owner: owner, + gates: 0u64, + amount: amount, + }; + } - let remaining: Token = Token { - owner: token.owner, - gates: token.gates, - amount: difference, - }; + // Deposits some amount of money into the bank. + // Returns a new Token with the remaining amount of money. + // - `token` : A record containing tokens to deposit. + // - `amount`: The amount of tokens to deposit. + transition deposit(token: Token, amount: u64) -> Token { + let difference: u64 = token.amount - amount; - // Compute the hash of the token owner. - let hash: field = BHP256::hash(token.owner); + let remaining: Token = Token { + owner: token.owner, + gates: token.gates, + amount: difference, + }; - async finalize(hash, amount); + // Compute the hash of the token owner. + let hash: field = BHP256::hash(token.owner); - return remaining; -} + async finalize(hash, amount); -// Updates on-chain state by the amount of tokens deposited. -// - `hash` : The hash of the token owner. -// - `amount`: The amount of tokens that were deposited. -finalize deposit(hash: field, amount: u64) { - increment(balances, hash, amount); -} + return remaining; + } -// Returns a new Token containing the amount of money withdrawn. -// - `recipient`: The address of the account to withdraw the tokens to. -// - `amount` : The amount of tokens to withdraw. -// - `rate` : The compound interest rate. -// - `periods` : The number of periods to compound the interest over. -// Requires that the function caller is the bank. -@program -function withdraw(recipient: address, amount: u64, rate: u64, periods: u64) -> Token { - console.assert_eq(self.caller, aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a); - let hash: field = BHP256::hash(recipient); + // Updates on-chain state by the amount of tokens deposited. + // - `hash` : The hash of the token owner. + // - `amount`: The amount of tokens that were deposited. + finalize deposit(hash: field, amount: u64) { + increment(balances, hash, amount); + } - let total: u64 = calculate_interest(amount, rate, periods); + // Returns a new Token containing the amount of money withdrawn. + // - `recipient`: The address of the account to withdraw the tokens to. + // - `amount` : The amount of tokens to withdraw. + // - `rate` : The compound interest rate. + // - `periods` : The number of periods to compound the interest over. + // Requires that the function caller is the bank. + transition withdraw(recipient: address, amount: u64, rate: u64, periods: u64) -> Token { + console.assert_eq(self.caller, aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a); + let hash: field = BHP256::hash(recipient); - let token: Token = Token { - owner: recipient, - gates: 0u64, - amount: total, - }; + let total: u64 = calculate_interest(amount, rate, periods); - async finalize(hash, amount); + let token: Token = Token { + owner: recipient, + gates: 0u64, + amount: total, + }; - return token; -} + async finalize(hash, amount); -// Updates on-chain state by the amount of tokens withdrawn. -// - `hash` : The hash of the token owner. -// - `amount`: The amount of tokens that were withdrawn. -finalize withdraw(hash: field, amount: u64) { - decrement(balances, hash, amount); -} + return token; + } -// Returns the total amount of tokens after compounding interest. -// - `principal`: The amount of tokens to compound interest over. -// - `rate` : The compound interest rate. -// - `periods` : The number of periods to compound the interest over. -function calculate_interest(principal: u64, rate: u64, periods: u64) -> u64 { - let amount: u64 = principal; + // Updates on-chain state by the amount of tokens withdrawn. + // - `hash` : The hash of the token owner. + // - `amount`: The amount of tokens that were withdrawn. + finalize withdraw(hash: field, amount: u64) { + decrement(balances, hash, amount); + } - for i:u64 in 0u64..100u64 { - if i < periods { - amount += (amount * rate) / 10000u64; + // Returns the total amount of tokens after compounding interest. + // - `principal`: The amount of tokens to compound interest over. + // - `rate` : The compound interest rate. + // - `periods` : The number of periods to compound the interest over. + function calculate_interest(principal: u64, rate: u64, periods: u64) -> u64 { + let amount: u64 = principal; + + for i:u64 in 0u64..100u64 { + if i < periods { + amount += (amount * rate) / 10000u64; + } } + + return amount; } - return amount; -} +} diff --git a/battleship/imports/board.leo b/battleship/imports/board.leo index d2df93d..d62b1cf 100644 --- a/battleship/imports/board.leo +++ b/battleship/imports/board.leo @@ -1,117 +1,118 @@ -// Battleship boards are represented by 8x8 squares. -// A u64 is all that is required to represent a hit or a miss on a single board. -// Starting from the top row, left to right, a hit is 1 and a miss is 0. -// A first move resulting in a hit in row 1, column 3 would be: -// 00100000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 -// A second u64 is needed to represent which squares have been played, with 1s being played squares and 0s being -// unplayed squares. -record board_state { - owner: address, - gates: u64, - // The hits and misses registered on the opponent's board. - hits_and_misses: u64, - // The squares that have been played on the opponent's board. - played_tiles: u64, - // The ship bitstring representing all ship positions on your own board - ships: u64, - player_1: address, - player_2: address, - game_started: bool, -} +// The `program` scope defines the data types, functions, and state associated with the `board` program. +program board.aleo { + // Battleship boards are represented by 8x8 squares. + // A u64 is all that is required to represent a hit or a miss on a single board. + // Starting from the top row, left to right, a hit is 1 and a miss is 0. + // A first move resulting in a hit in row 1, column 3 would be: + // 00100000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 + // A second u64 is needed to represent which squares have been played, with 1s being played squares and 0s being + // unplayed squares. + record board_state { + owner: address, + gates: u64, + // The hits and misses registered on the opponent's board. + hits_and_misses: u64, + // The squares that have been played on the opponent's board. + played_tiles: u64, + // The ship bitstring representing all ship positions on your own board + ships: u64, + player_1: address, + player_2: address, + game_started: bool, + } -// Returns a new board_state. -@program -function new_board_state( - ships: u64, - opponent: address, -) -> board_state { - return board_state { - owner: self.caller, - gates: 0u64, - hits_and_misses: 0u64, - played_tiles: 0u64, - ships, - player_1: self.caller, - player_2: opponent, - game_started: false, - }; -} + // Returns a new board_state. + transition new_board_state( + ships: u64, + opponent: address, + ) -> board_state { + return board_state { + owner: self.caller, + gates: 0u64, + hits_and_misses: 0u64, + played_tiles: 0u64, + ships, + player_1: self.caller, + player_2: opponent, + game_started: false, + }; + } -// Returns a new board state that has been started. -// Fails if this board has been started before. -@program -function start_board( - // The record of the board to start. A board can only be started once. - board: board_state, -) -> board_state { - // Ensure this board hasn't been used to start a game before. - console.assert(!board.game_started); + // Returns a new board state that has been started. + // Fails if this board has been started before. + transition start_board( + // The record of the board to start. A board can only be started once. + board: board_state, + ) -> board_state { + // Ensure this board hasn't been used to start a game before. + console.assert(!board.game_started); - return board_state { - owner: board.owner, - gates: board.gates, - hits_and_misses: board.hits_and_misses, - played_tiles: board.played_tiles, - ships: board.ships, - player_1: board.player_1, - player_2: board.player_2, - game_started: true, - }; -} + return board_state { + owner: board.owner, + gates: board.gates, + hits_and_misses: board.hits_and_misses, + played_tiles: board.played_tiles, + ships: board.ships, + player_1: board.player_1, + player_2: board.player_2, + game_started: true, + }; + } -// Returns a new board state record that includes all the played tiles. -// Fails if r1 has been played before. -@program -function update_played_tiles( - // The record of the board to update. - board: board_state, - // The u64 equivalent of a bitstring fire coordinate to send to the opponent. - shoot: u64, -) -> board_state { - // Need to make sure r1 is a valid move. Only one bit of r1 should be flipped. - let flip_bit: u64 = shoot - 1u64; - // bitwise and operation - let check_move: u64 = shoot & flip_bit; - console.assert_eq(check_move, 0u64); + // Returns a new board state record that includes all the played tiles. + // Fails if r1 has been played before. + transition update_played_tiles( + // The record of the board to update. + board: board_state, + // The u64 equivalent of a bitstring fire coordinate to send to the opponent. + shoot: u64, + ) -> board_state { + // Need to make sure r1 is a valid move. Only one bit of r1 should be flipped. + let flip_bit: u64 = shoot - 1u64; + // bitwise and operation + let check_move: u64 = shoot & flip_bit; + console.assert_eq(check_move, 0u64); - // Need to make sure r1 is a valid move given the played_tiles. no bits should overlap. - let check_tiles: u64 = shoot & board.played_tiles; - console.assert_eq(check_tiles, 0u64); + // Need to make sure r1 is a valid move given the played_tiles. no bits should overlap. + let check_tiles: u64 = shoot & board.played_tiles; + console.assert_eq(check_tiles, 0u64); - // Update played tiles. - let played_tiles: u64 = board.played_tiles | shoot; + // Update played tiles. + let played_tiles: u64 = board.played_tiles | shoot; - return board_state { - owner: board.owner, - gates: board.gates, - hits_and_misses: board.hits_and_misses, - played_tiles, - ships: board.ships, - player_1: board.player_1, - player_2: board.player_2, - game_started: board.game_started, - }; -} + return board_state { + owner: board.owner, + gates: board.gates, + hits_and_misses: board.hits_and_misses, + played_tiles, + ships: board.ships, + player_1: board.player_1, + player_2: board.player_2, + game_started: board.game_started, + }; + } -// Returns a new board state record that includes all the hits and misses. -@program -function update_hits_and_misses( - // The record of the board to update. - board: board_state, - // The u64 equivalent of a bitstring of whether this player's previous move was a hit or miss. - hit_or_miss: u64, -) -> board_state { - // Update hits and misses. - let hits_and_misses: u64 = board.hits_and_misses | hit_or_miss; + // Returns a new board state record that includes all the hits and misses. + transition update_hits_and_misses( + // The record of the board to update. + board: board_state, + // The u64 equivalent of a bitstring of whether this player's previous move was a hit or miss. + hit_or_miss: u64, + ) -> board_state { + // Update hits and misses. + let hits_and_misses: u64 = board.hits_and_misses | hit_or_miss; - return board_state { - owner: board.owner, - gates: board.gates, - hits_and_misses, - played_tiles: board.played_tiles, - ships: board.ships, - player_1: board.player_1, - player_2: board.player_2, - game_started: board.game_started, - }; + return board_state { + owner: board.owner, + gates: board.gates, + hits_and_misses, + played_tiles: board.played_tiles, + ships: board.ships, + player_1: board.player_1, + player_2: board.player_2, + game_started: board.game_started, + }; + } } + + diff --git a/battleship/imports/move.leo b/battleship/imports/move.leo index 9ec81eb..6cd1f3c 100644 --- a/battleship/imports/move.leo +++ b/battleship/imports/move.leo @@ -1,48 +1,48 @@ -record move { - owner: address, - gates: u64, - incoming_fire_coordinate: u64, - player_1: address, - player_2: address, - // One flipped bit indicates a hit. No flipped bits indicates a miss. - prev_hit_or_miss: u64, -} +// The `program` scope defines the data types, functions, and state associated with the `move` program. +program move.aleo { + record move { + owner: address, + gates: u64, + incoming_fire_coordinate: u64, + player_1: address, + player_2: address, + // One flipped bit indicates a hit. No flipped bits indicates a miss. + prev_hit_or_miss: u64, + } -// Returns new move record owned by the opponent. -@program -function create_move( - // The move record created by the opponent. - move_record: move, - // The u64 representation of incoming_fire_coordinate, the bitstring fire coordinate to send to the opponent. - incoming_fire_coordinate: u64, - // The u64 representation of prev_hit_or_miss, this player's previous fire coordinate as a hit or miss. - prev_hit_or_miss: u64, -) -> move { - // A new move record should be created and owned by the opponent. - let one_is_owner: bool = move_record.player_1 == move_record.owner; - let opponent: address = one_is_owner ? move_record.player_2 : move_record.player_1; + // Returns new move record owned by the opponent. + transition create_move( + // The move record created by the opponent. + move_record: move, + // The u64 representation of incoming_fire_coordinate, the bitstring fire coordinate to send to the opponent. + incoming_fire_coordinate: u64, + // The u64 representation of prev_hit_or_miss, this player's previous fire coordinate as a hit or miss. + prev_hit_or_miss: u64, + ) -> move { + // A new move record should be created and owned by the opponent. + let one_is_owner: bool = move_record.player_1 == move_record.owner; + let opponent: address = one_is_owner ? move_record.player_2 : move_record.player_1; - return move { - owner: opponent, - gates: move_record.gates, - incoming_fire_coordinate, - player_1: move_record.player_2, - player_2: move_record.player_1, - prev_hit_or_miss, - }; -} + return move { + owner: opponent, + gates: move_record.gates, + incoming_fire_coordinate, + player_1: move_record.player_2, + player_2: move_record.player_1, + prev_hit_or_miss, + }; + } -// Returns the move record owned by the opponent. -// Note, this move record contains dummy fire coordinates and previous hit or miss. -@program -function start_game(player_2: address) -> move { - return move { - owner: player_2, - gates: 0u64, - incoming_fire_coordinate: 0u64, - player_1: self.caller, - player_2: player_2, - prev_hit_or_miss: 0u64, - }; + // Returns the move record owned by the opponent. + // Note, this move record contains dummy fire coordinates and previous hit or miss. + transition start_game(player_2: address) -> move { + return move { + owner: player_2, + gates: 0u64, + incoming_fire_coordinate: 0u64, + player_1: self.caller, + player_2: player_2, + prev_hit_or_miss: 0u64, + }; + } } - diff --git a/battleship/imports/verify.leo b/battleship/imports/verify.leo index 04aa3ec..84fd4dd 100644 --- a/battleship/imports/verify.leo +++ b/battleship/imports/verify.leo @@ -1,125 +1,126 @@ -// Returns the number of flipped bits. -// E.g. 17870283321406128128u64, in binary 11111000 00000000 00000000 00000000 00000000 00000000 00000000 00000000, -// returns 5u64; -function bitcount(bits: u64) -> u64 { - let r1: u64 = bits / 2u64; - let r2: u64 = bits / 4u64; - let r3: u64 = bits / 8u64; - - let r4: u64 = r1 & 8608480567731124087u64; - let r5: u64 = r2 & 3689348814741910323u64; - let r6: u64 = r3 & 1229782938247303441u64; - - let r7: u64 = bits - r4 - r5 - r6; - - let r8: u64 = r7 / 16u64; - let r9: u64 = r7 + r8; - let r10: u64 = r9 & 1085102592571150095u64; - let r11: u64 = r10 % 255u64; - - return r11; +// The `program` scope defines the data types, functions, and state associated with the `verify` program. +program verify.aleo { + // Returns the number of flipped bits. + // E.g. 17870283321406128128u64, in binary 11111000 00000000 00000000 00000000 00000000 00000000 00000000 00000000, + // returns 5u64; + function bitcount(bits: u64) -> u64 { + let r1: u64 = bits / 2u64; + let r2: u64 = bits / 4u64; + let r3: u64 = bits / 8u64; + + let r4: u64 = r1 & 8608480567731124087u64; + let r5: u64 = r2 & 3689348814741910323u64; + let r6: u64 = r3 & 1229782938247303441u64; + + let r7: u64 = bits - r4 - r5 - r6; + + let r8: u64 = r7 / 16u64; + let r9: u64 = r7 + r8; + let r10: u64 = r9 & 1085102592571150095u64; + let r11: u64 = r10 % 255u64; + + return r11; + } + + // Returns boolean of whether all the flipped bits in location are "adjacent". Horizontally, this means all flipped bits are + // directly next to each other (111). Vertically, this means all flipped bits are separated by 7 unflipped bits + // (10000000100000001). + function adjacency_check( + // The u64 representation of a ship's placement in an 8x8 grid. + ship: u64, + // The u64 representation of a ship's bitstring, either horizontally or vertically. + // E.g. a ship of length 3's bit string horizontally would be: 000111 = 7u64. Vertically, the bit string would be: + // 10000000100000001 = 65793u64. + orientation: u64, + ) -> bool { + // This may result in 0. + let division: u64 = ship / orientation; + + // subtracting 1 from 0 will cause an underflow, so we should check for this edge case. + let is_eq: bool = division == 0u64; + + // if the above division resulted in 0, we know the adjacency check should return false. + // Setting to r4 to 3 (11) will guarantee failure here. + let ternary: u64 = is_eq ? 3u64 : division; + let subtraction: u64 = ternary - 1u64; + let and: u64 = subtraction & ternary; + + let bits_are_adjacent: bool = and == 0u64; + + return bits_are_adjacent; + } + + // Returns boolean of whether adjacent flipped bits don't split a row of size 8. + // E.g. 111000000 has adjacent flipped bits but splits a row: 00000001 11000000 + function horizontal_check( + // The u64 representation of a ship's placement in an 8x8 grid. + ship: u64, + // The u64 representation of a ship's bitstring horizontally. + horizontal: u64, + ) -> bool { + let remainder: u64 = ship % 255u64; + // This may result in 0. + let division: u64 = remainder / horizontal; + + // Subtracting 1 from 0 will cause an underflow. + let is_eq: bool = division == 0u64; + + // Setting to 3 will guarantee failure. + let ternary: u64 = is_eq ? 3u64 : division; + let subtraction: u64 = ternary - 1u64; + let and: u64 = subtraction & ternary; + + let bits_split_row: bool = and == 0u64; + + return bits_split_row; + } + + // Returns `true` if the ship placement is valid. + transition validate_ship( + // The u64 representation of a ship's placement in an 8x8 grid. + ship: u64, + // The length of the placed ship. + length: u64, + // The u64 equivalent of a ship's horizontal bitstring representation. + horizontal: u64, + // The u64 equivalent of a ship's vertical bitstring representation. + vertical: u64, + ) -> bool { + // Check bitcount -- all other validations depend on the bitcount being correct. + let num_bits: u64 = bitcount(ship); + console.assert_eq(num_bits, length); + + // Check horizontal bits of ship. + let is_adjacent: bool = adjacency_check(ship, horizontal); // True if bits are adjacent horizontally. + let is_horizontal: bool = horizontal_check(ship, horizontal); // True if those horizontal bits are not split across rows. + let valid_horizontal: bool = is_adjacent && is_horizontal; // True if bits are adjacent horizontally and not split across rows. + + // Check vertical bits of ship. + let valid_vertical: bool = adjacency_check(ship, vertical); // True if bits are adjacent vertically. + + let ship_is_valid: bool = valid_horizontal || valid_vertical; // Ship is valid if it is vertically or horizontally valid. + + return ship_is_valid; + } + + // Returns the u64 representation of all the ships' placements in an 8x8 grid. This function will fail + // if any of the ship placements overlap each other. + transition create_board( + // The u64 representation of a carrier's placement in an 8x8 grid. Length = 5. + carrier: u64, + // The u64 representation of a battleship's placement in an 8x8 grid. Length = 4. + battleship: u64, + // The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3. + cruiser: u64, + // The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2. + destroyer: u64, + ) -> u64 { + // Bitwise combine the ship placements together + let ships: u64 = carrier | battleship | cruiser | destroyer; + + let num_bits: u64 = bitcount(ships); + console.assert_eq(num_bits, 14u64); // Given 4 individually-valid ships, a valid combination should yield exactly 14 flipped bits. + + return ships; + } } - -// Returns boolean of whether all the flipped bits in location are "adjacent". Horizontally, this means all flipped bits are -// directly next to each other (111). Vertically, this means all flipped bits are separated by 7 unflipped bits -// (10000000100000001). -function adjacency_check( - // The u64 representation of a ship's placement in an 8x8 grid. - ship: u64, - // The u64 representation of a ship's bitstring, either horizontally or vertically. - // E.g. a ship of length 3's bit string horizontally would be: 000111 = 7u64. Vertically, the bit string would be: - // 10000000100000001 = 65793u64. - orientation: u64, -) -> bool { - // This may result in 0. - let division: u64 = ship / orientation; - - // subtracting 1 from 0 will cause an underflow, so we should check for this edge case. - let is_eq: bool = division == 0u64; - - // if the above division resulted in 0, we know the adjacency check should return false. - // Setting to r4 to 3 (11) will guarantee failure here. - let ternary: u64 = is_eq ? 3u64 : division; - let subtraction: u64 = ternary - 1u64; - let and: u64 = subtraction & ternary; - - let bits_are_adjacent: bool = and == 0u64; - - return bits_are_adjacent; -} - -// Returns boolean of whether adjacent flipped bits don't split a row of size 8. -// E.g. 111000000 has adjacent flipped bits but splits a row: 00000001 11000000 -function horizontal_check( - // The u64 representation of a ship's placement in an 8x8 grid. - ship: u64, - // The u64 representation of a ship's bitstring horizontally. - horizontal: u64, -) -> bool { - let remainder: u64 = ship % 255u64; - // This may result in 0. - let division: u64 = remainder / horizontal; - - // Subtracting 1 from 0 will cause an underflow. - let is_eq: bool = division == 0u64; - - // Setting to 3 will guarantee failure. - let ternary: u64 = is_eq ? 3u64 : division; - let subtraction: u64 = ternary - 1u64; - let and: u64 = subtraction & ternary; - - let bits_split_row: bool = and == 0u64; - - return bits_split_row; -} - -// Returns `true` if the ship placement is valid. -@program -function validate_ship( - // The u64 representation of a ship's placement in an 8x8 grid. - ship: u64, - // The length of the placed ship. - length: u64, - // The u64 equivalent of a ship's horizontal bitstring representation. - horizontal: u64, - // The u64 equivalent of a ship's vertical bitstring representation. - vertical: u64, -) -> bool { - // Check bitcount -- all other validations depend on the bitcount being correct. - let num_bits: u64 = bitcount(ship); - console.assert_eq(num_bits, length); - - // Check horizontal bits of ship. - let is_adjacent: bool = adjacency_check(ship, horizontal); // True if bits are adjacent horizontally. - let is_horizontal: bool = horizontal_check(ship, horizontal); // True if those horizontal bits are not split across rows. - let valid_horizontal: bool = is_adjacent && is_horizontal; // True if bits are adjacent horizontally and not split across rows. - - // Check vertical bits of ship. - let valid_vertical: bool = adjacency_check(ship, vertical); // True if bits are adjacent vertically. - - let ship_is_valid: bool = valid_horizontal || valid_vertical; // Ship is valid if it is vertically or horizontally valid. - - return ship_is_valid; -} - -// Returns the u64 representation of all the ships' placements in an 8x8 grid. This function will fail -// if any of the ship placements overlap each other. -@program -function create_board( - // The u64 representation of a carrier's placement in an 8x8 grid. Length = 5. - carrier: u64, - // The u64 representation of a battleship's placement in an 8x8 grid. Length = 4. - battleship: u64, - // The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3. - cruiser: u64, - // The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2. - destroyer: u64, -) -> u64 { - // Bitwise combine the ship placements together - let ships: u64 = carrier | battleship | cruiser | destroyer; - - let num_bits: u64 = bitcount(ships); - console.assert_eq(num_bits, 14u64); // Given 4 individually-valid ships, a valid combination should yield exactly 14 flipped bits. - - return ships; -} \ No newline at end of file diff --git a/battleship/src/main.leo b/battleship/src/main.leo index 5032f7d..94f427d 100644 --- a/battleship/src/main.leo +++ b/battleship/src/main.leo @@ -1,106 +1,106 @@ -// The 'battleship.leo' program. +// The imported programs. import board.leo; import move.leo; import verify.leo; -// Returns a new record representing a new game of battleship. -@program -function initialize_board( - // The u64 representation of a carrier's placement in an 8x8 grid. Length = 5. - carrier: u64, - // The u64 representation of a battleship's placement in an 8x8 grid. Length = 4. - battleship: u64, - // The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3. - cruiser: u64, - // The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2. - destroyer: u64, - // The address of the opponent. - player: address, -) -> board.leo/board_state.record { - // Verify that each individual ship placement bitstring is valid. - let valid_carrier: bool = verify.leo/validate_ship(carrier, 5u64, 31u64, 4311810305u64); - console.assert(valid_carrier); - - let valid_battleship: bool = verify.leo/validate_ship(battleship, 4u64, 15u64, 16843009u64); - console.assert(valid_battleship); - - let valid_cruiser: bool = verify.leo/validate_ship(cruiser, 3u64, 7u64, 65793u64); - console.assert(valid_cruiser); - - let valid_destroyer: bool = verify.leo/validate_ship(destroyer, 2u64, 3u64, 257u64); - console.assert(valid_destroyer); - - // Create the board with all the ship placements combined. - let board: u64 = verify.leo/create_board(carrier, battleship, cruiser, destroyer); - - // Initialize the board state record. - let state: board_state = board.leo/new_board_state(board, player); - - return state; +// The `program` scope defines the data types, functions, and state associated with the `battleship` program. +program battleship.aleo { + // Returns a new record representing a new game of battleship. + transition initialize_board( + // The u64 representation of a carrier's placement in an 8x8 grid. Length = 5. + carrier: u64, + // The u64 representation of a battleship's placement in an 8x8 grid. Length = 4. + battleship: u64, + // The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3. + cruiser: u64, + // The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2. + destroyer: u64, + // The address of the opponent. + player: address, + ) -> board.leo/board_state.record { + // Verify that each individual ship placement bitstring is valid. + let valid_carrier: bool = verify.leo/validate_ship(carrier, 5u64, 31u64, 4311810305u64); + console.assert(valid_carrier); + + let valid_battleship: bool = verify.leo/validate_ship(battleship, 4u64, 15u64, 16843009u64); + console.assert(valid_battleship); + + let valid_cruiser: bool = verify.leo/validate_ship(cruiser, 3u64, 7u64, 65793u64); + console.assert(valid_cruiser); + + let valid_destroyer: bool = verify.leo/validate_ship(destroyer, 2u64, 3u64, 257u64); + console.assert(valid_destroyer); + + // Create the board with all the ship placements combined. + let board: u64 = verify.leo/create_board(carrier, battleship, cruiser, destroyer); + + // Initialize the board state record. + let state: board_state = board.leo/new_board_state(board, player); + + return state; + } + + // Returns an updated board state record that has been started. This board cannot be used to start any other games. + // Returns a dummy move record owned by the opponent. + // This function commits a given board to a game with an opponent and creates the initial dummy move. + transition offer_battleship( + // The board record to start a game with. + board: board.leo/board_state.record, + ) -> (board.leo/board_state.record, move.leo/move.record) { + let state: board_state = board.leo/start_board(board); + let dummy: move = move.leo/start_game(board.player_2); + + return (state, dummy); + } + + // Returns updated board_state.record that has been started and can no longer be used to join or start new games. + // Returns dummy move record owned by the opponent. + transition start_battleship( + // The board record to play the game with. + board: board.leo/board_state.record, + // The move record to play to begin the game. This should be the dummy move record created from offer_battleship. + move_start: move.leo/move.record, + ) -> (board.leo/board_state.record, move.leo/move.record) { + // Validate that the move players and board players match each other. + console.assert_eq(board.player_1, move_start.player_2); + console.assert_eq(board.player_2, move_start.player_1); + + let state: board_state = board.leo/start_board(board); + let dummy: move = move.leo/start_game(board.player_2); + + return (state, dummy); + } + + // Returns updated board record. + // Returns new move record owned by opponent. + transition play( + // The board record to update. + board: board.leo/board_state.record, + // The incoming move from the opponent. + move_incoming: move.leo/move.record, + // The u64 equivalent of the bitwise representation of the next coordinate to play on the opponent's board. + shoot: u64, + ) -> (board.leo/board_state.record, move.leo/move.record) { + // Verify the board has been started. This prevents players from starting a game and then creating + // a brand new board to play with. + console.assert(board.game_started); + + // Validate that the move players and board players match each other. + console.assert_eq(board.player_1, move_incoming.player_2); + console.assert_eq(board.player_2, move_incoming.player_1); + + // Play coordinate on own board. Will fail if not a valid move. + let hit_or_miss: board_state = board.leo/update_played_tiles(board, shoot); + + // Update own board with result of last shot. + let next_board: board_state = board.leo/update_hits_and_misses(hit_or_miss, move_incoming.prev_hit_or_miss); + + // Assess whether incoming fire coordinate is a hit. + let is_hit: u64 = move_incoming.incoming_fire_coordinate & board.ships; + + let next_move: move = move.leo/create_move(move_incoming, shoot, is_hit); + + return (next_board, next_move); + } } -// Returns an updated board state record that has been started. This board cannot be used to start any other games. -// Returns a dummy move record owned by the opponent. -// This function commits a given board to a game with an opponent and creates the initial dummy move. -@program -function offer_battleship( - // The board record to start a game with. - board: board.leo/board_state.record, -) -> (board.leo/board_state.record, move.leo/move.record) { - let state: board_state = board.leo/start_board(board); - let dummy: move = move.leo/start_game(board.player_2); - - return (state, dummy); -} - -// Returns updated board_state.record that has been started and can no longer be used to join or start new games. -// Returns dummy move record owned by the opponent. -@program -function start_battleship( - // The board record to play the game with. - board: board.leo/board_state.record, - // The move record to play to begin the game. This should be the dummy move record created from offer_battleship. - move_start: move.leo/move.record, -) -> (board.leo/board_state.record, move.leo/move.record) { - // Validate that the move players and board players match each other. - console.assert_eq(board.player_1, move_start.player_2); - console.assert_eq(board.player_2, move_start.player_1); - - let state: board_state = board.leo/start_board(board); - let dummy: move = move.leo/start_game(board.player_2); - - return (state, dummy); -} - -// Returns updated board record. -// Returns new move record owned by opponent. -@program -function play( - // The board record to update. - board: board.leo/board_state.record, - // The incoming move from the opponent. - move_incoming: move.leo/move.record, - // The u64 equivalent of the bitwise representation of the next coordinate to play on the opponent's board. - shoot: u64, -) -> (board.leo/board_state.record, move.leo/move.record) { - // Verify the board has been started. This prevents players from starting a game and then creating - // a brand new board to play with. - console.assert(board.game_started); - - // Validate that the move players and board players match each other. - console.assert_eq(board.player_1, move_incoming.player_2); - console.assert_eq(board.player_2, move_incoming.player_1); - - // Play coordinate on own board. Will fail if not a valid move. - let hit_or_miss: board_state = board.leo/update_played_tiles(board, shoot); - - // Update own board with result of last shot. - let next_board: board_state = board.leo/update_hits_and_misses(hit_or_miss, move_incoming.prev_hit_or_miss); - - // Assess whether incoming fire coordinate is a hit. - let is_hit: u64 = move_incoming.incoming_fire_coordinate & board.ships; - - let next_move: move = move.leo/create_move(move_incoming, shoot, is_hit); - - return (next_board, next_move); -} \ No newline at end of file diff --git a/tictactoe/src/main.leo b/tictactoe/src/main.leo index 8940d5f..a2c44d4 100644 --- a/tictactoe/src/main.leo +++ b/tictactoe/src/main.leo @@ -1,111 +1,113 @@ -// A row in a tic tac toe board. -// - `c1` : The first entry in the row. -// - `c2` : The second entry in the row. -// - `c3` : The third entry in the row. -// A valid entry is either 0, 1, or 2, where 0 is empty, 1 corresponds to player 1, and 2 corresponds to player 2. -// Any other values are invalid. -struct Row { - c1: u8, - c2: u8, - c3: u8 -} +// The `program` scope defines the data types, functions, and state associated with the `tictactoe` program. +program tictactoe.aleo { + // A row in a tic tac toe board. + // - `c1` : The first entry in the row. + // - `c2` : The second entry in the row. + // - `c3` : The third entry in the row. + // A valid entry is either 0, 1, or 2, where 0 is empty, 1 corresponds to player 1, and 2 corresponds to player 2. + // Any other values are invalid. + struct Row { + c1: u8, + c2: u8, + c3: u8 + } -// A tic tac toe board. -// - `r1` : The first row in the board. -// - `r2` : The second row in the board. -// - `r3` : The third row in the board. -struct Board { - r1: Row, - r2: Row, - r3: Row, -} + // A tic tac toe board. + // - `r1` : The first row in the board. + // - `r2` : The second row in the board. + // - `r3` : The third row in the board. + struct Board { + r1: Row, + r2: Row, + r3: Row, + } -// Returns an empty board. -@program -function new() -> Board { - return Board { - r1: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, - r2: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, - r3: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, - }; -} + // Returns an empty board. + transition new() -> Board { + return Board { + r1: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, + r2: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, + r3: Row { c1: 0u8, c2: 0u8, c3: 0u8 }, + }; + } -// Returns `true` if there exists a row, column, or diagonal with all entries occupied by the same player. -// - `b` : A tic tac toe board. -// - `p` : A number corresponding to a player. -function check_for_win(b: Board, p: u8) -> bool { - return - (b.r1.c1 == p && b.r1.c2 == p && b.r1.c3 == p) || // row 1 - (b.r2.c1 == p && b.r2.c2 == p && b.r2.c3 == p) || // row 2 - (b.r3.c1 == p && b.r3.c3 == p && b.r3.c3 == p) || // row 3 - (b.r1.c1 == p && b.r2.c1 == p && b.r3.c1 == p) || // column 1 - (b.r1.c2 == p && b.r2.c3 == p && b.r3.c2 == p) || // column 2 - (b.r1.c3 == p && b.r2.c3 == p && b.r3.c3 == p) || // column 3 - (b.r1.c1 == p && b.r2.c2 == p && b.r3.c3 == p) || // diagonal - (b.r1.c3 == p && b.r2.c2 == p && b.r3.c1 == p); // other diagonal -} + // Returns `true` if there exists a row, column, or diagonal with all entries occupied by the same player. + // - `b` : A tic tac toe board. + // - `p` : A number corresponding to a player. + function check_for_win(b: Board, p: u8) -> bool { + return + (b.r1.c1 == p && b.r1.c2 == p && b.r1.c3 == p) || // row 1 + (b.r2.c1 == p && b.r2.c2 == p && b.r2.c3 == p) || // row 2 + (b.r3.c1 == p && b.r3.c3 == p && b.r3.c3 == p) || // row 3 + (b.r1.c1 == p && b.r2.c1 == p && b.r3.c1 == p) || // column 1 + (b.r1.c2 == p && b.r2.c3 == p && b.r3.c2 == p) || // column 2 + (b.r1.c3 == p && b.r2.c3 == p && b.r3.c3 == p) || // column 3 + (b.r1.c1 == p && b.r2.c2 == p && b.r3.c3 == p) || // diagonal + (b.r1.c3 == p && b.r2.c2 == p && b.r3.c1 == p); // other diagonal + } -// Returns an updated tic tac toe board with a move made by a player. -// Returns a `u8` corresponding to the player who won the game, or 0 if no one has won yet. -// - `player` : A number corresponding to a player. -// - `row` : The row of the move. -// - `col` : The column of the move. -// - `board` : A tic tac toe board. -// Assumes that `player` is either 1 or 2. -// Assumes that `row` and `col` are valid indices into the board. -// If an entry is already occupied, the move is invalid and the board is returned unchanged. -@program -function make_move(player: u8, row: u8, col: u8, board: Board) -> (Board, u8) { - // Check that inputs are valid. - console.assert(player == 1u8 || player == 2u8); - console.assert(1u8 <= row && row <= 3u8); - console.assert(1u8 <= col && col <= 3u8); + // Returns an updated tic tac toe board with a move made by a player. + // Returns a `u8` corresponding to the player who won the game, or 0 if no one has won yet. + // - `player` : A number corresponding to a player. + // - `row` : The row of the move. + // - `col` : The column of the move. + // - `board` : A tic tac toe board. + // Assumes that `player` is either 1 or 2. + // Assumes that `row` and `col` are valid indices into the board. + // If an entry is already occupied, the move is invalid and the board is returned unchanged. + transition make_move(player: u8, row: u8, col: u8, board: Board) -> (Board, u8) { + // Check that inputs are valid. + console.assert(player == 1u8 || player == 2u8); + console.assert(1u8 <= row && row <= 3u8); + console.assert(1u8 <= col && col <= 3u8); - // Unpack the entries in the board into variables. - let r1c1: u8 = board.r1.c1; - let r1c2: u8 = board.r1.c2; - let r1c3: u8 = board.r1.c3; - let r2c1: u8 = board.r2.c1; - let r2c2: u8 = board.r2.c2; - let r2c3: u8 = board.r2.c3; - let r3c1: u8 = board.r3.c1; - let r3c2: u8 = board.r3.c2; - let r3c3: u8 = board.r3.c3; + // Unpack the entries in the board into variables. + let r1c1: u8 = board.r1.c1; + let r1c2: u8 = board.r1.c2; + let r1c3: u8 = board.r1.c3; + let r2c1: u8 = board.r2.c1; + let r2c2: u8 = board.r2.c2; + let r2c3: u8 = board.r2.c3; + let r3c1: u8 = board.r3.c1; + let r3c2: u8 = board.r3.c2; + let r3c3: u8 = board.r3.c3; - // Update the appropriate entry with the given move. - if row == 1u8 && col == 1u8 && r1c1 == 0u8 { - r1c1 = player; - } else if row == 1u8 && col == 2u8 && r1c2 == 0u8 { - r1c2 = player; - } else if row == 1u8 && col == 3u8 && r1c3 == 0u8 { - r1c3 = player; - } else if row == 2u8 && col == 1u8 && r2c1 == 0u8 { - r2c1 = player; - } else if row == 2u8 && col == 2u8 && r2c2 == 0u8 { - r2c2 = player; - } else if row == 2u8 && col == 3u8 && r2c3 == 0u8 { - r2c3 = player; - } else if row == 3u8 && col == 1u8 && r3c1 == 0u8 { - r3c1 = player; - } else if row == 3u8 && col == 2u8 && r3c2 == 0u8 { - r3c2 = player; - } else if row == 3u8 && col == 3u8 && r3c3 == 0u8 { - r3c3 = player; - } + // Update the appropriate entry with the given move. + if row == 1u8 && col == 1u8 && r1c1 == 0u8 { + r1c1 = player; + } else if row == 1u8 && col == 2u8 && r1c2 == 0u8 { + r1c2 = player; + } else if row == 1u8 && col == 3u8 && r1c3 == 0u8 { + r1c3 = player; + } else if row == 2u8 && col == 1u8 && r2c1 == 0u8 { + r2c1 = player; + } else if row == 2u8 && col == 2u8 && r2c2 == 0u8 { + r2c2 = player; + } else if row == 2u8 && col == 3u8 && r2c3 == 0u8 { + r2c3 = player; + } else if row == 3u8 && col == 1u8 && r3c1 == 0u8 { + r3c1 = player; + } else if row == 3u8 && col == 2u8 && r3c2 == 0u8 { + r3c2 = player; + } else if row == 3u8 && col == 3u8 && r3c3 == 0u8 { + r3c3 = player; + } - // Construct the updated game board. - let updated: Board = Board { - r1: Row { c1: r1c1, c2: r1c2, c3: r1c3 }, - r2: Row { c1: r2c1, c2: r2c2, c3: r2c3 }, - r3: Row { c1: r3c1, c2: r2c2, c3: r2c3 }, - }; + // Construct the updated game board. + let updated: Board = Board { + r1: Row { c1: r1c1, c2: r1c2, c3: r1c3 }, + r2: Row { c1: r2c1, c2: r2c2, c3: r2c3 }, + r3: Row { c1: r3c1, c2: r2c2, c3: r2c3 }, + }; - // Check if the game is over. - if check_for_win(updated, 1u8) { - return (updated, 1u8); - } else if check_for_win(updated, 2u8) { - return (updated, 2u8); - } else { - return (updated, 0u8); + // Check if the game is over. + if check_for_win(updated, 1u8) { + return (updated, 1u8); + } else if check_for_win(updated, 2u8) { + return (updated, 2u8); + } else { + return (updated, 0u8); + } } + } diff --git a/token/src/main.leo b/token/src/main.leo index b560c13..043aca2 100644 --- a/token/src/main.leo +++ b/token/src/main.leo @@ -1,137 +1,134 @@ -// On-chain storage of an `account` map, with `address` as the key, -// and `u64` as the value. -mapping account: address => u64; - -record token { - // The token owner. - owner: address, - // The Aleo balance (in gates). - gates: u64, - // The token amount. - amount: u64, -} - -/* Mint */ - -// The function `mint_public` issues the specified token amount for the token receiver publicly on the network. -@program -function mint_public(public receiver: address, public amount: u64) { - // Mint the tokens publicly by invoking the computation on-chain. - async finalize(receiver, amount); -} - -finalize mint_public(public receiver: address, public amount: u64) { - // Increments `account[receiver]` by `amount`. - // If `account[receiver]` does not exist, it will be created. - // If `account[receiver] + amount` overflows, `mint_public` is reverted. - increment(account, receiver, amount); -} - -// The function `mint_private` initializes a new record with the specified amount of tokens for the receiver. -@program -function mint_private(receiver: address, amount: u64) -> token { - return token { - owner: receiver, - gates: 0u64, - amount: amount, - }; -} - -/* Transfer */ -@program -function transfer_public(public receiver: address, public amount: u64) { - // Transfer the tokens publicly, by invoking the computation on-chain. - async finalize(self.caller, receiver, amount); -} - -finalize transfer_public(public sender: address, public receiver: address, public amount: u64) { - // Decrements `account[sender]` by `amount`. - // If `account[sender]` does not exist, it will be created. - // If `account[sender] - amount` underflows, `transfer_public` is reverted. - decrement(account, sender, amount); - // Increments `account[receiver]` by `amount`. - // If `account[receiver]` does not exist, it will be created. - // If `account[receiver] + amount` overflows, `transfer_public` is reverted. - increment(account, receiver, amount); -} - -// The function `transfer_private` sends the specified token amount to the token receiver from the specified token record. -@program -function transfer_private(sender: token, receiver: address, amount: u64) -> (token, token) { - // Checks the given token record has sufficient balance. - // This `sub` operation is safe, and the proof will fail if an overflow occurs. - // `difference` holds the change amount to be returned to sender. - let difference: u64 = sender.amount - amount; - - // Produce a token record with the change amount for the sender. - let remaining: token = token { - owner: sender.owner, - gates: sender.gates, - amount: difference, - }; - - // Produce a token record for the specified receiver. - let transferred: token = token { - owner: receiver, - gates: 0u64, - amount: amount, - }; - - // Output the sender's change record and the receiver's record. - return (remaining, transferred); -} - -// The function `transfer_private_to_public` turns a specified token amount from a token record into public tokens for the specified receiver. -// This function preserves privacy for the sender's record, however it publicly reveals the token receiver and the token amount. -@program -function transfer_private_to_public(sender: token, public receiver: address, public amount: u64) -> token { - // Checks the given token record has a sufficient token amount. - // This `sub` operation is safe, and the proof will fail if an underflow occurs. - // `difference` holds the change amount for the caller. - let difference: u64 = sender.amount - amount; - - // Produces a token record with the change amount for the caller. - let remaining: token = token { - owner: sender.owner, - gates: sender.gates, - amount: difference, - }; - - // Increment the token amount publicly for the token receiver. - async finalize(receiver, amount); - - // Output the sender's change record. - return remaining; -} - -finalize transfer_private_to_public(public receiver: address, public amount: u64) { - // Increments `account[receiver]` by `amount`. - // If `account[receiver]` does not exist, it will be created. - // If `account[receiver] + amount` overflows, `transfer_private_to_public` is reverted. - increment(account, receiver, amount); -} - -// The function `transfer_public_to_private` turns a specified token amount from `account` into a token record for the specified receiver. -// This function preserves privacy for the receiver's record, however it publicly reveals the caller and the specified token amount. -@program -function transfer_public_to_private(public receiver: address, public amount: u64) -> token { - // Produces a token record for the token receiver. - let transferred: token = token { - owner: receiver, - gates: 0u64, - amount: amount, - }; - - // Decrement the token amount of the caller publicly. - async finalize(self.caller, amount); - - // Output the receiver's record. - return transferred; -} - -finalize transfer_public_to_private(public sender: address, public amount: u64) { - // Decrements `account[sender]` by `amount`. - // If `account[sender]` does not exist, it will be created. - // If `account[sender] - amount` underflows, `transfer_public_to_private` is reverted. - decrement(account, sender, amount); +// The `program` scope defines the data types, functions, and state associated with the `token` program. +program token.aleo { + // On-chain storage of an `account` map, with `address` as the key, + // and `u64` as the value. + mapping account: address => u64; + + record token { + // The token owner. + owner: address, + // The Aleo balance (in gates). + gates: u64, + // The token amount. + amount: u64, + } + + /* Mint */ + + // The function `mint_public` issues the specified token amount for the token receiver publicly on the network. + transition mint_public(public receiver: address, public amount: u64) { + // Mint the tokens publicly by invoking the computation on-chain. + async finalize(receiver, amount); + } + + finalize mint_public(public receiver: address, public amount: u64) { + // Increments `account[receiver]` by `amount`. + // If `account[receiver]` does not exist, it will be created. + // If `account[receiver] + amount` overflows, `mint_public` is reverted. + increment(account, receiver, amount); + } + + // The function `mint_private` initializes a new record with the specified amount of tokens for the receiver. + transition mint_private(receiver: address, amount: u64) -> token { + return token { + owner: receiver, + gates: 0u64, + amount: amount, + }; + } + + /* Transfer */ + transition transfer_public(public receiver: address, public amount: u64) { + // Transfer the tokens publicly, by invoking the computation on-chain. + async finalize(self.caller, receiver, amount); + } + + finalize transfer_public(public sender: address, public receiver: address, public amount: u64) { + // Decrements `account[sender]` by `amount`. + // If `account[sender]` does not exist, it will be created. + // If `account[sender] - amount` underflows, `transfer_public` is reverted. + decrement(account, sender, amount); + // Increments `account[receiver]` by `amount`. + // If `account[receiver]` does not exist, it will be created. + // If `account[receiver] + amount` overflows, `transfer_public` is reverted. + increment(account, receiver, amount); + } + + // The function `transfer_private` sends the specified token amount to the token receiver from the specified token record. + transition transfer_private(sender: token, receiver: address, amount: u64) -> (token, token) { + // Checks the given token record has sufficient balance. + // This `sub` operation is safe, and the proof will fail if an overflow occurs. + // `difference` holds the change amount to be returned to sender. + let difference: u64 = sender.amount - amount; + + // Produce a token record with the change amount for the sender. + let remaining: token = token { + owner: sender.owner, + gates: sender.gates, + amount: difference, + }; + + // Produce a token record for the specified receiver. + let transferred: token = token { + owner: receiver, + gates: 0u64, + amount: amount, + }; + + // Output the sender's change record and the receiver's record. + return (remaining, transferred); + } + + // The function `transfer_private_to_public` turns a specified token amount from a token record into public tokens for the specified receiver. + // This function preserves privacy for the sender's record, however it publicly reveals the token receiver and the token amount. + transition transfer_private_to_public(sender: token, public receiver: address, public amount: u64) -> token { + // Checks the given token record has a sufficient token amount. + // This `sub` operation is safe, and the proof will fail if an underflow occurs. + // `difference` holds the change amount for the caller. + let difference: u64 = sender.amount - amount; + + // Produces a token record with the change amount for the caller. + let remaining: token = token { + owner: sender.owner, + gates: sender.gates, + amount: difference, + }; + + // Increment the token amount publicly for the token receiver. + async finalize(receiver, amount); + + // Output the sender's change record. + return remaining; + } + + finalize transfer_private_to_public(public receiver: address, public amount: u64) { + // Increments `account[receiver]` by `amount`. + // If `account[receiver]` does not exist, it will be created. + // If `account[receiver] + amount` overflows, `transfer_private_to_public` is reverted. + increment(account, receiver, amount); + } + + // The function `transfer_public_to_private` turns a specified token amount from `account` into a token record for the specified receiver. + // This function preserves privacy for the receiver's record, however it publicly reveals the caller and the specified token amount. + transition transfer_public_to_private(public receiver: address, public amount: u64) -> token { + // Produces a token record for the token receiver. + let transferred: token = token { + owner: receiver, + gates: 0u64, + amount: amount, + }; + + // Decrement the token amount of the caller publicly. + async finalize(self.caller, amount); + + // Output the receiver's record. + return transferred; + } + + finalize transfer_public_to_private(public sender: address, public amount: u64) { + // Decrements `account[sender]` by `amount`. + // If `account[sender]` does not exist, it will be created. + // If `account[sender] - amount` underflows, `transfer_public_to_private` is reverted. + decrement(account, sender, amount); + } } diff --git a/vote/src/main.leo b/vote/src/main.leo index 84e7e9f..7628a1d 100644 --- a/vote/src/main.leo +++ b/vote/src/main.leo @@ -1,100 +1,97 @@ -// The 'vote.leo' program. +// The `program` scope defines the data types, functions, and state associated with the `vote` program. +program vote.aleo { + // Proposal details + struct ProposalInfo { + title: field, + content: field, + proposer: address, + } -// Proposal details -struct ProposalInfo { - title: field, - content: field, - proposer: address, -} + // Proposal record records proposal info publicly + record Proposal { + owner: address, + gates: u64, + id: field, + info: ProposalInfo, + } -// Proposal record records proposal info publicly -record Proposal { - owner: address, - gates: u64, - id: field, - info: ProposalInfo, -} + // Save proposal info in public storage. + mapping proposals: field => ProposalInfo; -// Save proposal info in public storage. -mapping proposals: field => ProposalInfo; + // Privacy tickets to vote + record Ticket { + owner: address, + gates: u64, + pid: field, + } -// Privacy tickets to vote -record Ticket { - owner: address, - gates: u64, - pid: field, -} + // Count the total tickets issued for each proposal + mapping tickets: field => u64; -// Count the total tickets issued for each proposal -mapping tickets: field => u64; + mapping agree_votes: field => u64; -mapping agree_votes: field => u64; + mapping disagree_votes: field => u64; -mapping disagree_votes: field => u64; + // Propose a new proposal to vote on. + transition propose(public info: ProposalInfo) -> Proposal { + // Authenticate proposer. + console.assert_eq(self.caller, info.proposer); -// Propose a new proposal to vote on. -@program -function propose(public info: ProposalInfo) -> Proposal { - // Authenticate proposer. - console.assert_eq(self.caller, info.proposer); + // Generate a new proposal id. + let id: field = BHP256::hash(info.title); - // Generate a new proposal id. - let id: field = BHP256::hash(info.title); + // Finalize the proposal id. + async finalize(id); - // Finalize the proposal id. - async finalize(id); + // Return a new record for the proposal. + return Proposal { + owner: self.caller, + gates: 0u64, + id, + info, + }; + } + // Create a new proposal in the "tickets" mapping. + finalize propose(public id: field) { + increment(tickets, id, 0u64); + } - // Return a new record for the proposal. - return Proposal { - owner: self.caller, - gates: 0u64, - id, - info, - }; -} -// Create a new proposal in the "tickets" mapping. -finalize propose(public id: field) { - increment(tickets, id, 0u64); -} + // Create a new ticket to vote with. + transition new_ticket( + public pid: field, + public voter: address, + ) -> Ticket { + // Finalize the proposal id for the ticket. + async finalize(pid); -// Create a new ticket to vote with. -@program -function new_ticket( - public pid: field, - public voter: address, -) -> Ticket { - // Finalize the proposal id for the ticket. - async finalize(pid); + return Ticket { + owner: voter, + gates: 0u64, + pid, + }; + } + // Create a new ticket on a proposal in the "tickets" mapping. + finalize new_ticket(public pid: field) { + increment(tickets, pid, 1u64); + } - return Ticket { - owner: voter, - gates: 0u64, - pid, - }; -} -// Create a new ticket on a proposal in the "tickets" mapping. -finalize new_ticket(public pid: field) { - increment(tickets, pid, 1u64); -} + // Vote privately to agree with a proposal. + transition agree(ticket: Ticket) { + // Finalize this vote. + async finalize(ticket.pid); + } + finalize agree(public pid: field) { + // Publicly increment the number of agree votes. + increment(agree_votes, pid, 1u64); + } -// Vote privately to agree with a proposal. -@program -function agree(ticket: Ticket) { - // Finalize this vote. - async finalize(ticket.pid); -} -finalize agree(public pid: field) { - // Publicly increment the number of agree votes. - increment(agree_votes, pid, 1u64); -} - -// Vote privately to disagree with a proposal. -@program -function disagree(ticket: Ticket) { - // Finalize this vote. - async finalize(ticket.pid); -} -finalize disagree(pid: field) { - // Publicly increment the number of disagree votes. - increment(disagree_votes, pid, 1u64); + // Vote privately to disagree with a proposal. + transition disagree(ticket: Ticket) { + // Finalize this vote. + async finalize(ticket.pid); + } + finalize disagree(pid: field) { + // Publicly increment the number of disagree votes. + increment(disagree_votes, pid, 1u64); + } }