A simple, 2-player number guessing game in Python 3.
Clone
HTTPS:
git clone https://vervis.peers.community/repos/yENdo
SSH:
git clone USERNAME@vervis.peers.community:yENdo
Branches
Tags
v0.0.3
::
grid.py
#!/usr/bin/env python3
# Copyright 2018 UltrasonicMadness
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A grid of numbers of a certain width and height.
The rows and columns on this grid can be highlighted.
"""
from random import randint
from igexceptions import *
class Grid():
def __init__(self, secretNumber, width, height):
"""Sets up a grid for the Impossible Grid game.
Arrays for storing the numbers of highlighted rows and columns are
initialised.
Parameters:
secretNumber: Player 1's secret number.
width: The width of the grid.
height: The height of the grid.
Returns:
This method does not return any data.
"""
self.secretNumber = secretNumber
self.width = width
self.height = height
self.hlRows = []
self.hlCols = []
self.rowHistory = []
self.colHistory = []
# Returns a horizontal grid-line
def _genLine(self, start, line, separator, end):
output = ""
# Generate the top line
output += start
# For each column in the grid
for x in range(0, self.width):
# Make the width of the grid line match the rest of the grid.
for i in range(0, len(str(self.width * self.height)) + 2):
output += line
if x < self.width - 1:
# The separator, which is a T-intersection or a cross
output += separator
else:
# The character at the end (corner or sideways T-intersection)
output += end
# Return the generated line
return output
# Returns a horizontal grid line with numbers and separators.
def _genNumberLine(self, rowNumber, separator, highlight):
output = ""
# Calculate the first number in this row.
startingNumber = rowNumber * self.width
# Start with the given separator character
output += separator
# For each column in the grid
for x in range(0, self.width):
# If the cell is highlighted, add the highlight char.
if x in self.hlCols or rowNumber in self.hlRows:
hlChar = highlight
else:
hlChar = " "
# Output the calculated number in the cell, zero padded to the
# length of the highest number so the table doesn't look off.
# It will also be 'highlighted' by the hlChar if the cell is
# part of a highlighted row or column.
output += hlChar + str(startingNumber + x + 1) \
.zfill(len(str(self.width * self.height))) + hlChar
# Add the last separator char
output += separator
return output
def show(self):
"""Prints the grid to the standard output.
Returns:
This method does not return any data.
"""
# Top line made with box-drawing chars
print(self._genLine("\u250d", "\u2501", "\u252f", "\u2511"))
# For each row, print the numbers separated by grid lines
for r in range(0, self.height):
print(self._genNumberLine(r, "\u2502", "\u2593"))
if r < self.height - 1:
print(self._genLine("\u251d", "\u2501", "\u253f", "\u2525"))
# Bottom line
print(self._genLine("\u2515", "\u2501", "\u2537", "\u2519"))
# The grid calls this function to highlight the nearest valid row
# to initPos.
def _cheat(self, initPos, col):
# How far from the initPos row or column to attempt highlighting
offset = 1
if col:
if initPos not in self.colHistory:
self.colHistory.append(initPos)
else:
if initPos not in self.rowHistory:
self.rowHistory.append(initPos)
while True:
# Depending on the value, the positions are checked in a different
# order.
highFirst = randint(0, 1) == 1
# Order the numbers differently depending on the value generated
# above.
if highFirst:
posToCheck = [initPos + offset, initPos - offset]
else:
posToCheck = [initPos - offset, initPos + offset]
# Try both positions in the given order.
try:
if col:
self.highlightCol(posToCheck[0])
else:
self.highlightRow(posToCheck[0])
break
except:
try:
if col:
self.highlightCol(posToCheck[1])
else:
self.highlightRow(posToCheck[1])
break
except:
# If both attempts raise an exception, try again with
# the next 2 farther away positions.
offset += 1
def highlightRow(self, highlight):
"""Highlights the row at the given position.
Raises:
HLOutOfRangeException: The position is less than 1 or greater than the
width.
DuplicateHLException: The row at the given position has already been
highlighted.
"""
if highlight < 0 or highlight > self.width - 1:
raise HLOutOfRangeException()
elif highlight in self.hlRows or highlight in self.rowHistory:
raise DuplicateHLException()
elif self.rowHasSecretNumber(highlight):
self._cheat(highlight, False)
else:
self.hlRows.append(highlight)
def highlightCol(self, highlight):
"""Highlights the column at the given position.
Raises:
HLOutOfRangeException: The position is less than 1 or greater than the
height.
DuplicateHLException: The column at the given position has already been
highlighted.
"""
if highlight < 0 or highlight > self.height - 1:
raise HLOutOfRangeException()
elif highlight in self.hlCols or highlight in self.colHistory:
raise DuplicateHLException()
elif self.colHasSecretNumber(highlight):
self._cheat(highlight, True)
else:
self.hlCols.append(highlight)
def getValueAtPos(self, x, y):
"""Returns the number at the given position on the grid"""
return self.height * y + x + 1
def rowHasSecretNumber(self, row):
"""Checks if the given row has the secret number and returns True if
it does, False otherwise.
"""
firstNum = self.height * row
return self.secretNumber in \
range(firstNum, firstNum + self.width)
def colHasSecretNumber(self, col):
"""Checks if the given column has the secret number and returns True if
it does, False otherwise.
"""
firstNum = col
return self.secretNumber in \
range(firstNum, self.height * self.width, self.height)