Runes

http://codeforces.com/group/NVaJtLaLjS/contest/243021

You are helping an archaeologist decipher some runes. He knows that this ancient society used a
Base 10 system, and that they never start a number with a leading zero. He’s figured out most of
the digits as well as a few operators, but he needs your help to figure out the rest.
The professor will give you a simple math expression. He has converted all of the runes he knows
into digits. The only operators he knows are addition (+), subtraction (-), and multiplication (),
so those are the only ones that will appear. Each number will be in the range from −999, 999 to
999, 999, and will consist of only the digits ‘0’–‘9’, possibly a leading ‘-’, and a few ‘?’s. The ‘?’s
represent a digit rune that the professor doesn’t know (never an operator, an ‘=’, or a leading ‘-’).
All of the ‘?’s in an expression will represent the same digit (0–9), and it won’t be one of the other
given digits in the expression.
Given an expression, figure out the value of the rune represented by the question mark. If
more than one digit works, give the lowest one. If no digit works, well, that’s bad news for the
professor—it means that he’s got some of his runes wrong. Output −1 in that case.
Input
The sample data will start with the number of test cases T (1 ≤ T ≤ 100). Each test case will
consist of a single line, of the form:
[number][op][number]=[number]
Each [number] will consist of only the digits ‘0’-‘9’, with possibly a single leading minus ‘-’, and
possibly some ‘?’s. No number will begin with a leading ‘0’ unless it is 0, no number will begin
with -0, and no number will have more than 6 characters (digits or ?s). The [op] will separate the
first and second [number]s, and will be one of: +, - or . The = will always be present between the
second and third [number]s. There will be no spaces, tabs, or other characters. There is guaranteed
to be at least one ? in every equation.
Output
Output the lowest digit that will make the equation work when substituted for the ?s, or output
−1 if no digit will work. Output no extra spaces or blank lines.
Sample Input Sample Output
5
1+1=?
123
45?=5?088
-5?
-1=5?
19–45=5?
??*??=302?
2
6
0
-1
5

题意:把?处换成一个数字,若有多个符合,输出最小的;若没有符合或格式错误,输出-1。
注意题意:式子中已经有的数字不能填在?处。
看起来是一道简单的码农题,但还是有一些要注意的,思路不清晰很容易写错。
这道题一个很好的简化方法是定位两个符号,把字符串划分为3个数字的字符串(这步非常好),再借助sscanf函数,可以简化很多。

#include<bits/stdc++.h>
using namespace std;
#define ll  long long

int T,n;
char s[100],t[100];
map<int,bool> mp;

bool check()
{
    int p;
    for(p=1;p<n;p++)
        if(t[p]=='+'||t[p]=='-'||t[p]=='*')break;
    int p2;
    for(p2=0;p2<n;p2++)if(t[p2]=='=')break;

    char c[100];int m=p;
    for(int i=0;i<m;i++)c[i]=t[i];
    if(m>1&&c[0]=='-'&&c[1]=='0')return false;
    if(m>1&&c[0]=='0'&&isdigit(c[1]))return false;
    m=p2-p-1;
    for(int i=0;i<m;i++)c[i]=t[p+1+i];
    if(m>1&&c[0]=='-'&&c[1]=='0')return false;
    if(m>1&&c[0]=='0'&&isdigit(c[1]))return false;
    m=n-p2-1;
    for(int i=0;i<m;i++)c[i]=t[p2+1+i];
    if(m>1&&c[0]=='-'&&c[1]=='0')return false;
    if(m>1&&c[0]=='0'&&isdigit(c[1]))return false;

    int r1,r2,r3;
    sscanf(t,"%d",&r1);
    sscanf(t+p+1,"%d",&r2);
    sscanf(t+p2+1,"%d",&r3);
    if(t[p]=='+')return r1+r2==r3;
    if(t[p]=='-')return r1-r2==r3;
    if(t[p]=='*')return r1*r2==r3;
}

int main()
{
    //freopen("input.in","r",stdin);
    cin>>T;
    while(T--)
    {
        mp.clear();
        bool ok=0;
        scanf("%s",s);
        n=strlen(s);
        for(int i=0;i<n;i++)if(isdigit(s[i]))mp[s[i]-'0']=1;
        for(int i=0;i<10;i++)
        {
            if(mp.count(i))continue;
            memcpy(t,s,sizeof(s));
            for(int j=0;j<n;j++)if(t[j]=='?')t[j]='0'+i;
            if(check())
            {
                printf("%d\n",i);
                ok=1;
                break;
            }
        }
        if(!ok)puts("-1");
    }
    return 0;
}
################################## # Semi-OOP version of runes.py # # Last updated: 21 January 2025 # ################################## ######### START OF SETUP ######### # Imports import functools import graphics import math import time import PyGif from random import random # Constants viewport_size = 600 # This is the height of the viewport spread = 20 active_hollusion = None lastframe = None Posn = graphics.Posn Rgb = graphics.Rgb draw_solid_polygon = graphics.draw_solid_polygon graphics.init(viewport_size) vp = graphics.open_viewport("ViewPort", viewport_size, viewport_size) lp = graphics.open_pixmap("LeftPort", viewport_size, viewport_size) rp = graphics.open_pixmap("RightPort", viewport_size, viewport_size) def type_checker(types): """ A setup function to help you check for types. Nothing to see here. """ def decorator(func): name = func.__name__ # functools.wraps preserves the docstring @functools.wraps(func) def checker(*args): for i in range(len(args)): if not isinstance(args[i], types[i]): expected = types[i].__name__ actual = type(args[i]).__name__ raise TypeError( f"Function {name}: Expected type {expected} for argument #{i + 1} but given {args[i]} of type {actual}" ) return func(*args) return checker return decorator def is_list_or_tuple(lst): """ A setup function to check for types. Nothing to see here. """ return isinstance(lst, (list, tuple)) class Frame: """ A frame object. Nothing to see here. """ def __init__(self, p0, p1, p2, z1, z2): self.orig = p0 self.x = p1 self.y = p2 self.z1 = z1 self.z2 = z2 unit_frame = Frame(Posn(0, 0), Posn(viewport_size, 0), Posn(0, viewport_size), 0, 1) class Rune: """ A rune object. Nothing to see here. """ def __init__(self, func): self.fn = func def show(self, vp, frame): self.fn(vp, frame) def __str__(self): return "Rune" def scale_vect(mult, p): """ A setup function to scale vectors. Nothing to see here. """ return Posn(mult * p.x, mult * p.y) def transform_posn(frame): """ A setup function for position transformation. Nothing to see here. """ def f(posn): return frame.orig + ( scale_vect(posn.x / viewport_size, frame.x) + scale_vect(posn.y / viewport_size, frame.y) ) return f def inverse_transform_posn(frame): """ The 'inverse' of transform_posn. Nothing to see here. """ a = frame.x.x b = frame.y.x c = frame.x.y d = frame.y.y det = a * d - b * c if det == 0: raise Exception("somehow you managed to zero the determinant for your frame") inv_mat = ((d / det, -b / det), (-c / det, a / det)) def function(posn): nonlocal inv_mat t = list( map( lambda m: m[0] * (posn.x - frame.orig.x) + m[1] * (posn.y - frame.orig.y), inv_mat, ) ) return Posn(viewport_size * t[0], viewport_size * t[1]) return Rune(function) def center_and_fill(p): """ A function used in circle_bb, spiral_bb, and ribbon_bb. Nothing to see here. """ center = Posn(viewport_size / 2, viewport_size / 2) return center + scale_vect(viewport_size / 2, p) ############ END OF SETUP ############ @type_checker((Rune,)) def show(rune): """ Shows the `rune` at the working window. """ return rune.show(vp, unit_frame) def clear_all(): """ Clears the current working window. """ global active_hollusion global vp, lp, rp if active_hollusion != None: active_hollusion("kill") active_hollusion = None graphics.clear_viewport(vp) graphics.clear_viewport(lp) graphics.clear_viewport(rp) def blank_bbf(vp, frame): """ A blank rune. Basically nothing. """ blank_bb = Rune(blank_bbf) def sail_bbf(vp, frame): """ A sail-shaped rune. """ p = [ Posn(viewport_size / 2, 0), Posn(viewport_size / 2, viewport_size), Posn(viewport_size, viewport_size), ] if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) sail_bb = Rune(sail_bbf) def corner_bbf(vp, frame): """ A small triangular rune at the corner. """ p = [ Posn(viewport_size / 2, 0), Posn(viewport_size, 0), Posn(viewport_size, viewport_size / 2), ] if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) corner_bb = Rune(corner_bbf) def black_bbf(vp, frame): """ A rune without any blank space. """ p = [ Posn(0, 0), Posn(viewport_size, 0), Posn(viewport_size, viewport_size), Posn(0, viewport_size), ] if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) black_bb = Rune(black_bbf) def spiral_bbf(vp, frame): """ A rune that definitely looks like a spiral. """ theta_max = 30 offset = 0.1 angle = 0 p = [] while angle < theta_max: p.append( Posn( (offset + angle / theta_max) * math.cos(angle), (offset + angle / theta_max) * math.sin(angle), ) ) angle += offset if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), map(center_and_fill, p)), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), map(center_and_fill, p)), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) spiral_bb = Rune(spiral_bbf) def circle_bbf(vp, frame): """ A perfect circle rune! """ unit = 50 p = [] angle = 0 while angle < 2 * math.pi: p.append(Posn(math.cos(angle), math.sin(angle))) angle += unit / viewport_size if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), map(center_and_fill, p)), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), map(center_and_fill, p)), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) circle_bb = Rune(circle_bbf) def quarter_bbf(vp, frame): """ Quarter of a circle """ unit = 50 p = [] angle = 0 while angle < math.pi / 2: p.append(Posn(-2 * math.cos(angle) + 1, -2 * math.sin(angle) + 1)) angle += unit / viewport_size p.append(Posn(1, -1)) # Top corner p.append(Posn(1, 1)) # Center of circle if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), map(center_and_fill, p)), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), map(center_and_fill, p)), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) quarter_bb = Rune(quarter_bbf) def pentagram_bbf(vp, frame): """ A star-shaped rune. How cool is that? """ unit_offset = viewport_size / 2 s1 = math.sin(2 * math.pi / 5) * unit_offset c1 = math.cos(2 * math.pi / 5) * unit_offset s2 = math.sin(4 * math.pi / 5) * unit_offset c2 = math.cos(math.pi / 5) * unit_offset a = s2 / (s1 + s2) a_ = 1 - a p = [ Posn(-s1 + unit_offset, -c1 + unit_offset), Posn(s1 + unit_offset, -c1 + unit_offset), Posn(-s2 + unit_offset, c2 + unit_offset), Posn(unit_offset, 0), Posn(s2 + unit_offset, c2 + unit_offset), ] p = [ p[0], p[3] * a + p[2] * a_, p[2], p[1] * a + p[2] * a_, p[4], p[2] * a + p[1] * a_, p[1], p[4] * a + p[3] * a_, p[3], p[2] * a + p[3] * a_, ] if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) pentagram_bb = Rune(pentagram_bbf) def heart_bbf(vp, frame): """ A heart-shaped rune. Good to spread positivity :) """ k = math.sqrt(2) / 2 p = [ Posn(viewport_size / 2, (1 - k) / (1 + 3 * k) * viewport_size), Posn( (1 - k) / (1 + k) * viewport_size / 2, (1 + k) / (1 + 3 * k) * viewport_size ), Posn(viewport_size / 2, viewport_size), Posn( viewport_size - (1 - k) / (1 + k) * viewport_size / 2, (1 + k) / (1 + 3 * k) * viewport_size, ), ] # Draws a kite if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) # Draws the top of the heart heart_circle = stack_frac( 2 / (1 + 3 * k), quarter_turn_right(stack_frac(k / (1 + k), blank_bb, circle_bb)), blank_bb, ) heart_circle.show(vp, frame) flip_horiz(heart_circle).show(vp, frame) heart_bb = Rune(heart_bbf) def rcross_bbf(vp, frame): """ An upper triangular rune with some small part mirrored to its diagonal. """ p1 = [ Posn(0, 0), Posn(viewport_size / 4, viewport_size / 4), Posn(3 * viewport_size / 4, viewport_size / 4), Posn(3 * viewport_size / 4, 3 * viewport_size / 4), Posn(viewport_size, viewport_size), Posn(viewport_size, 0), ] p2 = [ Posn(viewport_size / 4, viewport_size / 4), Posn(viewport_size / 4, 3 * viewport_size / 4), Posn(3 * viewport_size / 4, 3 * viewport_size / 4), ] if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p1), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) draw_solid_polygon( port, map(transform_posn(frame), p2), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p1), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) draw_solid_polygon( vp, map(transform_posn(frame), p2), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) rcross_bb = Rune(rcross_bbf) def ribbon_bbf(vp, frame): """ A ribbon-shaped rune, similar to a beautiful spiral. """ theta_max = 30 thickness = -1 / theta_max unit = 0.1 p = [] angle = 0 # Make ribbon while angle < theta_max: p.append( Posn( (angle / theta_max) * math.cos(angle), (angle / theta_max) * math.sin(angle), ) ) angle += unit # Close it while angle > 0: p.append( Posn( abs(math.cos(angle) * thickness) + (angle / theta_max * math.cos(angle)), abs(math.sin(angle) * thickness) + (angle / theta_max * math.sin(angle)), ) ) angle -= unit if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), map(center_and_fill, p)), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), map(center_and_fill, p)), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) ribbon_bb = Rune(ribbon_bbf) def nova_bbf(vp, frame): """ Two small sail-shaped runes combined into an L-shaped rune. """ p = [ Posn(viewport_size / 2, 0), Posn(viewport_size / 4, viewport_size / 2), Posn(viewport_size, viewport_size / 2), Posn(viewport_size / 2, viewport_size / 4), ] if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): draw_solid_polygon( port, map(transform_posn(frame), p), Posn( (0.3 - frame.z1) * (spread * (((2 * count) / (len(vp) - 1)) - 1)), 0 ), Rgb(frame.z1, frame.z1, frame.z1), ) elif vp != None: draw_solid_polygon( vp, map(transform_posn(frame), p), Posn(0, 0), Rgb(frame.z1, frame.z1, frame.z1), ) nova_bb = Rune(nova_bbf) # Frame transformation factory def process_frame(op, frame): """ A frame transformation factory. Nothing to see here. """ p0 = frame.orig p1 = frame.x p2 = frame.y z1 = frame.z1 z2 = frame.z2 if op == "bottom_frac": return lambda frac: Frame( p0 + scale_vect(1 - frac, p2), p1, scale_vect(frac, p2), z1, z2 ) elif op == "top_frac": return lambda frac: Frame(p0, p1, scale_vect(frac, p2), z1, z2) # To devs, probably unused elif op == "left": return Frame(p0, scale_vect(1 / 2, p1), p2, z1, z2) # To devs, probably unused elif op == "right": return Frame(p0 + scale_vect(1 / 2, p1), scale_vect(1 / 2, p1), p2, z1, z2) elif op == "flip_horiz": return Frame(p0 + p1, scale_vect(-1, p1), p2, z1, z2) elif op == "flip_vert": return Frame(p0 + p2, p1, scale_vect(-1, p2), z1, z2) elif op == "reduce_2": # unused in original raise NotImplementedError("reduce_2 is not implemented") elif op == "rotate": def function(rad): cos_theta = math.cos(rad) sin_theta = math.sin(rad) def rotate_posn(p): return Posn( cos_theta * p.x + sin_theta * p.y, cos_theta * p.y - sin_theta * p.x ) half_gradient = scale_vect(1 / 2, p1 + p2) center = p0 + half_gradient + rotate_posn(scale_vect(-1, half_gradient)) return Frame(center, rotate_posn(p1), rotate_posn(p2), z1, z2) return function elif op == "rotate90": return Frame(p0 + p1, p2, scale_vect(-1, p1), z1, z2) elif op == "deep_frac": return lambda frac: Frame(p0, p1, p2, z1 + ((z2 - z1) * frac), z2) elif op == "shallow_frac": return lambda frac: Frame(p0, p1, p2, z1, z1 + ((z2 - z1) * frac)) elif op == "scale_independent": def function(ratio_x, ratio_y): d_xy = (p1 * (1 - ratio_x) + p2 * (1 - ratio_y)) * 0.5 center = p0 + d_xy return Frame(center, p1 * ratio_x, p2 * ratio_y, z1, z2) return function elif op == "translate": return lambda x, y: Frame( p0 + scale_vect(x, p1) + scale_vect(y, p2), p1, p2, z1, z2 ) # Basic rune combinations @type_checker((float, Rune, Rune)) def stack_frac(frac, rune1, rune2): """ Stacks `rune1` on top and `rune2` at the bottom with the vertical proportion of `rune1` equals to `frac`. """ def function(vp, frame): if not 0 <= frac <= 1: raise ValueError("stack_frac: 0 <= frac <= 1 is required") else: uf = process_frame("top_frac", frame)(frac) lf = process_frame("bottom_frac", frame)(1 - frac) rune1.show(vp, uf) rune2.show(vp, lf) return Rune(function) @type_checker((Rune, Rune)) def stack(rune1, rune2): """ Stacks `rune1` on top and `rune2` at the bottom with equal proportion. """ return stack_frac(1 / 2, rune1, rune2) @type_checker((float, Rune)) def rotate(rad, rune): """ Rotate `rune` by a certain angle `rad`, in radians, counterclockwise. """ def function(vp, frame): rune.show(vp, process_frame("rotate", frame)(rad)) return Rune(function) @type_checker((Rune,)) def eighth_turn_left(rune): """ Rotate `rune` by pi/4 radians counterclockwise. In other words, 45 degrees to the left. """ return rotate(math.pi / 4, rune) @type_checker((Rune,)) def quarter_turn_right(rune): """ Rotate `rune` by pi/2 radians clockwise. In other words, 90 degrees to the right. """ def function(vp, frame): rune.show(vp, process_frame("rotate90", frame)) return Rune(function) @type_checker((Rune,)) def flip_vert(rune): """ Flips `rune` vertically. """ def function(vp, frame): rune.show(vp, process_frame("flip_vert", frame)) return Rune(function) @type_checker((Rune,)) def flip_horiz(rune): """ Flips `rune` horizontally. """ def function(vp, frame): rune.show(vp, process_frame("flip_horiz", frame)) return Rune(function) @type_checker((float, Rune, Rune)) def overlay_frac(frac, rune1, rune2): """ Overlay `rune1` on top and `rune2` at the bottom with the z-axis proportion of `rune1` equals `frac`. Basically a 3D-representation of stack_frac. """ def function(vp, frame): if not 0 <= frac <= 1: raise ValueError("overlay_frac: 0 <= frac <= 1 is required") else: df = process_frame("deep_frac", frame)(frac) sf = process_frame("shallow_frac", frame)(frac) rune2.show(vp, df) rune1.show(vp, sf) return Rune(function) @type_checker((Rune, Rune)) def overlay(rune1, rune2): """ Overlay `rune1` on top and `rune2` at the bottom with equal z-axis proportion. """ return overlay_frac(1 / 2, rune1, rune2) @type_checker((float, float, Rune)) def scale_independent(ratio_x, ratio_y, rune): """ Scales `rune`'s width by `ratio_x` and its height by `ratio_y`. The scaling anchor point is the center of the rune. """ def function(vp, frame): rune.show(vp, process_frame("scale_independent", frame)(ratio_x, ratio_y)) return Rune(function) @type_checker((float, Rune)) def scale(ratio, rune): """ Scales `rune` by `ratio`, maintaining aspect ratio. """ return scale_independent(ratio, ratio, rune) @type_checker((float, float, Rune)) def translate(x, y, rune): """ Translates `rune` by `x` * 100% of the screen to the right and by `y` * 100% of the screen downwards. Positive `x` means to the right, positive `y` means downwards. """ def function(vp, frame): rune.show(vp, process_frame("translate", frame)(x, y)) return Rune(function) @type_checker((Rune,)) def turn_upside_down(rune): """ Turns `rune` upside down, a.k.a. 180 degrees. """ return quarter_turn_right(quarter_turn_right(rune)) @type_checker((Rune,)) def quarter_turn_left(rune): """ Turns `rune` to the left by 90 degrees. In other word, pi/2 radians counterclockwise. """ return turn_upside_down(quarter_turn_right(rune)) @type_checker((Rune, Rune)) def beside(rune1, rune2): """ Puts `rune1` and `rune2` beside each other. Both runes share the same horizontal proportion. """ return quarter_turn_right(stack(quarter_turn_left(rune2), quarter_turn_left(rune1))) @type_checker((Rune,)) def make_cross(rune): """ Creates a cross out of the base `rune`. """ return stack( beside(quarter_turn_right(rune), turn_upside_down(rune)), beside(rune, quarter_turn_left(rune)), ) # TODO refactor type_checker, pat is a function, but function is not a keyword or built-in. def repeat_pattern(n, pat, pic): """ Repeats a pattern, pat, on a rune, pic, by n times. """ if n == 0: return pic else: return pat(repeat_pattern(n - 1, pat, pic)) @type_checker((int, Rune)) def stackn(n, rune): """ Stacks n identical `rune` vertically. The vertical proportions of the runes will be all equal. """ if n == 1: return rune else: return stack_frac(1 / n, rune, stackn(n - 1, rune)) ########################################################################## # Functions below this line are deprecated! You don't have to check them # ########################################################################## def hollusion(rune, ports=None): """ Creates a hollusion of `rune`. """ global active_hollusion frequency = 2 MAX_X = round(viewport_size) MAX_Y = round(viewport_size) num = ports if ports == None or ports <= 2: num = 9 buffers = list( map( lambda p: graphics.open_pixmap("buffer", viewport_size, viewport_size), range(num), ) ) def animation(cmd=None): ports = buffers kill = False curr = -1 dir = 1 def Self(msg): nonlocal kill nonlocal curr nonlocal Self nonlocal dir if msg == "next": curr += dir if curr == num or curr < 0: dir = -dir curr += 2 * dir graphics.show_viewport(buffers[curr]) if not kill: vp[0].after( round(1000 / (frequency * len(ports))), lambda: Self("next") ) elif msg == "kill": kill = True elif msg == "buffer": return ports else: return return Self rune.show(buffers, unit_frame) if active_hollusion != None: active_hollusion("kill") active_hollusion = animation() active_hollusion("next") return active_hollusion def anaglyph(rune): """ Creates an anaglyph of `rune`. Very advisable to use 3D glasses for the effects. """ if graphics.PIL_available: MAX_X = round(viewport_size) MAX_Y = viewport_size stereo = vp depth = graphics.open_pixmap("Depthmap Viewport", viewport_size, viewport_size) def get_depth(x, y, pix): return pix[x, y][0] rune.show([lp, rp], unit_frame) lp_pix = graphics.get_pixels(lp) rp_pix = graphics.get_pixels(rp) pixels = graphics.get_pixels(stereo) for y in range(MAX_Y): for x in range(MAX_X): l = get_depth(x, y, lp_pix) r = get_depth(x, y, rp_pix) pixels[x, y] = (r, l, l) graphics.pixels_to_canvas(stereo) else: print("PIL does not appear to be available") def function_to_painter(depth_fun): """ Converts a depth function depth_fun into a rune. """ tolerance = 1 / spread def get_depth(x, y, dir, frame): # lp -> dir = -1, rp -> dir = 1 result = 1 for c in range(0, spread): ox = round(x + (dir * ((-0.3 * spread) + c))) if 0 <= ox < viewport_size: curr = depth_fun(round(ox), round(y)) if curr != 1: curr = frame.z1 + ((frame.z2 - frame.z1) * curr) d = abs(curr - c / spread) if d < tolerance: result = curr return result def painter(vp, frame): def ana_out_loop(port, count): inverse_transform = inverse_transform_posn(frame) tgtpixels = graphics.get_pixels(port) size = graphics.get_image_size(port) MAX_X = size[0] MAX_Y = size[1] tgtpixels = graphics.get_pixels(port) for y in range(MAX_Y): for x in range(MAX_X): posn = inverse_transform(Posn(x, y)) col = get_depth(posn.x, posn.y, count, frame) col = round(min(col, 1) * 255) if col < 255: tgtpixels[x, y] = ( min(col, tgtpixels[x, y][0]), min(col, tgtpixels[x, y][1]), min(col, tgtpixels[x, y][2]), ) graphics.pixels_to_canvas(port) if is_list_or_tuple(vp[0]): for count, port in enumerate(vp): ana_out_loop(port, ((2 * count) / (len(vp) - 1) - 1)) else: inverse_transform = inverse_transform_posn(frame) tgtpixels = graphics.get_pixels(vp) size = graphics.get_image_size(vp) MAX_X = size[0] MAX_Y = size[1] for y in range(MAX_Y): for x in range(MAX_X): posn = inverse_transform(Posn(x, y)) color = depth_fun(posn.x, posn.y) if color != 1: color = frame.z1 + ((frame.z2 - frame.z1) * color) color = round(min(color, 1) * 255) if color < 255: # assuming that white is the transparency color tgtpixels[x, y] = ( min(color, tgtpixels[x, y][0]), min(color, tgtpixels[x, y][1]), min(color, tgtpixels[x, y][2]), ) graphics.pixels_to_canvas(vp) return painter def image_to_painter(filename): """ Converts an image file to a rune. Probably a work in progress. """ img = graphics.load_image(filename) tolerance = 1 / spread limit = 0.86 # Process def painter(vp, frame): if is_list_or_tuple(vp[0]): def get_depth(x, y, dir): global spread nonlocal pixels for c in range(spread): ox = round(x + dir * (-0.3 * spread + c)) if 0 <= ox < viewport_size: if ( type(pixels[ox, y]) is int ): # this is a workaround for black/white pictures curr = pixels[ox, y] else: curr = pixels[ox, y][0] d = abs(curr - 255 * c / spread) if d <= tolerance * 255: return curr return 255 def ana_out_loop(port, count): nonlocal img size = graphics.get_image_size(img) MAX_X = size[0] MAX_Y = size[1] tsize = graphics.get_image_size(port) TMAX_X = tsize[0] TMAX_Y = tsize[1] tgtpixels = graphics.get_pixels(port) inv_transform = inverse_transform_posn(frame) for y in range(TMAX_Y): for x in range(TMAX_X): orig = inv_transform(Posn(x, y)) rx = round(orig.x) ry = round(orig.y) if 0 <= rx < MAX_X and 0 <= ry < MAX_Y: # within bounds col = get_depth(rx, ry, count) if col > 255 * limit: col = 999 else: col = round( frame.z1 * 255 + (frame.z2 - frame.z1) * col ) if col <= 255: tgtpixels[x, y] = ( min(col, tgtpixels[x, y][0]), min(col, tgtpixels[x, y][1]), min(col, tgtpixels[x, y][2]), ) graphics.pixels_to_canvas(port) pixels = graphics.get_pixels(img) for count, port in enumerate(vp): ana_out_loop(port, ((2 * count) / (len(vp) - 1) - 1)) else: transform = inverse_transform_posn(frame) graphics.blit_pixels( vp, transform, graphics.get_pixels(img), graphics.get_image_size(vp), graphics.get_image_size(img), True, frame.z1, frame.z2, ) # block level image transfer return painter def stereogram(painter): """ Generates a stereogram of a rune. """ E = 300 # distance between eyes in pixels D = 600 # distance between eyes and image plane in pixels delta = 40 # stereo separation MAX_X = round(viewport_size) MAX_Y = viewport_size MAX_Z = 0 CENTRE = round(MAX_X / 2) stereo = vp pixels = graphics.get_pixels(stereo) depthmap = graphics.open_pixmap("temp", viewport_size, viewport_size) depth_pix = graphics.get_pixels(depthmap) painter(depthmap, unit_frame) Infinity = float("inf") depth_pix = graphics.get_pixels(depthmap) def get_depth(x, y): if (0) < x < (MAX_X): return -100 * depth_pix[x, y][0] / 255 - 400 else: return -500 for y in range(MAX_Y): link_left = {} link_right = {} colours = {} for x in range(MAX_X): z = get_depth(x, y) s = delta + z * ( E / (z - D) ) # Determine distance between intersection of lines of sight on image left = x - round(s / 2) # x is integer, left is integer right = left + round(s) # right is integer if left > 0 and right < MAX_X: if (not (left in link_right) or s < link_right[left]) and ( not (right in link_left) or s < link_left[right] ): link_right[left] = round(s) link_left[right] = round(s) # Constraint resolution for x in range(MAX_X): try: s = link_left[x] except KeyError: s = Infinity if s != Infinity: s = x d = None if x > s: d = link_right[x - s] else: d = Infinity if s == Infinity or s > d: link_left[x] = 0 # Drawing step for x in range(MAX_X): s = link_left[x] # should be valid for [0, MAX_X - 1] try: colour = colours[x - s] except KeyError: colour = ( round(random() * 10 / 9 * 255), round(random() * 10 / 9 * 255), round(random() * 10 / 9 * 255), ) pixels[x, y] = colour colours[x] = colour graphics.pixels_to_canvas(stereo) def save_image(filename): """ Saves a rune into an image file. """ graphics.saveImage(vp, filename) def save_hollusion(filename): """ Saves a hollusion into a GIF file. filename is a string without ".gif" at the back. """ if graphics.PIL_available: if active_hollusion == None: raise ("No hollusion active") else: filename += ".gif" frames = list( map(lambda vp: graphics.get_image(vp), active_hollusion("buffer")) ) rev = frames[1 : len(frames) - 1] rev.reverse() frames.extend(rev) PyGif.saveAnimated(filename, frames, 1 / len(frames)) else: print("PIL does not appear to be available")
最新发布
09-01
由于没有提供`runes.py`的具体代码,无法直接对其进行分析和优化。不过,可以给出一些关于rune图形绘制及操作相关功能的通用分析和优化思路。 ### 通用分析 - **模块化设计**:在半面向对象版本中,应该有明确的类和方法划分。例如,可能有一个`Rune`类来表示单个rune图形,以及一个`RuneCanvas`类来管理多个rune图形的绘制和操作。 - **数据结构**:合理选择数据结构来存储rune图形的信息,如坐标、颜色、形状等。 - **绘制算法**:确保绘制算法的效率,避免不必要的重复计算。 ### 通用优化建议 - **封装性**:将rune图形的属性和操作封装在类中,提高代码的可维护性和可扩展性。 - **性能优化**:使用合适的数据结构和算法来提高绘制和操作的性能。例如,使用哈希表来快速查找和更新rune图形。 - **错误处理**:在关键的方法中添加错误处理机制,增强代码的健壮性。 ### 示例代码(假设的runes.py) ```python class Rune: def __init__(self, x, y, shape): self.x = x self.y = y self.shape = shape def move(self, dx, dy): self.x += dx self.y += dy def draw(self, canvas): # 这里只是示例,实际的绘制逻辑需要根据具体情况实现 canvas.draw_at(self.x, self.y, self.shape) class RuneCanvas: def __init__(self): self.runes = [] def add_rune(self, rune): self.runes.append(rune) def draw_all(self): for rune in self.runes: rune.draw(self) def draw_at(self, x, y, shape): # 这里只是示例,实际的绘制逻辑需要根据具体情况实现 print(f"Drawing {shape} at ({x}, {y})") # 使用示例 canvas = RuneCanvas() rune = Rune(10, 20, "★") canvas.add_rune(rune) canvas.draw_all() ``` ### 优化后的示例代码 ```python class Rune: def __init__(self, x, y, shape): self.x = x self.y = y self.shape = shape def move(self, dx, dy): try: self.x += dx self.y += dy except TypeError: print("Invalid input for movement. Please use numbers.") def draw(self, canvas): canvas.draw_at(self.x, self.y, self.shape) class RuneCanvas: def __init__(self): self.runes = {} self.id_counter = 0 def add_rune(self, rune): rune_id = self.id_counter self.runes[rune_id] = rune self.id_counter += 1 return rune_id def draw_all(self): for rune in self.runes.values(): rune.draw(self) def draw_at(self, x, y, shape): print(f"Drawing {shape} at ({x}, {y})") def get_rune(self, rune_id): return self.runes.get(rune_id) # 使用示例 canvas = RuneCanvas() rune = Rune(10, 20, "★") rune_id = canvas.add_rune(rune) canvas.draw_all() # 移动rune found_rune = canvas.get_rune(rune_id) if found_rune: found_rune.move(5, 5) canvas.draw_all() ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值