Created
July 2, 2024 22:07
-
-
Save Lorenzobattistela/1484a94f29cd5225fc4e0fec3b25f37f to your computer and use it in GitHub Desktop.
UNO! This is a 2 player uno simulation written in bend!
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
# -------------------------- | |
# optimization possibility: use List/got instead of successive removes + igets | |
type Option: | |
None | |
Some { value } | |
def List/got(idx,list): | |
switch idx: | |
case 0: | |
match list: | |
case List/Nil: | |
return (Option/None, []) | |
case List/Cons: | |
return (Option/Some(list.head), list.tail) | |
case _: | |
match list: | |
case List/Nil: | |
return (Option/None, []) | |
case List/Cons: | |
(elem, tail) = List/got((idx - 1), list.tail) | |
return (elem, List/Cons(list.head, tail)) | |
# ---------------------------------------------- | |
# simple uno simulation written in bend! | |
TIE = 4 | |
P2_WIN = 3 | |
P1_WIN = 2 | |
TRUE = 1 | |
FALSE = 0 | |
# a card is a tuple (Color, number) | |
type Color: | |
red | |
green | |
blue | |
yellow | |
type Turn: | |
p1 | |
p2 | |
def get_color_id(color): | |
match color: | |
case Color/red: | |
return 1 | |
case Color/green: | |
return 2 | |
case Color/blue: | |
return 3 | |
case Color/yellow: | |
return 4 | |
def get_color(color_id): | |
switch color_id: | |
# defaulting to red, it should not happen though since we use % 4 in rnd | |
case 0: | |
return Color/red | |
case 1: | |
return Color/red | |
case 2: | |
return Color/green | |
case 3: | |
return Color/blue | |
case 4: | |
return Color/yellow | |
case _: | |
return Color/red | |
# uno supports cards from 1-9 | |
def generate_deck(n, seed): | |
bend n, state=1: | |
when n != 0: | |
state = state ^ (state << 13) | |
state = state ^ (state >> 17) | |
state = state ^ (state << 5) | |
state = state ^ (state << seed) | |
color_id = state % 4 + 1 | |
color = get_color(color_id) | |
return List/Cons(((state % 9) + 1, color), fork(n - 1, state)) | |
else: | |
return List/Nil | |
def deck_length(deck): | |
fold deck with idx = 0: | |
case List/Nil: | |
return idx | |
case List/Cons: | |
return deck.tail(idx + 1) | |
# returns the index of the card picked | |
def pick_card(deck, table_card): | |
fold deck with idx = 0: | |
case List/Nil: | |
# for now we can use 10 (not sure abt neg numbers yet), but this assumes we cant pick up new cards from a suffled deck | |
# this is for simplicity now | |
return 10 | |
case List/Cons: | |
# check if card is of the same color or same number | |
(number, color) = table_card | |
table_card_cpy = (number, color) | |
color_id = get_color_id(color) | |
(h_num, h_color) = deck.head | |
head_id = get_color_id(h_color) | |
# check for matching colors | |
if color_id == head_id: | |
return idx | |
else: | |
if number == h_num: | |
return idx | |
else: | |
return deck.tail(idx + 1) | |
def iget(deck, idx): | |
match deck: | |
case List/Nil: | |
return List/Nil | |
case List/Cons: | |
if idx == 0: | |
return deck.head | |
else: | |
return iget(deck.tail, idx - 1) | |
def remove(deck, card_idx): | |
match deck: | |
case List/Nil: | |
return List/Nil | |
case List/Cons: | |
if card_idx == 0: | |
return deck.tail | |
else: | |
return List/Cons(deck.head, remove(deck.tail, card_idx - 1)) | |
def empty_deck(deck): | |
match deck: | |
case List/Nil: | |
return TRUE | |
case List/Cons: | |
return FALSE | |
def play(p1_deck, p2_deck, table_card, turn, turns_with_no_play): | |
if turns_with_no_play == 2: | |
return (TIE, (p1_deck, p2_deck)) | |
else: | |
empty_p1 = empty_deck(p1_deck) | |
empty_p2 = empty_deck(p2_deck) | |
if empty_p1 == TRUE: | |
if empty_p2 == TRUE: | |
return "BOTH ARE EMPTY. SOMETHING WENT WRONG!" | |
else: | |
return (P1_WIN, 0) | |
else: | |
if empty_p2 == TRUE: | |
return (P2_WIN, 0) | |
else: | |
match turn: | |
case Turn/p1: | |
picked = pick_card(p1_deck, table_card) | |
if picked == 10: | |
return play(p1_deck, p2_deck, table_card, Turn/p2, turns_with_no_play + 1) | |
else: | |
# i need the card here to rec call with the new table_card | |
new_table_card = iget(p1_deck, picked) | |
p1_deck_new = remove(p1_deck, picked) | |
return play(p1_deck_new, p2_deck, new_table_card, Turn/p2, 0) | |
case Turn/p2: | |
picked = pick_card(p2_deck, table_card) | |
if picked == 10: | |
return play(p1_deck, p2_deck, table_card, Turn/p1, turns_with_no_play + 1) | |
else: | |
new_table_card = iget(p2_deck, picked) | |
p2_deck_new = remove(p2_deck, picked) | |
return play(p1_deck, p2_deck_new, new_table_card, Turn/p1, 0) | |
def untie(p1_d, p2_d): | |
p1_d_length = deck_length(p1_d) | |
p2_d_length = deck_length(p2_d) | |
if (p1_d_length == p2_d_length): | |
return "It is indeed a tie!" | |
else: | |
diff = p1_d_length - p2_d_length | |
# if diff is less than 9, it means p2 won. we cant check for negs cause in this case it will return the shifted number | |
if diff > 9: | |
return "Player 2 won because he has less cards!" | |
else: | |
return "Player 1 won because he has less cards!" | |
def get_game_result_str(game_result_t): | |
(game_result, decks) = game_result_t | |
switch game_result: | |
case 0: | |
return "Whoops. Something went wrong." | |
case 1: | |
return "Whoops. Something went wrong." | |
case 2: | |
return "Player 1 Wins!" | |
case 3: | |
return "Player 2 Wins!" | |
case 4: | |
(p1_deck, p2_deck) = decks | |
return untie(p1_deck, p2_deck) | |
case _: | |
return "Something went wrong" | |
def main(): | |
init_card = (1, Color/red) | |
# writing a simple test! | |
# p1_deck = [(2, Color/red), (4, Color/yellow), (8, Color/green)] | |
# p2_deck = [(2, Color/yellow), (4, Color/green), (1, Color/red)] | |
# result should be p1 wins! because p1 will have no cards wile p2 will have (1, Color/red) | |
# maybe it should be possible to simulate various rounds with different start players | |
# here ez win for p2! | |
p1_deck = [(1, Color/red), (4, Color/yellow), (8, Color/green)] | |
p2_deck = [(1, Color/red), (1, Color/red), (1, Color/red)] | |
# a random simulation of one round could happen simply by redefinining player decks: | |
# its possible also to randomize the init card | |
# 213 is just a seed so we dont get same cards for the 2 players | |
# p1_deck = generate_deck(9, 213) | |
# p2_deck = generate_deck(9, 100) | |
# to extend this implementation, some ideas are: | |
# refactor to have a list of players instead of 2 of them and alternate rounds between them | |
# the ability to pick a card from a shuffled deck when you have no options | |
# add "power cards" such as +2, block, etc. | |
# for now these are out of scope for a 30/40 min project | |
# another thing to do is to use the List/Got in the top of the file to enhance performance | |
game_res = play(p1_deck, p2_deck, init_card, Turn/p1, 0) | |
str_res = get_game_result_str(game_res) | |
return str_res | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment