Source code for boatman

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright 2009-2015 Joao Carlos Roseta Matos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
A simple logic game.
A boatman is comissioned to take a Wolf, a Goat and some Pasture to the other
margin.
He can only take one at the time.
While he is on the dock, nothing happens.
As soon as he leaves, the animals will try to eat.
The order of transportation is important because the Wolf eats the Goat and
the Goat eats the Pasture, but the Wolf doesn't eat the Pasture.

Portuguese

Um jogo de lógica simples.
Um barqueiro é contratado para levar um Lobo, uma Cabra e Pasto para a outra
margem.
Só pode levar um de cada vez.
Enquanto está na doca nada acontece.
Assim que saí, os animais tentam comer.
A ordem de transporte é importante porque o Lobo come a Cabra e a Cabra come o
Pasto, mas o Lobo não come o Pasto.
"""

# Python 3 compatibility
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

# import io  # Python 3 compatibility
import sys

from builtins import input  # Python 3 compatibility
import colorama as clrm

import ansi
import localization as lcl


ALLOWED_KEYS = lcl.ITEMS + [lcl.QUIT]
BOAT = r'\___/'
NO_BOAT = '     '
DOCK = clrm.Style.BRIGHT + clrm.Fore.YELLOW + '===' + clrm.Style.RESET_ALL
SEA = (clrm.Back.BLUE +
       '                                                   ' +
       clrm.Back.RESET)
# some auxiliary constants to help reading the code
RIGHT = True
LEFT = False


[docs]def fireworks(): """Print fireworks.""" ansi.print_at(2, 48, clrm.Style.BRIGHT + r'\ | /') ansi.print_at(3, 47, '-- * --') ansi.print_at(4, 48, '/ | \\') ansi.print_at(3, 38, clrm.Fore.RED + r'\ | /') ansi.print_at(4, 37, '-- * --') ansi.print_at(5, 38, '/ | \\') ansi.print_at(4, 28, clrm.Fore.YELLOW + r'\ | /') ansi.print_at(5, 27, '-- * --') ansi.print_at(6, 28, '/ | \\') ansi.print_at(7, 37, clrm.Fore.MAGENTA + '*') ansi.print_at(8, 45, clrm.Fore.GREEN + '*') ansi.print_at(9, 40, clrm.Fore.CYAN + '*' + clrm.Style.RESET_ALL)
[docs]def upd_status(cur_boat_pos, left_items, right_items): """Update game status, showing a message and if won some fireworks.""" if right_items == lcl.ITEMS: # win ansi.print_at(5, 1, lcl.WIN) fireworks() return lcl.GAME_OVER elif ((lcl.WOLF in left_items and lcl.GOAT in left_items and cur_boat_pos == RIGHT) or (lcl.WOLF in right_items and lcl.GOAT in right_items and cur_boat_pos == LEFT)): # loss ansi.print_at(5, 1, lcl.WOLF_ATE_GOAT) return lcl.GAME_OVER elif ((lcl.GOAT in left_items and lcl.PASTURE in left_items and cur_boat_pos == RIGHT) or (lcl.GOAT in right_items and lcl.PASTURE in right_items and cur_boat_pos == LEFT)): # loss ansi.print_at(5, 1, lcl.GOAT_ATE_PASTURE) return lcl.GAME_OVER
[docs]def move_boat(to_pos): """Move boat to right/left dock, and returns position after move.""" if to_pos == RIGHT: for col in range(5, 51): ansi.print_at(11, col - 1, NO_BOAT) ansi.print_at(11, col, BOAT) return RIGHT else: for col in range(50, 4, -1): ansi.print_at(11, col, NO_BOAT) ansi.print_at(11, col - 1, BOAT) return LEFT
[docs]def move_right(item, boat_pos, left_items, right_items): """Move item to right dock.""" pos = lcl.ITEMS.index(item) left_items[pos] = ' ' ansi.print_at(10, 1, clrm.Style.BRIGHT + ''.join(left_items) + clrm.Style.DIM) if boat_pos == RIGHT: cur_boat_pos = move_boat(LEFT) if upd_status(cur_boat_pos, left_items, right_items) == lcl.GAME_OVER: return lcl.GAME_OVER, cur_boat_pos cur_boat_pos = move_boat(RIGHT) right_items[pos] = item ansi.print_at(10, 55, clrm.Style.BRIGHT + ''.join(right_items) + clrm.Style.DIM) if upd_status(cur_boat_pos, left_items, right_items) == lcl.GAME_OVER: return lcl.GAME_OVER, cur_boat_pos return None, cur_boat_pos
[docs]def move_left(item, boat_pos, left_items, right_items): """Move item to left dock.""" pos = lcl.ITEMS.index(item) right_items[pos] = ' ' ansi.print_at(10, 55, clrm.Style.BRIGHT + ''.join(right_items) + clrm.Style.DIM) if boat_pos == LEFT: cur_boat_pos = move_boat(RIGHT) if upd_status(cur_boat_pos, left_items, right_items) == lcl.GAME_OVER: return lcl.GAME_OVER, cur_boat_pos cur_boat_pos = move_boat(LEFT) left_items[pos] = item ansi.print_at(10, 1, clrm.Style.BRIGHT + ''.join(left_items) + clrm.Style.DIM) if upd_status(cur_boat_pos, left_items, right_items) == lcl.GAME_OVER: return lcl.GAME_OVER, cur_boat_pos return None, cur_boat_pos
[docs]def main(): """Clear screen, draw scenario, request input and select correct action.""" left_items = lcl.ITEMS[:] # left dock items right_items = [' ', ' ', ' '] # right dock items cur_boat_pos = LEFT # current boat position clrm.init() ansi.clear_screen() print(lcl.TITLE) ansi.print_at(10, 1, clrm.Style.BRIGHT + ''.join(left_items) + clrm.Style.DIM) ansi.print_at(11, 1, DOCK) ansi.print_at(11, 4, BOAT) ansi.print_at(11, 55, DOCK) ansi.print_at(12, 4, SEA) while True: choice = '' while choice not in ALLOWED_KEYS: ansi.print_at(14, 1, lcl.PROMPT) choice = input('> ').upper() # ToDo: check for unicode and clear ansi.clear_line(14) # must clear line before actual input (!?) if choice in lcl.ITEMS: if choice in left_items: result, cur_boat_pos = move_right(choice, cur_boat_pos, left_items, right_items) else: result, cur_boat_pos = move_left(choice, cur_boat_pos, left_items, right_items) if result == lcl.GAME_OVER: ansi.print_at(6, 1, lcl.GAME_OVER) break else: # Quit break ansi.set_print_pos(16, 1)
if __name__ == '__main__': # import doctest # doctest.testmod(verbose=True) sys.exit(main()) # ToDo: add sound # ToDo: gui version