Skip to content

Instantly share code, notes, and snippets.

@strager
Created May 29, 2013 05:44
Show Gist options
  • Save strager/5668203 to your computer and use it in GitHub Desktop.
Save strager/5668203 to your computer and use it in GitHub Desktop.
Tic-tac-toe CLI game in Kitten
def concat ([[a]] -> [a]): (a)[] ([a] [a] -> [a]){ + } foldDown
def ; ([a] a -> [a]): push
def show_board_cell (Char -> Char){ }
def cell_number_to_index (Int -> Int):
8 __swap -
def show_board_cell_at ([Char] Int -> Char):
cell_number_to_index get
show_board_cell
def show_board_row ([Char] Int -> [Char]):
->row_index
->b
row_index 3 * ->i
([Char])[]
' '; b 0 i + show_board_cell_at;
'|'; b 1 i + show_board_cell_at;
'|'; b 2 i + show_board_cell_at;
def show_board ([Char] -> [Char]):
->b
([Char])[]
" A B C\n";
"1 "; b 0 show_board_row; "\n";
" --+-+--\n";
"2 "; b 1 show_board_row; "\n";
" --+-+--\n";
"3 "; b 2 show_board_row; "\n";
concat
def print_board ([Char] ->):
show_board print
def new_board (-> [Char]):
[ ' ', ' ', ' '
, ' ', ' ', ' '
, ' ', ' ', ' '
]
def any ([a] (a -> Bool) -> Bool):
map or
def all ([a] (a -> Bool) -> Bool):
map and
def elem ([a] a -> Bool):
->x
(Char -> Bool){ x = } any
def read_x (Char -> Int):
->c
if "aA" c elem: 0
else if "bB" c elem: 1
else if "cC" c elem: 2
else: -1
def read_y (Char -> Int):
->c
if "1!" c elem: 0
else if "2@" c elem: 1
else if "3#" c elem: 2
else: -1
def read_xy_ (Char Char -> Int Int Bool):
read_y ->y
read_x ->x
if x 0 >= y 0 >= &&:
x y true
else:
0 0 false
def read_xy (Char Char -> Int Int Bool):
->y
->x
x y read_xy_
if:
true
else:
drop drop
y x read_xy_
def read_move_line ([Char] -> Int Int Bool):
->chars
if chars length 2 =:
chars 1 get
chars 0 get
read_xy
else:
0 0 false
def xy_to_cell_number (Int Int -> Int):
->x ->y
y 3 *
x +
def edit_board ([Char] Int Char -> [Char]):
->c
->i
c
i cell_number_to_index
set
def infloop (->): infloop
def exit (->):
"Tell Jon to let me go!\n" print infloop
def ask_turn ([Char] Char -> [Char]):
->player
->board
board print_board
"It is " player push "'s turn. Choose your move: "+
stdout __print
getLine ->input
input read_move_line
->parsed ->x ->y
if parsed:
board
x y xy_to_cell_number
player edit_board
else if input "q" =:
exit board
else:
"I didn't understand that. Type e.g. \"a3\" to "
"move in the bottom-left cell. Type \"q\" to exit.\n"+
stdout __print
board player ask_turn
def next_player (Char -> Char):
if 'x' =: 'o'
else: 'x'
def gets ([a] [Int] -> [a]):
->indices
->xs
indices (Int -> a){ xs swap get } map
def check_sets (-> [[Int]]):
([[Int]])[]
// Rows
[0, 1, 2]; [3, 4, 5]; [6, 7, 8];
// Columns
[0, 3, 6]; [1, 4, 7]; [2, 5, 8];
// Diagonals
[0, 4, 8]; [2, 4, 6];
// ' ', 'x', or 'o'
def get_check_set_winner ([Char] [Int] -> Char):
gets ->players
if players (Char -> Bool){ 'x' = } all:
'x'
else if players (Char -> Bool){ 'o' = } all:
'o'
else:
' '
// ' ', 'x', 'o', or '*'
def get_winner ([Char] -> Char):
->board
board (Char -> Bool){ ' ' = } filter empty
->filled
if filled:
'*'
else:
check_sets
([Int] -> Char){ board swap get_check_set_winner } map
(Char -> Bool){ ' ' != } filter
->winners
if winners empty:
' '
else if winners (Char -> Bool){ 'x' = } all:
'x'
else if winners (Char -> Bool){ 'o' = } all:
'o'
else:
'*'
def game_loop ([Char] Char -> [Char] Char):
->player
dup get_winner ->winner
if "xo*" winner elem:
winner
else:
player ask_turn
player next_player game_loop
def game (->):
new_board 'x' game_loop
->winner
->final_board
newline
if winner '*' =:
"It's a tie!\n" print
else:
winner " wins!\n" prepend stdout __print
final_board print_board
def pass (->){ }
def loop ((-> Bool) ->):
->f
if f __apply:
f loop
else:
pass
def prompt_play_another (-> Bool):
"Play another game? [yN] " print
getLine ->input
if input (Char -> Bool){ "yY" swap elem } any:
newline
true
else if input (Char -> Bool){ "nN" swap elem } any:
newline
false
else if input empty:
newline
false
else:
prompt_play_another
def main (->):
(-> Bool){ game prompt_play_another } loop
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment