Created
September 15, 2025 16:47
-
-
Save InfiniteCoder01/f82903a3ac92b7c09eb42203faf594d1 to your computer and use it in GitHub Desktop.
Challenge #3 from @nigelwithrow, this time converting a flwaed Rust version of Rock-Paper-Scissors to C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdbool.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #define FAT_PTR_IMPL(T) \ | |
| typedef struct { \ | |
| void *ptr; \ | |
| T *meta; \ | |
| } FatPtr ## T; | |
| typedef enum { | |
| Rock, | |
| Paper, | |
| Scissors, | |
| } Move; | |
| typedef struct RockPaperScissorsVtable { | |
| Move (*play)(void *self); | |
| } RockPaperScissorsVtable; | |
| FAT_PTR_IMPL(RockPaperScissorsVtable); | |
| // Returns whether player 1 won | |
| bool battle(FatPtrRockPaperScissorsVtable p1, FatPtrRockPaperScissorsVtable p2) { | |
| const Move move1 = p1.meta->play(p1.ptr); | |
| const Move move2 = p2.meta->play(p2.ptr); | |
| if ((move1 == Rock && move2 == Scissors) | |
| || (move1 == Scissors && move2 == Paper) | |
| || (move1 == Paper && move2 == Rock)) { | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| typedef struct {} RandomPlayer; | |
| Move random_player_play(RandomPlayer *self) { | |
| const int r = rand() % 3; | |
| printf("> %d\n", r); | |
| if (r == 0) return Rock; | |
| else if (r == 1) return Paper; | |
| else if (r == 2) return Scissors; | |
| puts("unreachable executed!"); | |
| exit(-1); | |
| } | |
| RockPaperScissorsVtable RANDOM_PLAYER_VTABLE = { | |
| .play = (void *)random_player_play, | |
| }; | |
| int main() { | |
| srand(128); | |
| RandomPlayer p1inner; | |
| RandomPlayer p2inner; | |
| FatPtrRockPaperScissorsVtable p1 = { | |
| .ptr = &p1inner, | |
| .meta = &RANDOM_PLAYER_VTABLE, | |
| }; | |
| FatPtrRockPaperScissorsVtable p2 = { | |
| .ptr = &p2inner, | |
| .meta = &RANDOM_PLAYER_VTABLE, | |
| }; | |
| puts("Best of 3!"); | |
| int p1_won = 0; | |
| for (int i = 0; i < 3; i++) { | |
| if (battle(p1, p2)) p1_won++; | |
| } | |
| if (p1_won >= 2) puts("P1 wins!"); | |
| else puts("P2 wins!"); | |
| return 0; | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use rand::rng; | |
| enum Move { | |
| Rock, | |
| Paper, | |
| Scissors, | |
| } | |
| trait RockPaperScissors { | |
| fn play(&mut self) -> Move; | |
| } | |
| // Returns whether player 1 won | |
| fn battle(p1: &mut dyn RockPaperScissors, p2: &mut dyn RockPaperScissors) -> bool { | |
| use Move::*; | |
| match (p1.play(), p2.play()) { | |
| (Rock, Scissors) | (Scissors, Paper) | (Paper, Rock) => true, | |
| _ => false, | |
| } | |
| } | |
| struct RandomPlayer; | |
| impl RockPaperScissors for RandomPlayer { | |
| fn play(&mut self) -> Move { | |
| use rand::Rng as _; | |
| let mut rng = rng(); | |
| match rng.random::<u8>() % 3 { | |
| 0 => Move::Rock, | |
| 1 => Move::Paper, | |
| 2 => Move::Scissors, | |
| _ => unreachable!(), | |
| } | |
| } | |
| } | |
| fn main() { | |
| let mut p1 = RandomPlayer; | |
| let mut p2 = RandomPlayer; | |
| println!("Best of 3!"); | |
| let p1_won = (0..3).fold(0, |p1_won, _| { | |
| if battle(&mut p1, &mut p2) { | |
| p1_won + 1 | |
| } else { | |
| p1_won | |
| } | |
| }); | |
| if p1_won >= 2 { | |
| println!("P1 wins!"); | |
| } else { | |
| println!("P2 wins!"); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment