Uno (Card Game)/Julia: Difference between revisions

m
Fixed syntax highlighting.
m (add scoring)
m (Fixed syntax highlighting.)
 
(5 intermediate revisions by one other user not shown)
Line 2:
 
Gtk based graphical version.
<langsyntaxhighlight lang="julia">using Random, Colors, Gtk, Cairo
 
#=========== Channel and flag (IPC) section ===================#
 
""" channel, communicates player's mouse choice of card or color to game logic """
const channel = Channel{Any}(100)
 
""" flush the channel from mouse choice to game logic """
flushchannel() = while !isempty(channel) take!(channel); end
 
""" challenge flagsflag: true if challenge taken by player, display button """
const challenge = [false, false]
 
#============ Game play section ==================#
 
""" The Uno card type. The first field is color, second field is number or command. """
const UnoCard = Pair{String, String}
color(c::UnoCard) = first(c)
type(c::UnoCard) = last(c)
Line 59 ⟶ 62:
const originaldeck = [vec([UnoCard(c, v) for v in ttypes, c in colors]);
fill(UnoCard("Wild", "Wild"), 4); fill(UnoCard("Wild", "Draw Four"), 4)]
 
""" challenge flags: taken by player, display button """
const challenge = [false, false]
 
 
""" Set the next player to play to game.pnow (clockwise or counterclockwise) """
Line 98 ⟶ 97:
hands = [deck[i:i+6] for i in 1:7:27]
game = UnoCardGameState(drawpile, discardpile, [UnoCardGamePlayer(playernames[i], 0,
startswith(playernames[i], "Bot") ? true : false, hands[i])
for i in 1:length(playernames)], 1, "Wild", "Wild", true, true)
dealer = rand(1:length(playernames))
Line 153 ⟶ 152:
# bot will challenge half the time, player must challenge in 5 seconds.
if game.players[game.pnow].isabot && rand() < 0.5 ||
(!game.players[game.pnow].isabot && challenge[begin] == true)
challenge[begin] = false
logline("$(game.players[game.pnow].name) challenged Draw Four!")
Line 159 ⟶ 158:
nextplayer!(game); nextplayer!(game); nextplayer!(game); # prior player
game.colornow = game.lastcolor
indices = playableindices(game)
hand = game.players[game.pnow].hand
if any(ic -> color(hand[i]c) !== "Wild"game.colornow, playableindices(game)hand)
logline("Challenge sustained! Challenged Draw Four player draws 4.")
drawcardsfromdeck!(game, 42); drawcardsfromdeck!(game, 2)
game.pnow, game.colornow = challenger, savecolor
return
Line 172 ⟶ 170:
game.pnow, game.colornow = challenger, savecolor
end
challenge[begin] = false
end
logline("Player $(game.players[game.pnow].name) draws $n card$(n == 1 ? "" : "s").")
Line 334 ⟶ 333:
const cairocolor = Dict("Red" => colorant"red", "Yellow" => colorant"gold",
"Green" => colorant"green", "Blue" => colorant"blue", "Wild" => colorant"black")
 
""" CSS style button for bold colored text """
function colorbutton(txt::String, clr::String)
button = GtkButton(txt)
sc = Gtk.GAccessor.style_context(button)
pr = Gtk.CssProviderLeaf(data="button {color:$(clr); font-weight: bolder}")
push!(sc, Gtk.StyleProvider(pr), 600)
return button
end
 
""" Draw a UnoCard as a rectangle with rounded corners. """
Line 403 ⟶ 411:
Uno card game Gtk app. Draws game on a canvas, logs play on box below canvas.
"""
function UnoCardGameApp(w = 8641120, hcanwcan = 700810, hlogh = 100700)
win = GtkWindow("Uno Card Game", w, hcan + hlogh) |> (GtkFrame() |> (vboxhbox = GtkBox(:vh)))
swinvbox = GtkScrolledWindowGtkBox(:v)
can = GtkCanvas(wwcan, hcanh)
set_gtk_propertypush!(canhbox, :expand, truecan)
push!(swin, can)
push!(vbox, swin)
push!(vbox, logwindow) # from log section
set_gtk_property!(logwindow, :expand, true)
b, g = colorbutton("Blue", "blue"), colorbutton("Green", "green")
r, y = colorbutton("Red", "red"), colorbutton("Yellow", "gold")
chal = GtkButton("Challenge")
signal_connect(w -> push!(channel, "Blue"), b, "clicked")
signal_connect(w -> push!(channel, "Green"), g, "clicked")
signal_connect(w -> push!(channel, "Red"), r, "clicked")
signal_connect(w -> push!(channel, "Yellow"), y, "clicked")
signal_connect(w -> (challenge[begin] = true), chal, "clicked")
push!(vbox, swinb, g, r, y, chal)
push!(swinhbox, canvbox)
fontpointsize = w / 50
cardpositions = Dict{Int, Vector{Int}}()
 
colorpositions = Dict("Red" => [280, 435, 320, 475], "Yellow" => [340, 435, 380, 475],
# announce the rules and penalties per task description
"Green" => [400, 435, 440, 475], "Blue" => [460, 435, 500, 475])
info_dialog(unodocshtml, win)
challengeposition = [300, 475, 470, 465]
 
# create a game instance to start play
game = UnoCardGameState()
 
Line 430 ⟶ 449:
color = colorant"navy"
set_source(ctx, color)
move_to(ctx, 360, 400420)
show_text(ctx, game.players[1].name)
stroke(ctx)
Line 444 ⟶ 463:
cairocard(ctx, last(game.discardpile), 350, 240, 40, 80)
cairodrawfacedowncard(ctx, 410, 240, 40, 80)
if challenge[end]
set_source(ctx, colorant"black")
move_to(ctx, challengeposition[1], challengeposition[2])
show_text(ctx, "Challenge Draw Four")
stroke(ctx)
else
for (i, p) in enumerate(colorpositions)
set_source(ctx, cairocolor[first(p)])
x0, y0, x1, y1 = last(p)
rectangle(ctx, x0, y0, 40, 40)
fill(ctx)
end
end
hand = first(game.players).hand
isempty(hand) && return
nrow = (length(hand) + 15) ÷ 1615
for row in 1:nrow
cards = hand[(row - 1) * 1615 + 1 : min(length(hand), row * 1615 - 1)]
startx, starty = 40 + (1615 - length(cards)) * 20, 500 + 85 * (row - 1)
for (i, card) in enumerate(cards)
idx, x0 = (row - 1) * 1615 + i, startx + 50 * (i - 1)
cardpositions[idx] = [x0, starty, x0 + 40, starty + 80]
cairocard(ctx, card, x0, starty, 40, 80)
Line 473 ⟶ 479:
""" Gtk mouse callback: translates valid mouse clicks to a channel item """
signal_connect(can, "button-press-event") do b, evt
if challengeposition[1] < evt.x < challengeposition[3] &&
challengeposition[4] < evt.y < challengeposition[2]
challenge[begin] = true
return
end
challenge[begin] = false
for p in colorpositions
x0, y0, x1, y1 = last(p)
if x0 < evt.x < x1 && y0 < evt.y < y1
push!(channel, first(p))
return
end
end
for p in cardpositions
x0, y0, x1, y1 = last(p)
Line 495 ⟶ 488:
end
 
# do the turns of play in the game, keeping score totals from the rounds
for n in 1:1000
draw(can)
Line 502 ⟶ 496:
if startswith(game.players[game.pnow].name, "Play") &&
type(game.discardpile[end]) == "Draw Four" && game.commandsvalid
challenge[end] = true
draw(can)
Gtk.showall(win)
info_dialog("ChooseClick Challenge within 5 seconds to challenge a Draw Four")
sleep(53)
challenge[end] = false
end
sleep(2)
Line 516 ⟶ 508:
if type(game.discardpile[end]) == "Draw Two"
nextplayer!(game) # next player might have to draw before scoring done
drawcardsdrawcardsfromdeck!(game, 2)
elseif type(game.discardpile[end]) == "Draw Four"
nextplayer!(game)
drawcardsfromdeck!(game, 2)
drawcardsfromdeck!(game, 2) # D2 twice because not to be contested as a D4
end
roundpoints = sum(x -> handscore(x.hand), game.players)
Line 528 ⟶ 520:
info_dialog("The winner of round $n is $(game.players[winner].name).\n" *
"Winner gains $roundpoints points.", win)
logline("Scores: $([x.score for x in game.players])")
if any(x -> x.score >= 500, game.players)
s = "Game over. Scores:\n\n"
Line 543 ⟶ 536:
end
 
UnoCardGameApp()</syntaxhighlight>
</lang>
9,476

edits