Skip to content

Instantly share code, notes, and snippets.

@kalloc
Created March 27, 2024 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kalloc/160c115f8021c85369f5e7a12a1152d5 to your computer and use it in GitHub Desktop.
Save kalloc/160c115f8021c85369f5e7a12a1152d5 to your computer and use it in GitHub Desktop.
use borsh::{BorshDeserialize, BorshSerialize};
use shank::ShankInstruction;
use solana_program::{
account_info::AccountInfo, declare_id, entrypoint, entrypoint::ProgramResult, msg,
pubkey::Pubkey,
};
pub fn win_check(moves: [u32; 9]) -> u32 {
// Player 1 move will be marked as 1 and player 2 as 2
let [m1, m2, m3, m4, m5, m6, m7, m8, m9] = moves;
if (m1 == 1 && m2 == 1 && m3 == 1)
|| (m1 == 1 && m4 == 1 && m7 == 1)
|| (m7 == 1 && m8 == 1 && m9 == 1)
|| (m3 == 1 && m6 == 1 && m9 == 1)
|| (m1 == 1 && m5 == 1 && m9 == 1)
|| (m3 == 1 && m5 == 1 && m7 == 1)
|| (m2 == 1 && m5 == 1 && m8 == 1)
|| (m4 == 1 && m5 == 1 && m6 == 1)
{
// Condition for Player 1 Win
return 1;
} else if (m1 == 2 && m2 == 2 && m3 == 2)
|| (m1 == 2 && m4 == 2 && m7 == 2)
|| (m7 == 2 && m8 == 2 && m9 == 2)
|| (m3 == 2 && m6 == 2 && m9 == 2)
|| (m1 == 2 && m5 == 2 && m9 == 2)
|| (m3 == 2 && m5 == 2 && m7 == 2)
|| (m2 == 2 && m5 == 2 && m8 == 2)
|| (m4 == 2 && m5 == 2 && m6 == 2)
{
// Condition for Player 2 Win
return 2;
} else if (m1 == 1 || m1 == 2)
&& (m2 == 1 || m2 == 2)
&& (m3 == 1 || m3 == 2)
&& (m4 == 1 || m4 == 2)
&& (m5 == 1 || m5 == 2)
&& (m6 == 1 || m6 == 2)
&& (m7 == 1 || m7 == 2)
&& (m8 == 1 || m8 == 2)
&& (m9 == 1 || m9 == 2)
{
// Condition for Draw
return 3;
} else {
return 0;
}
}
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GameAccount {
pub player1: String,
pub player2: String,
pub moves: [u32; 9],
pub game_status: u32,
pub next_move: u32,
}
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct MoveData {
pub played_by: u32,
pub move_positon: usize,
}
#[derive(BorshSerialize, BorshDeserialize, Debug, ShankInstruction)]
pub enum GameInstruction {
#[account(0, writable, name = "game_account", desc = "The Game Account")]
#[account(1, name = "player1", desc = "The Player 1")]
#[account(2, name = "player2", desc = "The Player 2")]
NewGame,
#[account(0, writable, name = "game_account", desc = "The Game Account")]
#[account(1, name = "player1", desc = "The Player 1")]
#[account(2, name = "player2", desc = "The Player 2")]
Move(MoveData),
}
declare_id!("AaNiPUyjhrNPDt4N8LtoFqjwdJYTeNsuBTjRDi4ubMEb");
entrypoint!(tic_tac_toe);
pub fn tic_tac_toe(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let game_account = &accounts[0];
let player1 = accounts[1].key.to_string();
let player2 = accounts[2].key.to_string();
let instruction =
GameInstruction::try_from_slice(instruction_data).expect("Invalid Instruction Data");
match instruction {
// Create New Game or Reset the Game Data
GameInstruction::NewGame => {
msg!("Instruction 0 Start");
let game_data = GameAccount {
player1,
player2,
moves: [0, 0, 0, 0, 0, 0, 0, 0, 0],
game_status: 0,
next_move: 1,
};
msg!("Game Creation Successful!!");
msg!("Player 1: {:?}", game_data.player1);
msg!("Player 2: {:?}", game_data.player2);
game_data.serialize(&mut &mut game_account.data.borrow_mut()[..])?;
msg!("Instruction 0 End");
}
// Play game!!
GameInstruction::Move(MoveData {
played_by,
move_positon,
}) => {
msg!("Instruction 1 Start");
let mut game_data = GameAccount::try_from_slice(&game_account.data.borrow())?;
if game_data.game_status == 0 {
msg!("Player 1: {:?}", game_data.player1);
msg!("Player 2: {:?}", game_data.player2);
// Verify and updating moves in Game Account
if (game_data.moves[move_positon] == 0) && (game_data.next_move == played_by) {
if game_data.next_move == 1 {
game_data.moves[move_positon] = 1;
game_data.next_move = 2
} else if game_data.next_move == 2 {
game_data.moves[move_positon] = 2;
game_data.next_move = 1
}
} else {
msg!(" Wrong Move");
}
let game_status = win_check(game_data.moves);
match game_status {
0 => {
// Log the next player to move
msg!("Next move: Player {}", game_data.next_move);
}
1 => {
game_data.game_status = 1;
msg!("Player 1 won the game.");
}
2 => {
game_data.game_status = 2;
msg!("Player 2 won the game.");
}
3 => {
game_data.game_status = 3;
msg!("It's a Draw.");
}
_ => {
msg!("Game Error!!");
}
}
// Write the updated data to account.
game_data.serialize(&mut &mut game_account.data.borrow_mut()[..])?;
msg!("Instruction 1 End");
} else {
msg!(" Wrong Move.");
}
}
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment